├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── appveyor.yml ├── include └── staticlib │ ├── pion.hpp │ └── pion │ ├── algorithm.hpp │ ├── http_message.hpp │ ├── http_parser.hpp │ ├── http_request.hpp │ ├── http_request_reader.hpp │ ├── http_response.hpp │ ├── http_response_writer.hpp │ ├── http_server.hpp │ ├── logger.hpp │ ├── pion_exception.hpp │ ├── scheduler.hpp │ ├── tcp_connection.hpp │ ├── tcp_server.hpp │ └── websocket.hpp ├── resources ├── Doxyfile.in ├── logo.png ├── macros.cmake └── pkg-config.in ├── src ├── http_message.cpp ├── http_parser.cpp ├── http_request_reader.cpp ├── http_server.cpp ├── scheduler.cpp └── tcp_server.cpp └── test ├── CMakeLists.txt ├── asio.pc ├── certificates ├── client │ ├── staticlibs_test_ca.cer │ ├── staticlibs_test_ca.crt │ ├── testclient.cer │ ├── testclient.key │ ├── testclient.p12 │ ├── testclient.pem │ └── testclient_nopwd.key └── server │ ├── localhost.pem │ ├── localhost_nopwd.pem │ └── staticlibs_test_ca.cer ├── https_test.cpp ├── pion_test.cpp └── websocket_test.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /nbproject 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2017, alex at staticlibs.net 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | language: cpp 16 | 17 | sudo: required 18 | 19 | services: 20 | - docker 21 | 22 | os: 23 | - linux 24 | - osx 25 | 26 | before_install: 27 | - export CC= 28 | - export CXX= 29 | - export D="docker exec fedora" 30 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then 31 | docker pull fedora ; 32 | docker run -id --name fedora -v `pwd`/..:/src -w=/root -e "PKG_CONFIG_PATH=/src/external_asio/resources/pkgconfig_system" fedora bash ; 33 | fi 34 | 35 | install: 36 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then 37 | 38 | `# Ubuntu` ; 39 | sudo apt-get -y install 40 | g++ 41 | pkg-config 42 | cmake 43 | make 44 | valgrind 45 | libasio-dev 46 | libssl-dev 47 | liblog4cplus-dev ; 48 | 49 | `# Fedora` ; 50 | $D dnf install -y 51 | gcc-c++ 52 | pkg-config 53 | cmake 54 | make 55 | valgrind 56 | asio-devel 57 | openssl-devel 58 | log4cplus-devel 59 | zlib-devel ; 60 | 61 | `# Android` ; 62 | git clone https://github.com/staticlibs/android-ndk-r9d-arm-linux-androideabi-4.8.git ../android-ndk ; 63 | 64 | fi 65 | 66 | before_script: 67 | - cd .. 68 | - git clone https://github.com/staticlibs/cmake.git 69 | # mac and android 70 | - git clone https://github.com/staticlibs/external_asio.git 71 | - git clone https://github.com/staticlibs/lookaside_asio.git 72 | - git clone https://github.com/staticlibs/external_openssl.git 73 | - git clone https://github.com/staticlibs/lookaside_openssl.git 74 | # linux 75 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then 76 | export PKG_CONFIG_PATH=`pwd`/external_asio/resources/pkgconfig_system:$PKG_CONFIG_PATH ; 77 | export PKG_CONFIG_PATH=`pwd`/external_log4cplus/resources/pkgconfig_system:$PKG_CONFIG_PATH ; 78 | fi 79 | # all platforms 80 | - git clone https://github.com/staticlibs/staticlib_config.git 81 | - git clone https://github.com/staticlibs/staticlib_support.git 82 | - git clone https://github.com/staticlibs/staticlib_io.git 83 | - git clone https://github.com/staticlibs/staticlib_endian.git 84 | - git clone https://github.com/staticlibs/staticlib_crypto.git 85 | - git clone https://github.com/staticlibs/staticlib_websocket.git 86 | - git clone https://github.com/staticlibs/staticlib_utils.git 87 | # test only 88 | - rm -rf test 89 | - mkdir test 90 | - cp -r staticlib_pion/test/certificates test/ 91 | 92 | script: 93 | - set -e 94 | - mkdir build-standalone 95 | - mkdir build 96 | 97 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then 98 | 99 | `# macOS` ; 100 | set +e ; 101 | pushd build-standalone ; 102 | set -e ; 103 | cmake ../staticlib_pion -DCMAKE_CXX_FLAGS="--std=c++1z" ; 104 | make ; 105 | set +e; 106 | popd ; 107 | pushd build ; 108 | set -e ; 109 | cmake ../staticlib_pion/test -DSTATICLIB_TOOLCHAIN=macosx_amd64_clang -DCMAKE_BUILD_TYPE=Release ; 110 | make all test ; 111 | 112 | fi 113 | 114 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then 115 | 116 | `# Ubuntu` ; 117 | lsb_release -a ; 118 | pushd build-standalone ; 119 | cmake ../staticlib_pion -DCMAKE_CXX_FLAGS="--std=c++11" ; 120 | make ; 121 | popd ; 122 | pushd build ; 123 | cmake ../staticlib_pion/test -DCMAKE_BUILD_TYPE=Release ; 124 | make all test ; 125 | popd ; 126 | 127 | `# Fedora, pkg-config vars broken in F31` ; 128 | $D cat /etc/fedora-release ; 129 | $D cp /src/external_asio/resources/pkgconfig_system/asio.pc /usr/lib64/pkgconfig/asio.pc ; 130 | $D cmake /src/staticlib_pion -DCMAKE_CXX_FLAGS="--std=c++17" ; 131 | $D make ; 132 | $D sh -c "rm -rf /root && mkdir /root" ; 133 | $D cmake /src/staticlib_pion/test -DSTATICLIB_TOOLCHAIN=linux_amd64_gcc -DCMAKE_BUILD_TYPE=Release ; 134 | $D mkdir /test ; 135 | $D cp -r /src/staticlib_pion/test/certificates /test/ ; 136 | $D make all test ; 137 | 138 | `# Android` ; 139 | mkdir build-android ; 140 | pushd build-android ; 141 | cmake ../staticlib_pion/test -DCMAKE_BUILD_TYPE=Release -DSTATICLIB_TOOLCHAIN=android_armeabi_gcc -DANDROID_TOOLCHAIN_DIR=`pwd`/../android-ndk ; 142 | make ; 143 | 144 | fi 145 | 146 | notifications: 147 | email: 148 | on_success: always 149 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2015, alex at staticlibs.net 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | cmake_minimum_required ( VERSION 2.8.12 ) 16 | 17 | # project 18 | project ( staticlib_pion CXX ) 19 | set ( ${PROJECT_NAME}_STATICLIB_VERSION 2.0.3 ) 20 | set ( ${PROJECT_NAME}_DESCRIPTION "Embedded async HTTP 1.1 and WebSocket server based on a source code from https://github.com/splunk/pion" ) 21 | set ( ${PROJECT_NAME}_URL https://github.com/staticlibs/staticlib_pion ) 22 | include ( ${CMAKE_CURRENT_LIST_DIR}/resources/macros.cmake ) 23 | 24 | # docs 25 | option ( ${PROJECT_NAME}_ENABLE_DOCS "Generate doxyfile and exit build" OFF ) 26 | if ( ${PROJECT_NAME}_ENABLE_DOCS ) 27 | configure_file ( ${CMAKE_CURRENT_LIST_DIR}/resources/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile ) 28 | return ( ) 29 | endif ( ) 30 | 31 | # check deplibs cache 32 | if ( STATICLIB_USE_DEPLIBS_CACHE ) 33 | set ( ${PROJECT_NAME}_CACHED_LIB_PATH ${STATICLIB_DEPLIBS_CACHE_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${PROJECT_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX} ) 34 | if ( EXISTS ${${PROJECT_NAME}_CACHED_LIB_PATH} ) 35 | add_library( ${PROJECT_NAME} STATIC IMPORTED GLOBAL ) 36 | set_target_properties( ${PROJECT_NAME} PROPERTIES IMPORTED_LOCATION ${${PROJECT_NAME}_CACHED_LIB_PATH} ) 37 | message ( STATUS "Using cached library: [${${PROJECT_NAME}_CACHED_LIB_PATH}]" ) 38 | return ( ) 39 | endif ( ) 40 | endif ( ) 41 | 42 | # options, use set ( OPTNAME ON CACHE BOOL "") in parent to override 43 | option ( ${PROJECT_NAME}_DISABLE_LOGGING "Disable logging to std out and err" OFF ) 44 | # additionally set staticlib_pion_WILTON_INCLUDE and staticlib_pion_WILTON_LOGGING_INCLUDE in parent project 45 | option ( ${PROJECT_NAME}_USE_WILTON_LOGGING "Use wilton_logging lib for logging" OFF ) 46 | 47 | # standalone build 48 | if ( NOT DEFINED CMAKE_LIBRARY_OUTPUT_DIRECTORY ) 49 | set ( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} ) 50 | endif ( ) 51 | 52 | if ( NOT DEFINED STATICLIB_TOOLCHAIN ) 53 | if ( NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" ) 54 | staticlib_pion_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../external_asio ) 55 | staticlib_pion_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../external_openssl ) 56 | endif ( ) 57 | staticlib_pion_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../staticlib_config ) 58 | staticlib_pion_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../staticlib_support ) 59 | staticlib_pion_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../staticlib_io ) 60 | staticlib_pion_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../staticlib_endian ) 61 | staticlib_pion_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../staticlib_utils ) 62 | staticlib_pion_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../staticlib_crypto ) 63 | staticlib_pion_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../staticlib_websocket ) 64 | endif ( ) 65 | 66 | # dependencies 67 | set ( ${PROJECT_NAME}_DEPS 68 | staticlib_config 69 | staticlib_support 70 | staticlib_io 71 | staticlib_utils 72 | staticlib_websocket 73 | asio 74 | openssl ) 75 | 76 | staticlib_pion_pkg_check_modules ( ${PROJECT_NAME}_DEPS_PC REQUIRED ${PROJECT_NAME}_DEPS ) 77 | 78 | # library 79 | file ( GLOB_RECURSE ${PROJECT_NAME}_SRC ${CMAKE_CURRENT_LIST_DIR}/src/*.cpp ) 80 | file ( GLOB_RECURSE ${PROJECT_NAME}_HEADERS ${CMAKE_CURRENT_LIST_DIR}/include/*.hpp ) 81 | 82 | add_library ( ${PROJECT_NAME} STATIC ${${PROJECT_NAME}_SRC} ${${PROJECT_NAME}_HEADERS} ) 83 | source_group ( "src" FILES ${${PROJECT_NAME}_SRC} ) 84 | source_group ( "include" FILES ${${PROJECT_NAME}_HEADERS} ) 85 | 86 | set ( ${PROJECT_NAME}_DEFINITIONS 87 | -DASIO_STANDALONE 88 | -DASIO_HAS_STD_CHRONO 89 | -DASIO_HAS_STD_SYSTEM_ERROR ) 90 | 91 | set ( ${PROJECT_NAME}_OPTIONS "" ) 92 | set ( ${PROJECT_NAME}_CFLAGS_PUBLIC ${${PROJECT_NAME}_DEFINITIONS} ) 93 | 94 | if ( ${CMAKE_CXX_COMPILER_ID}x MATCHES "MSVCx" ) 95 | set ( ${PROJECT_NAME}_DEFINITIONS ${${PROJECT_NAME}_DEFINITIONS} 96 | -D_CRT_SECURE_NO_WARNINGS 97 | -D_SCL_SECURE_NO_WARNINGS 98 | -D_WIN32_WINNT=0x0501 99 | -DWIN32_LEAN_AND_MEAN 100 | -DSTATICLIB_PION_CMAKE_BUILD ) 101 | set ( ${PROJECT_NAME}_CFLAGS_PUBLIC ${${PROJECT_NAME}_CFLAGS_PUBLIC} 102 | -D_WIN32_WINNT=0x0501 103 | -DWIN32_LEAN_AND_MEAN ) 104 | endif ( ) 105 | 106 | if ( ${PROJECT_NAME}_DISABLE_LOGGING ) 107 | list ( APPEND ${PROJECT_NAME}_DEFINITIONS -DSTATICLIB_PION_DISABLE_LOGGING ) 108 | list ( APPEND ${PROJECT_NAME}_CFLAGS_PUBLIC -DSTATICLIB_PION_DISABLE_LOGGING ) 109 | endif ( ) 110 | 111 | if ( ${PROJECT_NAME}_USE_WILTON_LOGGING ) 112 | list ( APPEND ${PROJECT_NAME}_DEFINITIONS -DSTATICLIB_PION_USE_WILTON_LOGGING ) 113 | list ( APPEND ${PROJECT_NAME}_CFLAGS_PUBLIC -DSTATICLIB_PION_USE_WILTON_LOGGING ) 114 | endif ( ) 115 | 116 | 117 | if ( ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang" ) 118 | execute_process( COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE CLANG_FULL_VERSION_STRING ) 119 | string (REGEX REPLACE "^(Apple LLVM version|clang version) ([0-9]+\\.[0-9]+).*" "\\2" CLANG_VERSION_STRING ${CLANG_FULL_VERSION_STRING}) 120 | if ( (APPLE AND (CLANG_VERSION_STRING VERSION_GREATER 6.0)) OR 121 | ((NOT APPLE) AND (CLANG_VERSION_STRING VERSION_GREATER 3.5)) ) 122 | message ( STATUS "Enabling ASIO warning suppression for Clang: [${CLANG_VERSION_STRING}]" ) 123 | list ( APPEND ${PROJECT_NAME}_OPTIONS -Wno-unused-local-typedef ) 124 | list ( APPEND ${PROJECT_NAME}_CFLAGS_PUBLIC -Wno-unused-local-typedef ) 125 | endif ( ) 126 | endif ( ) 127 | 128 | if ( ${CMAKE_CXX_COMPILER_ID} MATCHES "GNU" ) 129 | # asio warnings with openssl on 130 | list ( APPEND ${PROJECT_NAME}_OPTIONS -Wno-unused-variable ) 131 | list ( APPEND ${PROJECT_NAME}_CFLAGS_PUBLIC -Wno-unused-variable ) 132 | endif ( ) 133 | 134 | target_include_directories ( ${PROJECT_NAME} BEFORE PRIVATE 135 | ${CMAKE_CURRENT_LIST_DIR}/include 136 | ${${PROJECT_NAME}_WILTON_INCLUDE} 137 | ${${PROJECT_NAME}_WILTON_LOGGING_INCLUDE} 138 | ${${PROJECT_NAME}_DEPS_PC_INCLUDE_DIRS} ) 139 | 140 | target_compile_definitions ( ${PROJECT_NAME} PRIVATE ${${PROJECT_NAME}_DEFINITIONS} ) 141 | 142 | target_compile_options ( ${PROJECT_NAME} PRIVATE 143 | ${${PROJECT_NAME}_OPTIONS} 144 | ${${PROJECT_NAME}_DEPS_PC_CFLAGS_OTHER} ) 145 | 146 | # pkg-config 147 | staticlib_pion_list_to_string ( ${PROJECT_NAME}_PC_CFLAGS_OTHER "" ${PROJECT_NAME}_CFLAGS_PUBLIC ) 148 | set ( ${PROJECT_NAME}_PC_CFLAGS "-I${CMAKE_CURRENT_LIST_DIR}/include ${${PROJECT_NAME}_PC_CFLAGS_OTHER}" ) 149 | set ( ${PROJECT_NAME}_PC_LIBS "-L${CMAKE_LIBRARY_OUTPUT_DIRECTORY} -l${PROJECT_NAME}" ) 150 | if( ${PROJECT_NAME}_USE_WILTON_LOGGING ) 151 | set ( ${PROJECT_NAME}_PC_CFLAGS "${${PROJECT_NAME}_PC_CFLAGS} -I${${PROJECT_NAME}_WILTON_INCLUDE}" ) 152 | set ( ${PROJECT_NAME}_PC_CFLAGS "${${PROJECT_NAME}_PC_CFLAGS} -I${${PROJECT_NAME}_WILTON_LOGGING_INCLUDE}" ) 153 | set ( ${PROJECT_NAME}_PC_LIBS "${${PROJECT_NAME}_PC_LIBS} -lwilton_logging" ) 154 | endif( ) 155 | if ( CMAKE_SYSTEM_NAME STREQUAL "Linux" ) 156 | set ( ${PROJECT_NAME}_PC_LIBS "${${PROJECT_NAME}_PC_LIBS} -lpthread" ) 157 | endif ( ) 158 | staticlib_pion_list_to_string ( ${PROJECT_NAME}_PC_REQUIRES "" ${PROJECT_NAME}_DEPS ) 159 | configure_file ( ${CMAKE_CURRENT_LIST_DIR}/resources/pkg-config.in 160 | ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pkgconfig/${PROJECT_NAME}.pc ) 161 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2015, alex@staticlibs.net 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Pion HTTP Server build for Staticlibs 2 | ===================================== 3 | 4 | [![travis](https://travis-ci.org/staticlibs/staticlib_pion.svg?branch=master)](https://travis-ci.org/staticlibs/staticlib_pion) 5 | [![appveyor](https://ci.appveyor.com/api/projects/status/github/staticlibs/staticlib_pion?svg=true)](https://ci.appveyor.com/project/staticlibs/staticlib-pion) 6 | 7 | This project is a part of [Staticlibs](http://staticlibs.net/). 8 | 9 | Embedded asynchronous HTTP 1.1 server implementation based on a source code from [Pion HTTP server](https://github.com/splunk/pion) 10 | project ([description](http://sourceforge.net/p/pion/mailman/message/32075645/)) that was heavily modified 11 | to support WebSocket and CORS. 12 | 13 | Link to the [API documentation](http://staticlibs.github.io/staticlib_pion/docs/html/namespacestaticlib_1_1pion.html). 14 | 15 | Usage [example](https://github.com/staticlibs/staticlib_pion/blob/master/test/pion_test.cpp). 16 | 17 | How to build 18 | ------------ 19 | 20 | [CMake](http://cmake.org/) is required for building. 21 | 22 | [pkg-config](http://www.freedesktop.org/wiki/Software/pkg-config/) utility is used for dependency management. 23 | For Windows users ready-to-use binary version of `pkg-config` can be obtained from [tools_windows_pkgconfig](https://github.com/staticlibs/tools_windows_pkgconfig) repository. 24 | See [StaticlibsPkgConfig](https://github.com/staticlibs/wiki/wiki/StaticlibsPkgConfig) for Staticlibs-specific details about `pkg-config` usage. 25 | 26 | [Perl](https://www.perl.org/) is also required for building, Windows users can obtain ready-to-use 27 | Perl distribution from [tools_windows_perl](https://github.com/staticlibs/tools_windows_perl) repository. 28 | 29 | [NASM](http://nasm.us/) is also required for building on Windows x86 30 | (optional on Windows x86_64 - will be used if present in `PATH`). 31 | You can obtain ready-to-use NASM distribution from 32 | [tools_windows_nasm](https://github.com/staticlibs/tools_windows_nasm) repository. 33 | 34 | To build the library on Windows using Visual Studio 2013 Express run the following commands using 35 | Visual Studio development command prompt 36 | (`C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\Shortcuts\VS2013 x86 Native Tools Command Prompt`): 37 | 38 | git clone https://github.com/staticlibs/tools_windows_pkgconfig.git 39 | git clone https://github.com/staticlibs/tools_windows_perl520.git 40 | git clone https://github.com/staticlibs/tools_windows_nasm.git 41 | set PATH=%PATH%;c:\projects\tools_windows_pkgconfig\bin;c:\projects\tools_windows_perl520\perl\bin;c:\projects\tools_windows_nasm 42 | git clone https://github.com/staticlibs/cmake.git 43 | git clone https://github.com/staticlibs/external_asio.git 44 | git clone https://github.com/staticlibs/lookaside_asio.git 45 | git clone https://github.com/staticlibs/external_openssl.git 46 | git clone https://github.com/staticlibs/lookaside_openssl.git 47 | git clone https://github.com/staticlibs/staticlib_config.git 48 | git clone https://github.com/staticlibs/staticlib_support.git 49 | git clone https://github.com/staticlibs/staticlib_io.git 50 | git clone https://github.com/staticlibs/staticlib_endian.git 51 | git clone https://github.com/staticlibs/staticlib_crypto.git 52 | git clone https://github.com/staticlibs/staticlib_websocket.git 53 | git clone https://github.com/staticlibs/staticlib_utils.git 54 | git clone https://github.com/staticlibs/staticlib_pion.git 55 | cd staticlib_pion 56 | mkdir build 57 | cd build 58 | cmake .. 59 | msbuild staticlib_pion.sln 60 | 61 | To build on other platforms using GCC or Clang with GNU Make: 62 | 63 | cmake .. -DCMAKE_CXX_FLAGS="--std=c++11" 64 | make 65 | 66 | Cloning of `external_asio` and tools is not required on Linux - system libraries will be used instead. 67 | 68 | See [StaticlibsToolchains](https://github.com/staticlibs/wiki/wiki/StaticlibsToolchains) for 69 | more information about the toolchain setup and cross-compilation. 70 | 71 | License information 72 | ------------------- 73 | 74 | This project is released under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0). 75 | 76 | Changelog 77 | --------- 78 | 79 | **2020-02-04** 80 | 81 | * version 2.0.3 82 | * allow to access TCP endpoint 83 | 84 | **2018-10-27** 85 | 86 | * version 2.0.2 87 | * do not send `500` response on handler exception 88 | 89 | **2018-06-21** 90 | 91 | * version 2.0.1 92 | * less strict checking for WebSocket handshake 93 | 94 | **2018-06-20** 95 | 96 | * version 2.0.0 97 | * core networking rework, version reset to untie from upstream pion versions 98 | * WebSocket support 99 | 100 | **2018-05-21** 101 | 102 | * version 5.0.7-17 103 | * make thread-stop hooks to run from the same thread 104 | 105 | **2018-03-12** 106 | 107 | * version 5.0.7-16 108 | * support logging through `wilton_logging` 109 | 110 | **2017-12-25** 111 | 112 | * version 5.0.7-15 113 | * vs2017 support 114 | 115 | **2017-05-19** 116 | 117 | * version 5.0.7-14 118 | * rename back to `pion` 119 | 120 | **2016-10-29** 121 | 122 | * version 5.0.7-13 123 | * use `asio` submodule from Fedora EPEL lookaside - it is thinner than upstream one and pre-patched for android_i386 and musl libc 124 | 125 | **2016-07-14** 126 | 127 | * version 5.0.7-12 128 | * `HEAD` and `OPTIONS` methods support 129 | 130 | **2016-07-12** 131 | 132 | * version 5.0.7-11 133 | * cleanup type aliases usage 134 | * replace `std::bind` with lambdas 135 | * minor `http_response_writer` API cleanup 136 | 137 | **2016-03-09** 138 | 139 | * version 5.0.7-10 140 | * major namespaces and classes renaming 141 | * original Pion `http::server` removed in favour of a `streaming` one 142 | 143 | **2016-01-22** 144 | 145 | * version 5.0.7-9 146 | * minor CMake changes 147 | 148 | **2015-12-03** 149 | 150 | * version 5.0.7-8 151 | * fix type in cmake workaround for newer clang 152 | 153 | **2015-12-03** 154 | 155 | * version 5.0.7-7 156 | * deplibs cache support 157 | * minor cmake cleanup 158 | 159 | **2015-10-20** 160 | 161 | * version 5.0.7-6 162 | * `pkg-config` integration 163 | * filters support 164 | * `shared_ptr` cleanup 165 | * `streaming_server` API changes 166 | * client certificate support fix 167 | 168 | **2015-09-05** 169 | 170 | * version 5.0.7-5 171 | * minor build changes 172 | 173 | **2015-07-12** 174 | 175 | * version 5.0.7-4 176 | * support for HTTPS with client certificate auth to `streaming_server` 177 | 178 | **2015-07-05** 179 | 180 | * version 5.0.7-3 181 | * toolchains update 182 | * clang 3.6+ fix with ASIO 183 | 184 | **2015-07-02** 185 | 186 | * version 5.0.7-2 187 | * locking fixes (use `lock_guards`) 188 | * suppress "no payload handler for GET" log warning 189 | 190 | **2015-07-01** 191 | 192 | * version 5.0.7-1 - toolchains update, minor cmake fixes 193 | 194 | **2015-06-04** 195 | 196 | * 5.0.7, initial public version 197 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2017, alex at staticlibs.net 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | environment: 16 | matrix: 17 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013 18 | SL_CMAKE_VS: 12 2013 19 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 20 | SL_CMAKE_VS: 15 2017 21 | 22 | clone_folder: c:\projects\staticlib_pion 23 | 24 | install: 25 | - cd .. 26 | - git clone https://github.com/staticlibs/tools_windows_pkgconfig.git 27 | - git clone https://github.com/staticlibs/tools_windows_perl520.git 28 | - git clone https://github.com/staticlibs/tools_windows_nasm.git 29 | - set PATH=%PATH%;c:\projects\tools_windows_pkgconfig\bin;c:\projects\tools_windows_perl520\perl\bin;c:\projects\tools_windows_nasm 30 | - git clone https://github.com/staticlibs/cmake.git 31 | - git clone https://github.com/staticlibs/external_asio.git 32 | - git clone https://github.com/staticlibs/lookaside_asio.git 33 | - git clone https://github.com/staticlibs/external_openssl.git 34 | - git clone https://github.com/staticlibs/lookaside_openssl.git 35 | - git clone https://github.com/staticlibs/staticlib_config.git 36 | - git clone https://github.com/staticlibs/staticlib_support.git 37 | - git clone https://github.com/staticlibs/staticlib_io.git 38 | - git clone https://github.com/staticlibs/staticlib_endian.git 39 | - git clone https://github.com/staticlibs/staticlib_crypto.git 40 | - git clone https://github.com/staticlibs/staticlib_websocket.git 41 | - git clone https://github.com/staticlibs/staticlib_utils.git 42 | - mkdir test 43 | - robocopy staticlib_pion\test\certificates test\certificates /e /ndl /njh /njs /nc /ns /np || true 44 | 45 | build: off 46 | 47 | build_script: 48 | - mkdir build-standalone 49 | - cd build-standalone 50 | - cmake ../staticlib_pion 51 | - cmake --build . 52 | - cd .. 53 | - mkdir build_i386 54 | - cd build_i386 55 | - cmake ../staticlib_pion/test 56 | -G "Visual Studio %SL_CMAKE_VS%" 57 | -DSTATICLIB_TOOLCHAIN=windows_i386_msvc 58 | -DCMAKE_BUILD_TYPE=Release 59 | - cmake --build . --config Release 60 | - ctest 61 | - cd .. 62 | - mkdir build_amd64 63 | - cd build_amd64 64 | - cmake ../staticlib_pion/test 65 | -G "Visual Studio %SL_CMAKE_VS% Win64" 66 | -DSTATICLIB_TOOLCHAIN=windows_amd64_msvc 67 | -DCMAKE_BUILD_TYPE=Release 68 | - cmake --build . --config Release 69 | - ctest 70 | -------------------------------------------------------------------------------- /include/staticlib/pion.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * File: pion.hpp 19 | * Author: alex 20 | * 21 | * Created on May 7, 2016, 12:04 PM 22 | */ 23 | 24 | #ifndef STATICLIB_PION_HPP 25 | #define STATICLIB_PION_HPP 26 | 27 | #include "staticlib/config.hpp" 28 | 29 | #include "staticlib/pion/http_request.hpp" 30 | #include "staticlib/pion/http_response.hpp" 31 | #include "staticlib/pion/http_response_writer.hpp" 32 | #include "staticlib/pion/http_server.hpp" 33 | #include "staticlib/pion/websocket.hpp" 34 | 35 | #endif /* STATICLIB_PION_HPP */ 36 | 37 | -------------------------------------------------------------------------------- /include/staticlib/pion/algorithm.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // --------------------------------------------------------------------- 18 | // pion: a Boost C++ framework for building lightweight HTTP interfaces 19 | // --------------------------------------------------------------------- 20 | // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion) 21 | // 22 | // Distributed under the Boost Software License, Version 1.0. 23 | // See http://www.boost.org/LICENSE_1_0.txt 24 | // 25 | 26 | #ifndef STATICLIB_PION_ALGORITHM_HPP 27 | #define STATICLIB_PION_ALGORITHM_HPP 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "staticlib/config.hpp" 36 | #include "staticlib/utils.hpp" 37 | 38 | namespace staticlib { 39 | namespace pion { 40 | 41 | /** 42 | * Contains some common algorithms 43 | * 44 | */ 45 | namespace algorithm { 46 | 47 | /** 48 | * Detect char 49 | * 50 | * @param c integer 51 | * @return true if char, false otherwise 52 | */ 53 | inline bool is_char(int c) { 54 | return (c >= 0 && c <= 127); 55 | } 56 | 57 | /** 58 | * Detect control char 59 | * 60 | * @param c integer 61 | * @return true if control char, false otherwise 62 | */ 63 | inline bool is_control(int c) { 64 | return ( (c >= 0 && c <= 31) || c == 127); 65 | } 66 | 67 | /** 68 | * Detect special char 69 | * 70 | * @param c integer 71 | * @return true if special char, false otherwise 72 | */ 73 | inline bool is_special(int c) { 74 | switch (c) { 75 | case '(': case ')': case '<': case '>': case '@': 76 | case ',': case ';': case ':': case '\\': case '"': 77 | case '/': case '[': case ']': case '?': case '=': 78 | case '{': case '}': case ' ': case '\t': 79 | return true; 80 | default: 81 | return false; 82 | } 83 | } 84 | 85 | /** 86 | * Called repeatedly to incrementally create a hash value from several variables. 87 | * 88 | * @see http://www.boost.org/doc/libs/1_58_0/doc/html/hash/combine.html 89 | * @param seed seed value for this hash 90 | * @param v value to compute hash over 91 | */ 92 | // http://stackoverflow.com/a/2595226 93 | template 94 | static void hash_combine(std::size_t& seed, const T& v) { 95 | std::hash hasher; 96 | seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); 97 | } 98 | 99 | /** 100 | * Case insensitive string equality predicate 101 | */ 102 | // http://www.boost.org/doc/libs/1_50_0/doc/html/unordered/hash_equality.html 103 | struct iequal_to : std::binary_function { 104 | /** 105 | * Case insensitive byte-to-byte string comparison, does not support Unicode 106 | * 107 | * @param x first string 108 | * @param y seconds string 109 | * @return true if strings equal ignoring case, false otherwise 110 | */ 111 | bool operator()(std::string const& x, std::string const& y) const { 112 | return sl::utils::iequals(x, y); 113 | } 114 | }; 115 | 116 | /** 117 | * Case insensitive hash generic function 118 | */ 119 | // http://www.boost.org/doc/libs/1_50_0/doc/html/unordered/hash_equality.html 120 | struct ihash : std::unary_function { 121 | /** 122 | * Computes hash over specified string 123 | * 124 | * @param x string to compute hash on 125 | * @return hash value 126 | */ 127 | std::size_t operator()(std::string const& x) const { 128 | std::size_t seed = 0; 129 | for (std::string::const_iterator it = x.begin(); it != x.end(); ++it) { 130 | // locale is expensive here 131 | algorithm::hash_combine(seed, std::toupper(*it/*, locale*/)); 132 | } 133 | return seed; 134 | } 135 | }; 136 | 137 | } // namespace 138 | } 139 | } 140 | 141 | #endif // STATICLIB_PION_ALGORITHM_HPP 142 | -------------------------------------------------------------------------------- /include/staticlib/pion/http_request.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // --------------------------------------------------------------------- 18 | // pion: a Boost C++ framework for building lightweight HTTP interfaces 19 | // --------------------------------------------------------------------- 20 | // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion) 21 | // 22 | // Distributed under the Boost Software License, Version 1.0. 23 | // See http://www.boost.org/LICENSE_1_0.txt 24 | // 25 | 26 | #ifndef STATICLIB_PION_HTTP_REQUEST_HPP 27 | #define STATICLIB_PION_HTTP_REQUEST_HPP 28 | 29 | #include 30 | #include 31 | 32 | #include "staticlib/config.hpp" 33 | 34 | #include "staticlib/pion/http_message.hpp" 35 | #include "staticlib/pion/http_parser.hpp" 36 | 37 | namespace staticlib { 38 | namespace pion { 39 | 40 | /** 41 | * Container for HTTP request information 42 | */ 43 | class http_request : public http_message { 44 | 45 | /** 46 | * Request method (GET, POST, PUT, etc.) 47 | */ 48 | std::string m_method; 49 | 50 | /** 51 | * Name of the resource or uri-stem to be delivered 52 | */ 53 | std::string m_resource; 54 | 55 | /** 56 | * Name of the resource or uri-stem originally requested 57 | */ 58 | std::string m_original_resource; 59 | 60 | /** 61 | * Query string portion of the URI 62 | */ 63 | std::string m_query_string; 64 | 65 | /** 66 | * HTTP query parameters parsed from the request line and post content 67 | */ 68 | std::unordered_multimap m_query_params; 69 | 70 | /** 71 | * Payload handler used with this request 72 | */ 73 | http_parser::payload_handler_type m_payload_handler; 74 | 75 | /** 76 | * Non-owning pointer to request_reader to be used during parsing 77 | */ 78 | http_parser* m_request_reader; 79 | 80 | public: 81 | 82 | /** 83 | * Constructs a new request object (default constructor) 84 | */ 85 | http_request() : 86 | m_method(REQUEST_METHOD_GET) { } 87 | 88 | /** 89 | * Deleted copy constructor 90 | */ 91 | http_request(const http_request&) = delete; 92 | 93 | /** 94 | * Deleted copy-assignment operator 95 | */ 96 | http_request& operator=(const http_request&) = delete; 97 | 98 | /** 99 | * Virtual destructor 100 | */ 101 | virtual ~http_request() STATICLIB_NOEXCEPT { } 102 | 103 | /** 104 | * Clears all request data 105 | */ 106 | virtual void clear() { 107 | http_message::clear(); 108 | m_method.erase(); 109 | m_resource.erase(); 110 | m_original_resource.erase(); 111 | m_query_string.erase(); 112 | m_query_params.clear(); 113 | } 114 | 115 | /** 116 | * The content length of the message can never be implied for requests 117 | * 118 | * @return false 119 | */ 120 | virtual bool is_content_length_implied() const { 121 | return false; 122 | } 123 | 124 | /** 125 | * Returns the request method (i.e. GET, POST, PUT) 126 | * 127 | * @return request method 128 | */ 129 | const std::string& get_method() const { 130 | return m_method; 131 | } 132 | 133 | /** 134 | * Returns the resource uri-stem to be delivered (possibly the result of a redirect) 135 | * 136 | * @return resource uri-stem to be delivered 137 | */ 138 | const std::string& get_resource() const { 139 | return m_resource; 140 | } 141 | 142 | /** 143 | * Returns the resource uri-stem originally requested 144 | * 145 | * @return resource uri-stem originally requested 146 | */ 147 | const std::string& get_original_resource() const { 148 | return m_original_resource; 149 | } 150 | 151 | /** 152 | * Returns the uri-query or query string requested 153 | * 154 | * @return uri-query or query string requested 155 | */ 156 | const std::string& get_query_string() const { 157 | return m_query_string; 158 | } 159 | 160 | /** 161 | * Returns a value for the query key if any are defined; otherwise, an empty string 162 | * 163 | * @param key query key 164 | * @return value for the query key if any are defined; otherwise, an empty string 165 | */ 166 | const std::string& get_query(const std::string& key) const { 167 | return get_value(m_query_params, key); 168 | } 169 | 170 | /** 171 | * Returns the query parameters 172 | * 173 | * @return query parameters multimap 174 | */ 175 | std::unordered_multimap& get_queries() { 176 | return m_query_params; 177 | } 178 | 179 | /** 180 | * Returns true if at least one value for the query key is defined 181 | * 182 | * @param key query key 183 | * @return true if at least one value for the query key is defined 184 | */ 185 | bool has_query(const std::string& key) const { 186 | return (m_query_params.find(key) != m_query_params.end()); 187 | } 188 | 189 | /** 190 | * Sets the HTTP request method (i.e. GET, POST, PUT) 191 | * 192 | * @param str request method 193 | */ 194 | void set_method(const std::string& str) { 195 | m_method = str; 196 | clear_first_line(); 197 | } 198 | 199 | /** 200 | * Sets the resource or uri-stem originally requested 201 | */ 202 | void set_resource(const std::string& str) { 203 | m_resource = m_original_resource = str; 204 | clear_first_line(); 205 | } 206 | 207 | /** 208 | * Changes the resource or uri-stem to be delivered (called as the result of a redirect) 209 | * 210 | * @param str resource or uri-stem to be delivered 211 | */ 212 | void change_resource(const std::string& str) { 213 | m_resource = str; 214 | } 215 | 216 | /** 217 | * Sets the uri-query or query string requested 218 | * 219 | * @param str uri-query or query string requested 220 | */ 221 | void set_query_string(const std::string& str) { 222 | m_query_string = str; 223 | clear_first_line(); 224 | } 225 | 226 | /** 227 | * Adds a value for the query key 228 | * 229 | * @param key query key 230 | * @param value additional value for this key 231 | */ 232 | void add_query(const std::string& key, const std::string& value) { 233 | m_query_params.insert(std::make_pair(key, value)); 234 | } 235 | 236 | /** 237 | * Changes the value of a query key 238 | * 239 | * @param key query key 240 | * @param value value for this key 241 | */ 242 | void change_query(const std::string& key, const std::string& value) { 243 | change_value(m_query_params, key, value); 244 | } 245 | 246 | /** 247 | * Removes all values for a query key 248 | * 249 | * @param key query key 250 | */ 251 | void delete_query(const std::string& key) { 252 | delete_value(m_query_params, key); 253 | } 254 | 255 | /** 256 | * Use the query parameters to build a query string for the request 257 | */ 258 | void use_query_params_for_query_string() { 259 | set_query_string(make_query_string(m_query_params)); 260 | } 261 | 262 | /** 263 | * Use the query parameters to build POST content for the request 264 | */ 265 | void use_query_params_for_post_content() { 266 | std::string post_content(make_query_string(m_query_params)); 267 | set_content_length(post_content.size()); 268 | char *ptr = create_content_buffer(); // null-terminates buffer 269 | if (!post_content.empty()) { 270 | memcpy(ptr, post_content.c_str(), post_content.size()); 271 | } 272 | set_method(REQUEST_METHOD_POST); 273 | set_content_type(CONTENT_TYPE_URLENCODED); 274 | } 275 | 276 | /** 277 | * Add content (for POST) from string 278 | * 279 | * @param value POST content 280 | */ 281 | void set_content(const std::string &value) { 282 | set_content_length(value.size()); 283 | char *ptr = create_content_buffer(); 284 | if (!value.empty()) { 285 | memcpy(ptr, value.c_str(), value.size()); 286 | } 287 | } 288 | 289 | /** 290 | * Add content (for POST) from buffer of given size; 291 | * Does nothing if the buffer is invalid or the buffer size is zero 292 | */ 293 | void set_content(const char* value, size_t size){ 294 | if (nullptr == value || 0 == size) return; 295 | set_content_length(size); 296 | char *ptr = create_content_buffer(); 297 | std::memcpy(ptr, value, size); 298 | } 299 | 300 | /** 301 | * This method should be called from payload_handler_creator 302 | * to stick payload handler to this request 303 | * 304 | * @param ph payload handler 305 | */ 306 | void set_payload_handler(http_parser::payload_handler_type ph) { 307 | m_payload_handler = std::move(ph); 308 | // this should be done only once during request processing 309 | // and we won't restrict request_reader lifecycle after 310 | // payload is processed, so we drop the pointer to it 311 | if (m_request_reader) { 312 | // request will always outlive reader 313 | m_request_reader->set_payload_handler(m_payload_handler); 314 | m_request_reader = nullptr; 315 | } 316 | } 317 | 318 | /** 319 | * Access to the wrapped payload handler object 320 | * 321 | * @return unwrapped payload handler object 322 | */ 323 | template 324 | T* get_payload_handler() { 325 | return m_payload_handler.target(); 326 | } 327 | 328 | /** 329 | * Access to the payload handler wrapper 330 | * 331 | * @return payload handler 332 | */ 333 | http_parser::payload_handler_type& get_payload_handler_wrapper() { 334 | return m_payload_handler; 335 | } 336 | 337 | /** 338 | * Internal method used with payload handlers 339 | */ 340 | void set_request_reader(http_parser* rr) { 341 | m_request_reader = rr; 342 | } 343 | 344 | protected: 345 | 346 | /** 347 | * Updates the string containing the first line for the HTTP message 348 | */ 349 | virtual void update_first_line() const { 350 | // start out with the request method 351 | m_first_line = m_method; 352 | m_first_line += ' '; 353 | // append the resource requested 354 | m_first_line += m_resource; 355 | if (!m_query_string.empty()) { 356 | // append query string if not empty 357 | m_first_line += '?'; 358 | m_first_line += m_query_string; 359 | } 360 | m_first_line += ' '; 361 | // append HTTP version 362 | m_first_line += get_version_string(); 363 | } 364 | 365 | /** 366 | * Appends HTTP headers for any cookies defined by the http::message 367 | */ 368 | virtual void append_cookie_headers() { 369 | for (std::unordered_multimap::const_iterator i = get_cookies().begin(); i != get_cookies().end(); ++i) { 370 | std::string cookie_header; 371 | cookie_header = i->first; 372 | cookie_header += COOKIE_NAME_VALUE_DELIMITER; 373 | cookie_header += i->second; 374 | add_header(HEADER_COOKIE, cookie_header); 375 | } 376 | } 377 | 378 | }; 379 | 380 | /** 381 | * Data type for a HTTP request pointer 382 | */ 383 | using http_request_ptr = std::unique_ptr; 384 | 385 | 386 | } // namespace 387 | } 388 | 389 | #endif // STATICLIB_PION_HTTP_REQUEST_HPP 390 | -------------------------------------------------------------------------------- /include/staticlib/pion/http_request_reader.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // --------------------------------------------------------------------- 18 | // pion: a Boost C++ framework for building lightweight HTTP interfaces 19 | // --------------------------------------------------------------------- 20 | // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion) 21 | // 22 | // Distributed under the Boost Software License, Version 1.0. 23 | // See http://www.boost.org/LICENSE_1_0.txt 24 | // 25 | 26 | #ifndef STATICLIB_PION_HTTP_REQUEST_READER_HPP 27 | #define STATICLIB_PION_HTTP_REQUEST_READER_HPP 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include "asio.hpp" 34 | 35 | #include "staticlib/config.hpp" 36 | 37 | #include "staticlib/pion/http_parser.hpp" 38 | #include "staticlib/pion/http_request.hpp" 39 | #include "staticlib/pion/tcp_connection.hpp" 40 | 41 | namespace staticlib { 42 | namespace pion { 43 | 44 | class http_server; 45 | 46 | /** 47 | * Asynchronously reads and parses HTTP requests 48 | */ 49 | class http_request_reader : public http_parser { 50 | private: 51 | /** 52 | * Server reference 53 | */ 54 | http_server& server; 55 | 56 | /** 57 | * The HTTP connection that has a new HTTP message to parse 58 | */ 59 | tcp_connection_ptr tcp_conn; 60 | 61 | /** 62 | * Maximum number of milliseconds for read operations 63 | */ 64 | uint32_t read_timeout_millis; 65 | 66 | /** 67 | * The new HTTP message container being created 68 | */ 69 | http_request_ptr request; 70 | 71 | public: 72 | 73 | /** 74 | * Constructor to be used with `std::make_unique` 75 | * 76 | * @param server reference to server 77 | * @param tcp_conn TCP connection containing a new message to parse 78 | */ 79 | http_request_reader(http_server& srv, tcp_connection_ptr& tcp_conn, 80 | uint32_t read_timeout) : 81 | http_parser(true), 82 | server(srv), 83 | tcp_conn(tcp_conn), 84 | read_timeout_millis(read_timeout), 85 | request(new http_request()) { 86 | request->set_remote_ip(tcp_conn->get_remote_ip()); 87 | request->set_request_reader(this); 88 | } 89 | 90 | /** 91 | * Deleted copy-constructor 92 | * 93 | * @param other instance 94 | */ 95 | http_request_reader(const http_request_reader&) = delete; 96 | 97 | /** 98 | * Deleted copy-assignment operator 99 | * 100 | * @param other instance 101 | * @return this instance 102 | */ 103 | http_request_reader& operator=(const http_request_reader&) = delete; 104 | 105 | /** 106 | * Incrementally reads & parses the HTTP message 107 | */ 108 | static void receive(std::unique_ptr self); 109 | 110 | private: 111 | 112 | /** 113 | * Consumes bytes that have been read using an HTTP parser 114 | * 115 | * @param read_error error status from the last read operation 116 | * @param bytes_read number of bytes consumed by the last read operation 117 | */ 118 | static void consume_bytes(std::unique_ptr self, 119 | const std::error_code& read_error, std::size_t bytes_read); 120 | 121 | /** 122 | * Consumes bytes that have been read using an HTTP parser 123 | * 124 | * @param self-owning instance 125 | */ 126 | static void consume_bytes(std::unique_ptr self); 127 | 128 | /** 129 | * Reads more bytes for parsing, with timeout support 130 | * 131 | * @param self-owning instance 132 | */ 133 | static void read_bytes_with_timeout(std::unique_ptr self); 134 | 135 | /** 136 | * Handles errors that occur during read operations 137 | * 138 | * @param read_error error status from the last read operation 139 | */ 140 | void handle_read_error(const std::error_code& read_error); 141 | 142 | /** 143 | * Called after we have finished parsing the HTTP message headers 144 | * 145 | * @param ec error code reference 146 | * @param rc result code reference 147 | */ 148 | void finished_parsing_headers(const std::error_code& ec, sl::support::tribool& rc); 149 | 150 | /** 151 | * Called after we have finished reading/parsing the HTTP message 152 | * 153 | * @param ec error code reference 154 | */ 155 | void finished_reading(const std::error_code& ec); 156 | 157 | }; 158 | 159 | } // namespace 160 | } 161 | 162 | #endif // STATICLIB_PION_HTTP_REQUEST_READER_HPP 163 | -------------------------------------------------------------------------------- /include/staticlib/pion/http_response.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // --------------------------------------------------------------------- 18 | // pion: a Boost C++ framework for building lightweight HTTP interfaces 19 | // --------------------------------------------------------------------- 20 | // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion) 21 | // 22 | // Distributed under the Boost Software License, Version 1.0. 23 | // See http://www.boost.org/LICENSE_1_0.txt 24 | // 25 | 26 | #ifndef STATICLIB_PION_HTTP_RESPONSE_HPP 27 | #define STATICLIB_PION_HTTP_RESPONSE_HPP 28 | 29 | #include 30 | 31 | #include "staticlib/config.hpp" 32 | 33 | #include "staticlib/pion/algorithm.hpp" 34 | #include "staticlib/pion/http_message.hpp" 35 | #include "staticlib/pion/http_request.hpp" 36 | 37 | namespace staticlib { 38 | namespace pion { 39 | 40 | /** 41 | * Container for HTTP response information 42 | */ 43 | class http_response : public http_message { 44 | 45 | /** 46 | * The HTTP response status code 47 | */ 48 | unsigned int status_code; 49 | 50 | /** 51 | * The HTTP response status message 52 | */ 53 | std::string status_message; 54 | 55 | /** 56 | * HTTP method used by the request 57 | */ 58 | std::string request_method; 59 | 60 | public: 61 | 62 | /** 63 | * Constructs a new response object for a particular request 64 | * 65 | * @param http_request_ptr the request that this is responding to 66 | */ 67 | http_response(const http_request& http_request_ptr) : 68 | status_code(RESPONSE_CODE_OK), 69 | status_message(RESPONSE_MESSAGE_OK) { 70 | update_request_info(http_request_ptr); 71 | } 72 | 73 | /** 74 | * Copy constructor 75 | * 76 | * @param http_response another instance 77 | */ 78 | http_response(const http_response& http_response) : 79 | http_message(http_response), 80 | status_code(http_response.status_code), 81 | status_message(http_response.status_message), 82 | request_method(http_response.request_method) { } 83 | 84 | /** 85 | * Virtual destructor 86 | */ 87 | virtual ~http_response() STATICLIB_NOEXCEPT { } 88 | 89 | /** 90 | * Clears all response data 91 | */ 92 | virtual void clear() { 93 | http_message::clear(); 94 | status_code = RESPONSE_CODE_OK; 95 | status_message = RESPONSE_MESSAGE_OK; 96 | request_method.clear(); 97 | } 98 | 99 | /** 100 | * The content length may be implied for certain types of responses 101 | * 102 | * @return whether content length implied 103 | */ 104 | virtual bool is_content_length_implied() const { 105 | return (request_method == REQUEST_METHOD_HEAD // HEAD responses have no content 106 | || (status_code >= 100 && status_code <= 199) // 1xx responses have no content 107 | || status_code == 204 || status_code == 205 // no content & reset content responses 108 | || status_code == 304 // not modified responses have no content 109 | ); 110 | } 111 | 112 | /** 113 | * Updates HTTP request information for the response object (use 114 | * this if the response cannot be constructed using the request) 115 | * 116 | * @param http_request the request that this is responding to 117 | */ 118 | void update_request_info(const http_request& http_request) { 119 | request_method = http_request.get_method(); 120 | if (http_request.get_version_major() == 1 && http_request.get_version_minor() >= 1) { 121 | set_chunks_supported(true); 122 | } else if (http_request.get_version_major() == 0) { 123 | // the request is likely HTTP 0.9 "simple-request", so expect the response to contain no header and no version info 124 | set_status_code(0U); 125 | set_status_message(""); 126 | set_version_major(0); 127 | set_version_minor(0); 128 | } 129 | } 130 | 131 | /** 132 | * Sets the HTTP response status code 133 | * 134 | * @param n HTTP response status code 135 | */ 136 | void set_status_code(unsigned int n) { 137 | status_code = n; 138 | clear_first_line(); 139 | } 140 | 141 | /** 142 | * Sets the HTTP response status message 143 | * 144 | * @param msg HTTP response status message 145 | */ 146 | void set_status_message(const std::string& msg) { 147 | status_message = msg; 148 | clear_first_line(); 149 | } 150 | 151 | /** 152 | * Returns the HTTP response status code 153 | * 154 | * @return HTTP response status code 155 | */ 156 | unsigned int get_status_code() const { 157 | return status_code; 158 | } 159 | 160 | /** 161 | * Returns the HTTP response status message 162 | * 163 | * @return 164 | */ 165 | const std::string& get_status_message() const { 166 | return status_message; 167 | } 168 | 169 | /** 170 | * Returns `true` if this response can have a body 171 | * 172 | * @return `true` if this response can have a body 173 | */ 174 | bool is_body_allowed() const { 175 | return REQUEST_METHOD_HEAD != request_method; 176 | } 177 | 178 | /** 179 | * Sets a cookie by adding a Set-Cookie header (see RFC 2109) 180 | * the cookie will be discarded by the user-agent when it closes 181 | * 182 | * @param name the name of the cookie 183 | * @param value the value of the cookie 184 | */ 185 | void set_cookie(const std::string& name, const std::string& value) { 186 | std::string set_cookie_header(make_set_cookie_header(name, value, "/")); 187 | add_header(HEADER_SET_COOKIE, set_cookie_header); 188 | } 189 | 190 | /** 191 | * Sets a cookie by adding a Set-Cookie header (see RFC 2109) 192 | * the cookie will be discarded by the user-agent when it closes 193 | * 194 | * @param name the name of the cookie 195 | * @param value the value of the cookie 196 | * @param path the path of the cookie 197 | */ 198 | void set_cookie(const std::string& name, const std::string& value, const std::string& path) { 199 | std::string set_cookie_header(make_set_cookie_header(name, value, path)); 200 | add_header(HEADER_SET_COOKIE, set_cookie_header); 201 | } 202 | 203 | /** 204 | * Sets a cookie by adding a Set-Cookie header (see RFC 2109) 205 | * 206 | * @param name the name of the cookie 207 | * @param value the value of the cookie 208 | * @param path the path of the cookie 209 | * @param max_age the life of the cookie, in seconds (0 = discard) 210 | */ 211 | void set_cookie(const std::string& name, const std::string& value, const std::string& path, 212 | const unsigned long max_age) { 213 | std::string set_cookie_header(make_set_cookie_header(name, value, path, true, max_age)); 214 | add_header(HEADER_SET_COOKIE, set_cookie_header); 215 | } 216 | 217 | /** 218 | * Sets a cookie by adding a Set-Cookie header (see RFC 2109) 219 | * 220 | * @param name the name of the cookie 221 | * @param value the value of the cookie 222 | * @param max_age the life of the cookie, in seconds (0 = discard) 223 | */ 224 | void set_cookie(const std::string& name, const std::string& value, const unsigned long max_age) { 225 | std::string set_cookie_header(make_set_cookie_header(name, value, "/", true, max_age)); 226 | add_header(HEADER_SET_COOKIE, set_cookie_header); 227 | } 228 | 229 | /** 230 | * Deletes cookie called name by adding a Set-Cookie header (cookie has no path) 231 | * 232 | * @param name cookie name 233 | */ 234 | void delete_cookie(const std::string& name) { 235 | std::string set_cookie_header(make_set_cookie_header(name, "", "/", true, 0)); 236 | add_header(HEADER_SET_COOKIE, set_cookie_header); 237 | } 238 | 239 | /** 240 | * Deletes cookie called name by adding a Set-Cookie header (cookie has a path) 241 | * 242 | * @param name cookie name 243 | * @param path cookie path 244 | */ 245 | void delete_cookie(const std::string& name, const std::string& path) { 246 | std::string set_cookie_header(make_set_cookie_header(name, "", path, true, 0)); 247 | add_header(HEADER_SET_COOKIE, set_cookie_header); 248 | } 249 | 250 | /** 251 | * Sets the time that the response was last modified (Last-Modified) 252 | * 253 | * @param t last modified time 254 | */ 255 | void set_last_modified(const unsigned long t); 256 | 257 | protected: 258 | 259 | /** 260 | * Updates the string containing the first line for the HTTP message 261 | */ 262 | virtual void update_first_line() const { 263 | // start out with the HTTP version 264 | m_first_line = get_version_string(); 265 | m_first_line += ' '; 266 | // append the response status code 267 | m_first_line += sl::support::to_string(status_code); 268 | m_first_line += ' '; 269 | // append the response status message 270 | m_first_line += status_message; 271 | } 272 | 273 | /** 274 | * Appends HTTP headers for any cookies defined by the http::message 275 | */ 276 | virtual void append_cookie_headers() { 277 | for (std::unordered_multimap 278 | ::const_iterator i = get_cookies().begin(); i != get_cookies().end(); ++i) { 279 | set_cookie(i->first, i->second); 280 | } 281 | } 282 | 283 | }; 284 | 285 | } // namespace 286 | } 287 | 288 | #endif // STATICLIB_PION_HTTP_RESPONSE_HPP 289 | -------------------------------------------------------------------------------- /include/staticlib/pion/http_response_writer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // --------------------------------------------------------------------- 18 | // pion: a Boost C++ framework for building lightweight HTTP interfaces 19 | // --------------------------------------------------------------------- 20 | // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion) 21 | // 22 | // Distributed under the Boost Software License, Version 1.0. 23 | // See http://www.boost.org/LICENSE_1_0.txt 24 | // 25 | 26 | #ifndef STATICLIB_PION_HTTP_RESPONSE_WRITER_HPP 27 | #define STATICLIB_PION_HTTP_RESPONSE_WRITER_HPP 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "asio.hpp" 36 | 37 | #include "staticlib/config.hpp" 38 | #include "staticlib/io/span.hpp" 39 | 40 | #include "staticlib/pion/logger.hpp" 41 | #include "staticlib/pion/http_message.hpp" 42 | #include "staticlib/pion/http_response.hpp" 43 | #include "staticlib/pion/tcp_connection.hpp" 44 | 45 | namespace staticlib { 46 | namespace pion { 47 | 48 | /** 49 | * Sends HTTP data asynchronously 50 | */ 51 | class http_response_writer { 52 | /** 53 | * The HTTP connection that we are writing the message to 54 | */ 55 | tcp_connection_ptr tcp_conn; 56 | 57 | /** 58 | * I/O write buffers that wrap the payload content to be written 59 | */ 60 | std::vector content_buffers; 61 | 62 | /** 63 | * Caches binary data included within the payload content 64 | */ 65 | std::vector> payload_cache; 66 | 67 | /** 68 | * The length (in bytes) of the response content to be sent (Content-Length) 69 | */ 70 | size_t content_length; 71 | 72 | /** 73 | * True if the HTTP client supports chunked transfer encodings 74 | */ 75 | bool client_supports_chunks; 76 | 77 | /** 78 | * True if data is being sent to the client using multiple chunks 79 | */ 80 | bool sending_chunks; 81 | 82 | /** 83 | * True if the HTTP message headers have already been sent 84 | */ 85 | bool sent_headers; 86 | 87 | /** 88 | * The response that will be sent 89 | */ 90 | std::unique_ptr response; 91 | 92 | /** 93 | * The initial HTTP response header line 94 | */ 95 | std::string response_line; 96 | 97 | public: 98 | 99 | /** 100 | * Constructor to be used with `std::make_unique` 101 | * 102 | * @param tcp_conn TCP connection used to send the response 103 | * @param http_request the request we are responding to 104 | */ 105 | http_response_writer(tcp_connection_ptr& tcp_conn, const http_request& http_request) : 106 | tcp_conn(tcp_conn), 107 | content_length(0), 108 | client_supports_chunks(true), 109 | sending_chunks(false), 110 | sent_headers(false), 111 | response(new http_response(http_request)) { 112 | // set whether or not the client supports chunks 113 | supports_chunked_messages(response->get_chunks_supported()); 114 | } 115 | 116 | /** 117 | * Deleted copy constructor 118 | */ 119 | http_response_writer(const http_response_writer&) = delete; 120 | 121 | /** 122 | * Deleted copy assignment operator 123 | */ 124 | http_response_writer& operator=(const http_response_writer&) = delete; 125 | 126 | /** 127 | * Returns a non-const reference to the response that will be sent 128 | * 129 | * @return reference to the response that will be sent 130 | */ 131 | http_response& get_response() { 132 | return *response; 133 | } 134 | 135 | /** 136 | * Clears out all of the memory buffers used to cache payload content data 137 | */ 138 | void clear() { 139 | content_buffers.clear(); 140 | payload_cache.clear(); 141 | content_length = 0; 142 | } 143 | 144 | /** 145 | * Write payload content 146 | * 147 | * @param data to append to the payload content 148 | */ 149 | void write(sl::io::span data) { 150 | if (response->is_body_allowed() && data.size() > 0) { 151 | content_buffers.push_back(add_to_cache(data)); 152 | content_length += data.size(); 153 | } 154 | } 155 | 156 | /** 157 | * Write payload content; the data written is not 158 | * copied, and therefore must persist until the message has finished 159 | * sending 160 | * 161 | * @param data the data to append to the payload content 162 | */ 163 | void write_nocopy(sl::io::span data) { 164 | if (response->is_body_allowed() && data.size() > 0) { 165 | content_buffers.push_back(asio::buffer(data.data(), data.size())); 166 | content_length += data.size(); 167 | } 168 | } 169 | 170 | /** 171 | * Sends all data buffered as a single HTTP message (without chunking). 172 | * Following a call to this function, it is not thread safe to use your 173 | * reference to the writer object. 174 | * 175 | * @param self-owning instance 176 | */ 177 | static void send(std::unique_ptr self) { 178 | auto self_ptr = self.get(); 179 | auto self_shared = sl::support::make_shared_with_release_deleter(self.release()); 180 | self_ptr->send_more_data(false, 181 | [self_shared](const std::error_code& ec, std::size_t bt) { 182 | auto self = sl::support::make_unique_from_shared_with_release_deleter(self_shared); 183 | if (nullptr != self.get()) { 184 | handle_write(std::move(self), ec, bt); 185 | } else { 186 | STATICLIB_PION_LOG_WARN("staticlib.pion.http_response_writer", 187 | "Lost context detected in 'async_write'"); 188 | } 189 | }); 190 | } 191 | 192 | /** 193 | * Sends all data buffered as a single HTTP chunk. Following a call to this 194 | * function, it is not thread safe to use your reference to the writer 195 | * object until the send_handler has been called. 196 | * 197 | * @param send_handler function that is called after the chunk has been sent 198 | * to the client. Your callback function must end by 199 | * calling one of send_chunk() or send_final_chunk(). Also, 200 | * be sure to clear() the writer before writing data to it. 201 | */ 202 | template void send_chunk(SendHandler send_handler) { 203 | sending_chunks = true; 204 | if (!supports_chunked_messages()) { 205 | // sending data in chunks, but the client does not support chunking; 206 | // make sure that the connection will be closed when we are all done 207 | tcp_conn->set_lifecycle(tcp_connection::lifecycle::close); 208 | } 209 | // make sure that we did not lose the TCP connection 210 | if (tcp_conn->is_open()) { 211 | // send more data 212 | send_more_data(false, send_handler); 213 | } else { 214 | tcp_conn->finish(); 215 | } 216 | } 217 | 218 | /** 219 | * Sends all data buffered (if any) and also sends the final HTTP chunk. 220 | * This function (either overloaded version) must be called following any 221 | * calls to send_chunk(). 222 | * Following a call to this function, it is not thread safe to use your 223 | * reference to the writer object. 224 | * 225 | * @param self-owning instance 226 | */ 227 | static void send_final_chunk(std::unique_ptr self) { 228 | self->sending_chunks = true; 229 | auto self_ptr = self.get(); 230 | auto self_shared = sl::support::make_shared_with_release_deleter(self.release()); 231 | self_ptr->send_more_data(true, 232 | [self_shared](const std::error_code& ec, std::size_t bt) { 233 | auto self = sl::support::make_unique_from_shared_with_release_deleter(self_shared); 234 | if (nullptr != self.get()) { 235 | handle_write(std::move(self), ec, bt); 236 | } else { 237 | STATICLIB_PION_LOG_WARN("staticlib.pion.http_response_writer", 238 | "Lost context detected in 'async_write' final"); 239 | } 240 | }); 241 | } 242 | 243 | /** 244 | * Returns a shared pointer to the TCP connection 245 | * 246 | * @return shared pointer to the TCP connection 247 | */ 248 | tcp_connection_ptr& get_connection() { 249 | return tcp_conn; 250 | } 251 | 252 | /** 253 | * Returns the length of the payload content (in bytes) 254 | * 255 | * @return length of the payload content (in bytes) 256 | */ 257 | size_t get_content_length() const { 258 | return content_length; 259 | } 260 | 261 | /** 262 | * Sets whether or not the client supports chunked messages 263 | * 264 | * @param b whether or not the client supports chunked messages 265 | */ 266 | void supports_chunked_messages(bool b) { 267 | client_supports_chunks = b; 268 | } 269 | 270 | /** 271 | * Returns true if the client supports chunked messages 272 | * 273 | * @return true if the client supports chunked messages 274 | */ 275 | bool supports_chunked_messages() const { 276 | return client_supports_chunks; 277 | } 278 | 279 | /** 280 | * Returns true if we are sending a chunked message to the client 281 | * 282 | * @return true if we are sending a chunked message to the client 283 | */ 284 | bool sending_chunked_message() const { 285 | return sending_chunks; 286 | } 287 | 288 | private: 289 | 290 | /** 291 | * Initializes a vector of write buffers with the HTTP message information 292 | * 293 | * @param write_buffers vector of write buffers to initialize 294 | */ 295 | void prepare_buffers_for_send(std::vector& write_buffers) { 296 | if (get_content_length() > 0) { 297 | response->set_content_length(get_content_length()); 298 | } 299 | response->prepare_buffers_for_send(write_buffers, get_connection()->get_keep_alive(), 300 | sending_chunked_message()); 301 | } 302 | 303 | /** 304 | * Called after the response is sent 305 | * 306 | * @param self-owning instance 307 | * @param write_error error status from the last write operation 308 | * @param bytes_written number of bytes sent by the last write operation 309 | */ 310 | static void handle_write(std::unique_ptr self, 311 | const std::error_code& ec, std::size_t bytes_written) { 312 | (void) bytes_written; 313 | if (!ec) { 314 | // response sent OK 315 | if (self->sending_chunked_message()) { 316 | STATICLIB_PION_LOG_DEBUG("staticlib.pion.http_response_writer", 317 | "Sent HTTP response chunk of " << bytes_written << " bytes"); 318 | } else { 319 | STATICLIB_PION_LOG_DEBUG("staticlib.pion.http_response_writer", 320 | "Sent HTTP response of " << bytes_written << " bytes (" 321 | << (self->get_connection()->get_keep_alive() ? "keeping alive)" : "closing)")); 322 | } 323 | } 324 | self->tcp_conn->finish(); 325 | } 326 | 327 | /** 328 | * Sends all of the buffered data to the client 329 | * 330 | * @param send_final_chunk true if the final 0-byte chunk should be included 331 | * @param send_handler function called after the data has been sent 332 | */ 333 | template 334 | void send_more_data(const bool send_final_chunk, SendHandler send_handler) { 335 | // make sure that we did not lose the TCP connection 336 | if (tcp_conn->is_open()) { 337 | // make sure that the content-length is up-to-date 338 | // prepare the write buffers to be sent 339 | auto write_buffers = std::vector(); 340 | prepare_write_buffers(write_buffers, send_final_chunk); 341 | // send data in the write buffers 342 | auto send_handler_stranded = tcp_conn->get_strand().wrap(send_handler); 343 | tcp_conn->async_write(write_buffers, send_handler_stranded); 344 | } else { 345 | tcp_conn->finish(); 346 | } 347 | } 348 | 349 | /** 350 | * Prepares write_buffers for next send operation 351 | * 352 | * @param write_buffers buffers to which data will be appended 353 | * @param send_final_chunk true if the final 0-byte chunk should be included 354 | */ 355 | void prepare_write_buffers(std::vector& write_buffers, 356 | const bool send_final_chunk) { 357 | // check if the HTTP headers have been sent yet 358 | if (! sent_headers) { 359 | // initialize write buffers for send operation 360 | prepare_buffers_for_send(write_buffers); 361 | 362 | // only send the headers once 363 | sent_headers = true; 364 | } 365 | 366 | // combine I/O write buffers (headers and content) so that everything 367 | // can be sent together; otherwise, we would have to send headers 368 | // and content separately, which would not be as efficient 369 | 370 | // don't send anything if there is no data in content buffers 371 | if (content_length > 0) { 372 | if (supports_chunked_messages() && sending_chunked_message()) { 373 | // prepare the next chunk of data to send 374 | // write chunk length in hex 375 | auto cast_buf = std::array(); 376 | #ifdef _WIN32 377 | auto written = sprintf_s(cast_buf.data(), cast_buf.size(), "%lx", static_cast(content_length)); 378 | #else // !WIN32 379 | auto written = sprintf(cast_buf.data(), "%lx", static_cast(content_length)); 380 | #endif // WIN32 381 | 382 | // add chunk length as a string at the back of the text cache 383 | // append length of chunk to write_buffers 384 | write_buffers.push_back(add_to_cache({cast_buf.data(), written})); 385 | // append an extra CRLF for chunk formatting 386 | write_buffers.push_back(asio::buffer(http_message::STRING_CRLF)); 387 | 388 | // append response content buffers 389 | write_buffers.insert(write_buffers.end(), content_buffers.begin(), 390 | content_buffers.end()); 391 | // append an extra CRLF for chunk formatting 392 | write_buffers.push_back(asio::buffer(http_message::STRING_CRLF)); 393 | } else { 394 | // append response content buffers 395 | write_buffers.insert(write_buffers.end(), content_buffers.begin(), 396 | content_buffers.end()); 397 | } 398 | } 399 | 400 | // prepare a zero-byte (final) chunk 401 | if (send_final_chunk && supports_chunked_messages() && sending_chunked_message()) { 402 | // add chunk length as a string at the back of the text cache 403 | char zero = '0'; 404 | // append length of chunk to write_buffers 405 | write_buffers.push_back(add_to_cache({std::addressof(zero), 1})); 406 | // append an extra CRLF for chunk formatting 407 | write_buffers.push_back(asio::buffer(http_message::STRING_CRLF)); 408 | write_buffers.push_back(asio::buffer(http_message::STRING_CRLF)); 409 | } 410 | } 411 | 412 | /** 413 | * Add data to cache 414 | * 415 | * @param data data span 416 | * @return asio buffer pointing to copy of passed data 417 | */ 418 | asio::const_buffer add_to_cache(sl::io::span data) { 419 | payload_cache.emplace_back(new char[data.size()]); 420 | char* dest = payload_cache.back().get(); 421 | std::memcpy(dest, data.data(), data.size()); 422 | return asio::buffer(dest, data.size()); 423 | } 424 | }; 425 | 426 | /** 427 | * Data type for a response_writer pointer 428 | */ 429 | using response_writer_ptr = std::unique_ptr; 430 | 431 | } // namespace 432 | } 433 | 434 | #endif // STATICLIB_PION_HTTP_RESPONSE_WRITER_HPP 435 | -------------------------------------------------------------------------------- /include/staticlib/pion/http_server.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * File: streaming_server.hpp 19 | * Author: alex 20 | * 21 | * Created on March 23, 2015, 8:10 PM 22 | */ 23 | 24 | #ifndef STATICLIB_PION_HTTP_SERVER_HPP 25 | #define STATICLIB_PION_HTTP_SERVER_HPP 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "asio.hpp" 35 | 36 | #include "staticlib/config.hpp" 37 | #include "staticlib/support.hpp" 38 | 39 | #include "staticlib/pion/http_parser.hpp" 40 | #include "staticlib/pion/http_request.hpp" 41 | #include "staticlib/pion/http_response_writer.hpp" 42 | #include "staticlib/pion/tcp_connection.hpp" 43 | #include "staticlib/pion/tcp_server.hpp" 44 | #include "staticlib/pion/websocket.hpp" 45 | 46 | namespace staticlib { 47 | namespace pion { 48 | 49 | class http_request_reader; 50 | 51 | /** 52 | * Server extension that supports streaming requests of arbitrary size (file upload) 53 | */ 54 | class http_server : public tcp_server { 55 | friend class http_request_reader; 56 | 57 | public: 58 | /** 59 | * Type of function that is used to handle requests 60 | */ 61 | using request_handler_type = std::function; 62 | 63 | /** 64 | * Type of function that is used to create payload handlers 65 | */ 66 | using payload_handler_creator_type = std::function; 67 | 68 | /** 69 | * Data type for a map of resources to request handlers 70 | */ 71 | using handlers_map_type = std::unordered_map; 72 | 73 | /** 74 | * Data type for a map of resources to request handlers 75 | */ 76 | using payloads_map_type = std::unordered_map; 77 | 78 | /** 79 | * Data type for a map of resources to WebSocket handlers 80 | */ 81 | using websocket_map_type = std::unordered_map; 82 | 83 | // path -> (id, connection) 84 | using websocket_conn_registry_type = std::multimap>>; 85 | 86 | private: 87 | /** 88 | * Timeout for read operations 89 | */ 90 | uint32_t read_timeout; 91 | 92 | /** 93 | * Collection of GET handlers that are recognized by this HTTP server 94 | */ 95 | handlers_map_type get_handlers; 96 | 97 | /** 98 | * Collection of POST handlers that are recognized by this HTTP server 99 | */ 100 | handlers_map_type post_handlers; 101 | 102 | /** 103 | * Collection of PUT handlers that are recognized by this HTTP server 104 | */ 105 | handlers_map_type put_handlers; 106 | 107 | /** 108 | * Collection of DELETE handlers that are recognized by this HTTP server 109 | */ 110 | handlers_map_type delete_handlers; 111 | 112 | /** 113 | * Collection of OPTIONS handlers that are recognized by this HTTP server 114 | */ 115 | handlers_map_type options_handlers; 116 | 117 | /** 118 | * Points to a function that handles bad HTTP requests 119 | */ 120 | request_handler_type bad_request_handler; 121 | 122 | /** 123 | * Points to a function that handles requests which match no web services 124 | */ 125 | request_handler_type not_found_handler; 126 | 127 | /** 128 | * Collection of payload handlers GET resources that are recognized by this HTTP server 129 | */ 130 | // GET payload won't happen, but lets be consistent here 131 | // to simplify clients implementation and to make sure that 132 | // pion's form-data parsing won't be triggered 133 | payloads_map_type get_payloads; 134 | 135 | /** 136 | * Collection of payload handlers POST resources that are recognized by this HTTP server 137 | */ 138 | payloads_map_type post_payloads; 139 | 140 | /** 141 | * Collection of payload handlers PUT resources that are recognized by this HTTP server 142 | */ 143 | payloads_map_type put_payloads; 144 | 145 | /** 146 | * Collection of payload handlers DELETE resources that are recognized by this HTTP server 147 | */ 148 | payloads_map_type delete_payloads; 149 | 150 | /** 151 | * Collection of payload handlers OPTIONS resources that are recognized by this HTTP server 152 | */ 153 | payloads_map_type options_payloads; 154 | 155 | /** 156 | * Collection of WebSocket WSOPEN resources that are recognized by this HTTP server 157 | */ 158 | websocket_map_type wsopen_handlers; 159 | 160 | /** 161 | * Collection of WebSocket WSMESSAGE resources that are recognized by this HTTP server 162 | */ 163 | websocket_map_type wsmessage_handlers; 164 | 165 | /** 166 | * Collection of WebSocket WSCLOSE resources that are recognized by this HTTP server 167 | */ 168 | websocket_map_type wsclose_handlers; 169 | 170 | websocket_conn_registry_type websocket_conn_registry; 171 | 172 | std::mutex websocket_conn_registry_mtx; 173 | 174 | public: 175 | ~http_server() STATICLIB_NOEXCEPT { } 176 | 177 | /** 178 | * Creates a new server object 179 | * 180 | * @param number_of_threads number of threads to use for requests processing 181 | * @param port TCP port 182 | * @param read_timeout_millis timeout for read operations 183 | * @param ip_address (optional) IPv4-address to use, ANY address by default 184 | * @param ssl_key_file (optional) path file containing concatenated X.509 key and certificate, 185 | * empty by default (SSL disabled) 186 | * @param ssl_key_password_callback (optional) callback function that should return a password 187 | * that will be used to decrypt a PEM-encoded RSA private key file 188 | * @param ssl_verify_file (optional) path to file containing one or more CA certificates in PEM format 189 | * @param ssl_verify_callback (optional) callback function that can be used to customize client 190 | * certificate auth 191 | */ 192 | http_server(uint32_t number_of_threads, uint16_t port, 193 | asio::ip::address_v4 ip_address = asio::ip::address_v4::any(), 194 | uint32_t read_timeout_millis = 10000, 195 | const std::string& ssl_key_file = std::string(), 196 | std::function ssl_key_password_callback = 197 | [](std::size_t, asio::ssl::context::password_purpose) { return std::string(); }, 198 | const std::string& ssl_verify_file = std::string(), 199 | std::function ssl_verify_callback = 200 | [](bool, asio::ssl::verify_context&) { return true; }); 201 | 202 | /** 203 | * Adds a new web service to the HTTP server 204 | * 205 | * @param method HTTP method name 206 | * @param resource the resource name or uri-stem to bind to the handler 207 | * @param request_handler function used to handle requests to the resource 208 | */ 209 | void add_handler(const std::string& method, const std::string& resource, 210 | request_handler_type request_handler); 211 | 212 | /** 213 | * Sets the function that handles bad HTTP requests 214 | * 215 | * @param handler function that handles bad HTTP requests 216 | */ 217 | void set_bad_request_handler(request_handler_type handler) { 218 | bad_request_handler = std::move(handler); 219 | } 220 | 221 | /** 222 | * Sets the function that handles requests which match no other web services 223 | * 224 | * @param handler function that handles requests which match no other web services 225 | */ 226 | void set_not_found_handler(request_handler_type handler) { 227 | not_found_handler = std::move(handler); 228 | } 229 | 230 | /** 231 | * Adds a new payload_handler to the HTTP server 232 | * 233 | * @param method HTTP method name 234 | * @param resource the resource name or uri-stem to bind to the handler 235 | * @param payload_handler function used to handle payload for the request 236 | */ 237 | void add_payload_handler(const std::string& method, const std::string& resource, 238 | payload_handler_creator_type payload_handler); 239 | 240 | /** 241 | * Adds a new handler for WebSocket events 242 | * 243 | * @param event WebSocket event name 244 | * @param resource the resource name or uri-stem to bind to the handler 245 | * @param handler function used to handle WebSocket events 246 | */ 247 | void add_websocket_handler(const std::string& event, const std::string& resource, 248 | websocket_handler_type handler); 249 | 250 | /** 251 | * Broadcasts specified message to the WebSocket clients currently 252 | * connected on the specified path 253 | * 254 | * @param path websocket path clients connected on 255 | * @param message message to broadcast 256 | * @param frame_type type of the websocket frame to use, `text` by default 257 | * @param dest_ids broadcast only to the specified list of ids, 258 | * broadcast to all clients on the specified path by default 259 | */ 260 | void broadcast_websocket(const std::string& path, sl::io::span message, 261 | sl::websocket::frame_type frame_type = sl::websocket::frame_type::text, 262 | const std::set& dest_ids = std::set()); 263 | private: 264 | /** 265 | * Handles a new TCP connection 266 | * 267 | * @param tcp_conn the new TCP connection to handle 268 | */ 269 | virtual void handle_connection(tcp_connection_ptr& conn) override; 270 | 271 | /** 272 | * Handles a new HTTP request 273 | * 274 | * @param request the HTTP request to handle 275 | * @param conn TCP connection containing a new request 276 | * @param ec error_code contains additional information for parsing errors 277 | * @param rc parsing result code, false: abort, true: ignore_body, indeterminate: continue 278 | */ 279 | void handle_request_after_headers_parsed(http_request_ptr& request, 280 | tcp_connection_ptr& conn, const std::error_code& ec, sl::support::tribool& rc); 281 | 282 | /** 283 | * Handles a new HTTP request 284 | * 285 | * @param request the HTTP request to handle 286 | * @param conn TCP connection containing a new request 287 | * @param ec error_code contains additional information for parsing errors 288 | */ 289 | void handle_request(http_request_ptr request, 290 | tcp_connection_ptr& conn, const std::error_code& ec); 291 | 292 | 293 | }; 294 | 295 | } // namespace 296 | } 297 | 298 | #endif /* STATICLIB_PION_HTTP_SERVER_HPP */ 299 | 300 | -------------------------------------------------------------------------------- /include/staticlib/pion/logger.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // --------------------------------------------------------------------- 18 | // pion: a Boost C++ framework for building lightweight HTTP interfaces 19 | // --------------------------------------------------------------------- 20 | // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion) 21 | // 22 | // Distributed under the Boost Software License, Version 1.0. 23 | // See http://www.boost.org/LICENSE_1_0.txt 24 | // 25 | 26 | #ifndef STATICLIB_PION_LOGGER_HPP 27 | #define STATICLIB_PION_LOGGER_HPP 28 | 29 | #include "staticlib/config.hpp" 30 | 31 | #if defined(STATICLIB_PION_DISABLE_LOGGING) 32 | 33 | #define STATICLIB_PION_LOG_DEBUG(LOG, MSG) 34 | #define STATICLIB_PION_LOG_INFO(LOG, MSG) 35 | #define STATICLIB_PION_LOG_WARN(LOG, MSG) 36 | #define STATICLIB_PION_LOG_ERROR(LOG, MSG) 37 | #define STATICLIB_PION_LOG_FATAL(LOG, MSG) 38 | 39 | #elif defined(STATICLIB_PION_USE_WILTON_LOGGING) 40 | 41 | #include 42 | #include 43 | 44 | #include "wilton/wilton_logging.h" 45 | 46 | namespace staticlib { 47 | namespace pion { 48 | namespace logger { 49 | 50 | /** 51 | * Send log message to wilton_logging 52 | * 53 | * @param name logger name 54 | * @param level logging level 55 | * @param message message 56 | * 57 | */ 58 | inline void log(const std::string& name, const std::string& level, const std::string& message){ 59 | wilton_logger_log(level.c_str(), static_cast(level.length()), 60 | name.c_str(), static_cast(name.length()), 61 | message.c_str(), static_cast(message.length())); 62 | } 63 | 64 | /** 65 | * Check whether specified logging level is enabled 66 | * 67 | * @param name logger name 68 | * @param level level to check 69 | * @returns true if enabled, false otherwise 70 | */ 71 | inline bool is_priority_enabled(const std::string& name, const std::string& level){ 72 | int res = 0; 73 | wilton_logger_is_level_enabled(name.c_str(), static_cast(name.length()), 74 | level.c_str(), static_cast(level.length()), std::addressof(res)); 75 | return res != 0; 76 | } 77 | 78 | } // namespace 79 | } 80 | } 81 | 82 | // Logging api, used in pion, send MSG as [str1 << str2], ostringstream used to handle it. 83 | #define STATICLIB_PION_LOG_TO_WILTON(LOG, LEVEL, MSG) \ 84 | if (logger::is_priority_enabled(LOG, LEVEL)) { \ 85 | std::ostringstream ostream; \ 86 | ostream << MSG; \ 87 | logger::log(LOG, LEVEL, ostream.str()); \ 88 | } 89 | 90 | #define STATICLIB_PION_LOG_DEBUG(LOG, MSG) STATICLIB_PION_LOG_TO_WILTON(LOG, "DEBUG", MSG) 91 | #define STATICLIB_PION_LOG_INFO(LOG, MSG) STATICLIB_PION_LOG_TO_WILTON(LOG, "INFO", MSG) 92 | #define STATICLIB_PION_LOG_WARN(LOG, MSG) STATICLIB_PION_LOG_TO_WILTON(LOG, "WARN", MSG) 93 | #define STATICLIB_PION_LOG_ERROR(LOG, MSG) STATICLIB_PION_LOG_TO_WILTON(LOG, "ERROR", MSG) 94 | #define STATICLIB_PION_LOG_FATAL(LOG, MSG) STATICLIB_PION_LOG_TO_WILTON(LOG, "FATAL", MSG) 95 | 96 | #else 97 | 98 | // Logging uses std::cout and std::cerr 99 | #include 100 | #include 101 | #include 102 | #include 103 | 104 | #define STATICLIB_PION_LOG_TO_OSTREAM(LOG, LEVEL, MSG) \ 105 | { std::cout << std::time(nullptr) << ' ' << std::this_thread::get_id() << ' ' << LEVEL << ' ' << LOG << ' ' << MSG << std::endl; } 106 | 107 | #define STATICLIB_PION_LOG_DEBUG(LOG, MSG) STATICLIB_PION_LOG_TO_OSTREAM(LOG, "DEBUG", MSG) 108 | #define STATICLIB_PION_LOG_INFO(LOG, MSG) STATICLIB_PION_LOG_TO_OSTREAM(LOG, "INFO", MSG) 109 | #define STATICLIB_PION_LOG_WARN(LOG, MSG) STATICLIB_PION_LOG_TO_OSTREAM(LOG, "WARN", MSG) 110 | #define STATICLIB_PION_LOG_ERROR(LOG, MSG) STATICLIB_PION_LOG_TO_OSTREAM(LOG, "ERROR", MSG) 111 | #define STATICLIB_PION_LOG_FATAL(LOG, MSG) STATICLIB_PION_LOG_TO_OSTREAM(LOG, "FATAL", MSG) 112 | 113 | #endif 114 | 115 | #endif // STATICLIB_PION_LOGGER_HPP 116 | -------------------------------------------------------------------------------- /include/staticlib/pion/pion_exception.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * File: pion_exception.hpp 19 | * Author: alex 20 | * 21 | * Created on September 24, 2015, 1:38 PM 22 | */ 23 | 24 | #ifndef STATICLIB_PION_PION_EXCEPTION_HPP 25 | #define STATICLIB_PION_PION_EXCEPTION_HPP 26 | 27 | #include 28 | #include 29 | 30 | #include "staticlib/support/exception.hpp" 31 | 32 | namespace staticlib { 33 | namespace pion { 34 | 35 | /** 36 | * Base exception class for business exceptions in staticlib modules 37 | */ 38 | class pion_exception : public sl::support::exception { 39 | public: 40 | /** 41 | * Default constructor 42 | */ 43 | pion_exception() = default; 44 | 45 | /** 46 | * Constructor with message 47 | * 48 | * @param msg error message 49 | */ 50 | pion_exception(const std::string& msg) : 51 | sl::support::exception(msg) { } 52 | 53 | }; 54 | 55 | } // namespace 56 | } 57 | 58 | #endif /* STATICLIB_PION_PION_EXCEPTION_HPP */ 59 | 60 | -------------------------------------------------------------------------------- /include/staticlib/pion/scheduler.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // --------------------------------------------------------------------- 18 | // pion: a Boost C++ framework for building lightweight HTTP interfaces 19 | // --------------------------------------------------------------------- 20 | // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion) 21 | // 22 | // Distributed under the Boost Software License, Version 1.0. 23 | // See http://www.boost.org/LICENSE_1_0.txt 24 | // 25 | 26 | #ifndef STATICLIB_PION_SCHEDULER_HPP 27 | #define STATICLIB_PION_SCHEDULER_HPP 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "asio.hpp" 39 | 40 | #include "staticlib/config.hpp" 41 | 42 | namespace staticlib { 43 | namespace pion { 44 | 45 | /** 46 | * Scheduler, combines Boost.ASIO with a managed thread pool for scheduling server threads 47 | */ 48 | class scheduler { 49 | /** 50 | * Mutex to make class thread-safe 51 | */ 52 | std::mutex mutex; 53 | 54 | /** 55 | * Condition triggered when there are no more active users 56 | */ 57 | std::condition_variable no_more_active_users; 58 | 59 | /** 60 | * Condition triggered when the scheduler has stopped 61 | */ 62 | std::condition_variable scheduler_has_stopped; 63 | 64 | /** 65 | * Total number of worker threads in the pool 66 | */ 67 | uint32_t num_threads; 68 | 69 | /** 70 | * The scheduler will not shutdown until there are no more active users 71 | */ 72 | uint32_t active_users; 73 | 74 | /** 75 | * True if the thread scheduler is running 76 | */ 77 | bool running; 78 | 79 | /** 80 | * Pool of threads used to perform work 81 | */ 82 | std::vector> thread_pool; 83 | 84 | /** 85 | * Service used to manage async I/O events 86 | */ 87 | asio::io_service asio_service; 88 | 89 | /** 90 | * Timer used to periodically check for shutdown 91 | */ 92 | asio::steady_timer timer; 93 | 94 | /** 95 | * Hook function, that is called after each scheduled thread will exit 96 | */ 97 | std::function thread_stop_hook; 98 | 99 | public: 100 | 101 | /** 102 | * Constructor 103 | */ 104 | scheduler(uint32_t number_of_threads) : 105 | num_threads(number_of_threads), 106 | active_users(0), 107 | running(false), 108 | asio_service(), 109 | timer(asio_service), 110 | thread_stop_hook([]() STATICLIB_NOEXCEPT {}) { } 111 | 112 | /** 113 | * Deleted copy constructor 114 | */ 115 | scheduler(const scheduler&) = delete; 116 | 117 | /** 118 | * Deleted copy assignment operator 119 | */ 120 | scheduler& operator=(const scheduler&) = delete; 121 | 122 | /** 123 | * Destructor 124 | */ 125 | ~scheduler() { 126 | shutdown(); 127 | } 128 | 129 | /** 130 | * Starts the thread scheduler (this is called automatically when necessary) 131 | */ 132 | void startup(); 133 | 134 | /** 135 | * Stops the thread scheduler (this is called automatically when the program exits) 136 | */ 137 | void shutdown(); 138 | 139 | /** 140 | * The calling thread will sleep until the scheduler has stopped 141 | */ 142 | void join(); 143 | 144 | /** 145 | * Registers an active user with the thread scheduler. Shutdown of the 146 | * scheduler is deferred until there are no more active users. This 147 | * ensures that any work queued will not reference destructed objects 148 | */ 149 | void add_active_user(); 150 | 151 | /** 152 | * Unregisters an active user with the thread scheduler 153 | */ 154 | void remove_active_user(); 155 | 156 | /** 157 | * Returns true if the scheduler is running 158 | * 159 | * @return whether scheduler is running 160 | */ 161 | bool is_running() const { 162 | return running; 163 | } 164 | 165 | /** 166 | * Returns an async I/O service used to schedule work 167 | * 168 | * @return asio service 169 | */ 170 | asio::io_service& get_io_service() { 171 | return asio_service; 172 | } 173 | 174 | /** 175 | * Schedules work to be performed by one of the pooled threads 176 | * 177 | * @param work_func work function to be executed 178 | */ 179 | void post(std::function work_func) { 180 | get_io_service().post(work_func); 181 | } 182 | 183 | /** 184 | * Thread function used to keep the io_service running 185 | * 186 | * @param my_service IO service used to re-schedule keep_running() 187 | * @param my_timer deadline timer used to keep the IO service active while running 188 | */ 189 | void keep_running(asio::io_service& my_service, asio::steady_timer& my_timer); 190 | 191 | /** 192 | * processes work passed to the asio service & handles uncaught exceptions 193 | * 194 | * @param service asio service 195 | */ 196 | void process_service_work(asio::io_service& service); 197 | 198 | /** 199 | * Setter for hook function, that is called from each worker thread 200 | * just before that worker thread is going to exit 201 | * 202 | * @param hook hook function 203 | */ 204 | void set_thread_stop_hook(std::function hook) { 205 | std::lock_guard scheduler_lock{mutex}; 206 | this->thread_stop_hook = hook; 207 | } 208 | 209 | private: 210 | 211 | /** 212 | * Stops all threads used to perform work 213 | */ 214 | void stop_threads(); 215 | 216 | }; 217 | 218 | } // namespace 219 | } 220 | 221 | #endif // STATICLIB_PION_SCHEDULER_HPP 222 | -------------------------------------------------------------------------------- /include/staticlib/pion/tcp_connection.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // --------------------------------------------------------------------- 18 | // pion: a Boost C++ framework for building lightweight HTTP interfaces 19 | // --------------------------------------------------------------------- 20 | // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion) 21 | // 22 | // Distributed under the Boost Software License, Version 1.0. 23 | // See http://www.boost.org/LICENSE_1_0.txt 24 | // 25 | 26 | #ifndef STATICLIB_PION_TCP_CONNECTION_HPP 27 | #define STATICLIB_PION_TCP_CONNECTION_HPP 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "asio.hpp" 35 | #include "asio/ssl.hpp" 36 | 37 | #include "staticlib/config.hpp" 38 | 39 | #include "staticlib/pion/algorithm.hpp" 40 | 41 | namespace staticlib { 42 | namespace pion { 43 | 44 | /** 45 | * Represents a single tcp connection 46 | */ 47 | class tcp_connection : public std::enable_shared_from_this { 48 | 49 | public: 50 | 51 | /** 52 | * Data type for the connection's current_lifecycle state 53 | */ 54 | enum class lifecycle { 55 | close, 56 | keepalive, 57 | pipelined 58 | }; 59 | 60 | /** 61 | * Data type for a function that handles TCP connection objects 62 | */ 63 | using connection_handler = std::function&)>; 64 | 65 | /** 66 | * Data type for an I/O read buffer 67 | */ 68 | using read_buffer_type = std::array; 69 | 70 | /** 71 | * Data type for a socket connection 72 | */ 73 | using socket_type = asio::ip::tcp::socket; 74 | 75 | /** 76 | * Data type for an SSL socket connection 77 | */ 78 | using ssl_socket_type = asio::ssl::stream; 79 | 80 | /** 81 | * Data type for SSL configuration context 82 | */ 83 | using ssl_context_type = asio::ssl::context; 84 | 85 | private: 86 | 87 | /** 88 | * SSL connection socket 89 | */ 90 | ssl_socket_type ssl_socket; 91 | 92 | /** 93 | * True if the connection is encrypted using SSL 94 | */ 95 | bool ssl_flag; 96 | 97 | /** 98 | * Buffer used for reading data from the TCP connection 99 | */ 100 | read_buffer_type read_buffer; 101 | 102 | /** 103 | * Saved read position bookmark 104 | */ 105 | std::pair read_position; 106 | 107 | /** 108 | * Lifecycle state for the connection 109 | */ 110 | lifecycle current_lifecycle; 111 | 112 | /** 113 | * Function called when a server has finished handling the connection 114 | */ 115 | connection_handler finished_handler; 116 | 117 | /** 118 | * Strand used to synchronize all async operations over this connection 119 | */ 120 | asio::io_service::strand strand; 121 | 122 | /** 123 | * Timer that can be used with IO operations over this connection 124 | */ 125 | asio::steady_timer timer; 126 | 127 | public: 128 | 129 | /** 130 | * Constructor to be used with `std::make_shared` 131 | * 132 | * @param io_service asio service associated with the connection 133 | * @param ssl_context asio ssl context associated with the connection 134 | * @param ssl_flag if true then the connection will be encrypted using SSL 135 | * @param finished_handler function called when a server has finished 136 | * handling the connection 137 | */ 138 | tcp_connection(asio::io_service& io_service, ssl_context_type& ssl_context, const bool ssl_flag_in, 139 | connection_handler finished_handler_in) : 140 | ssl_socket(io_service, ssl_context), 141 | ssl_flag(ssl_flag_in), 142 | current_lifecycle(lifecycle::close), 143 | finished_handler(finished_handler_in), 144 | strand(io_service), 145 | timer(io_service) { 146 | save_read_pos(nullptr, nullptr); 147 | } 148 | 149 | /** 150 | * Deleted copy constructor 151 | */ 152 | tcp_connection(const tcp_connection&) = delete; 153 | 154 | /** 155 | * Deleted copy assignment operator 156 | */ 157 | tcp_connection& operator=(const tcp_connection&) = delete; 158 | 159 | /** 160 | * Virtual destructor 161 | */ 162 | virtual ~tcp_connection() { 163 | close(); 164 | } 165 | 166 | /** 167 | * Returns true if the connection is currently open 168 | * 169 | * @return true if the connection is currently open 170 | */ 171 | bool is_open() const { 172 | return const_cast (ssl_socket).lowest_layer().is_open(); 173 | } 174 | 175 | /** 176 | * Closes the tcp socket and cancels any pending asynchronous operations 177 | */ 178 | void close() { 179 | if (is_open()) { 180 | try { 181 | // shutting down SSL will wait forever for a response from the remote end, 182 | // which causes it to hang indefinitely if the other end died unexpectedly 183 | // if (get_ssl_flag()) ssl_socket.shutdown(); 184 | 185 | // windows seems to require this otherwise it doesn't 186 | // recognize that connections have been closed 187 | ssl_socket.next_layer().shutdown(asio::ip::tcp::socket::shutdown_both); 188 | } catch (...) { 189 | } // ignore exceptions 190 | 191 | // close the underlying socket (ignore errors) 192 | std::error_code ec; 193 | ssl_socket.next_layer().close(ec); 194 | } 195 | } 196 | 197 | /** 198 | * Cancels any asynchronous operations pending on the socket. 199 | */ 200 | void cancel() { 201 | // there is no good way to do this on windows until vista or later (0x0600) 202 | // http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/basic_stream_socket/cancel/overload2.html 203 | // note that the asio docs are misleading because close() is not thread-safe, 204 | // and the suggested #define statements cause WAY too much trouble and heartache 205 | #if !defined(_MSC_VER) || (_WIN32_WINNT >= 0x0600) 206 | std::error_code ec; 207 | ssl_socket.next_layer().cancel(ec); 208 | #endif // !WINXP 209 | } 210 | 211 | /** 212 | * Cancels timer 213 | */ 214 | void cancel_timer() { 215 | #if !defined(_MSC_VER) || (_WIN32_WINNT >= 0x0600) 216 | std::error_code ec; 217 | timer.cancel(ec); 218 | #endif // !WINXP 219 | } 220 | 221 | /** 222 | * Asynchronously accepts a new tcp connection 223 | * 224 | * @param tcp_acceptor object used to accept new connections 225 | * @param handler called after a new connection has been accepted 226 | * 227 | * @see asio::basic_socket_acceptor::async_accept() 228 | */ 229 | template 230 | void async_accept(asio::ip::tcp::acceptor& tcp_acceptor, AcceptHandler handler) { 231 | tcp_acceptor.async_accept(ssl_socket.lowest_layer(), handler); 232 | } 233 | 234 | /** 235 | * Asynchronously performs server-side SSL handshake for a new connection 236 | * 237 | * @param handler called after the ssl handshake has completed 238 | * 239 | * @see asio::ssl::stream::async_handshake() 240 | */ 241 | template 242 | void async_handshake_server(SSLHandshakeHandler handler) { 243 | ssl_socket.async_handshake(asio::ssl::stream_base::server, handler); 244 | ssl_flag = true; 245 | } 246 | 247 | /** 248 | * Asynchronously reads some data into the connection's read buffer 249 | * 250 | * @param handler called after the read operation has completed 251 | * 252 | * @see asio::basic_stream_socket::async_read_some() 253 | */ 254 | template 255 | void async_read_some(ReadHandler handler) { 256 | if (get_ssl_flag()) { 257 | ssl_socket.async_read_some(asio::buffer(read_buffer), handler); 258 | } else { 259 | ssl_socket.next_layer().async_read_some(asio::buffer(read_buffer), handler); 260 | } 261 | } 262 | 263 | /** 264 | * Asynchronously writes data to the connection 265 | * 266 | * @param buffers one or more buffers containing the data to be written 267 | * @param handler called after the data has been written 268 | * 269 | * @see asio::async_write() 270 | */ 271 | template 272 | void async_write(const ConstBufferSequence& buffers, write_handler_t handler) { 273 | if (get_ssl_flag()) { 274 | asio::async_write(ssl_socket, buffers, handler); 275 | } else { 276 | asio::async_write(ssl_socket.next_layer(), buffers, handler); 277 | } 278 | } 279 | 280 | /** 281 | * This function should be called when a server has finished handling the connection 282 | */ 283 | void finish() { 284 | auto conn = shared_from_this(); 285 | if (finished_handler) { 286 | finished_handler(conn); 287 | } 288 | } 289 | 290 | /** 291 | * Returns true if the connection is encrypted using SSL 292 | * 293 | * @return true if the connection is encrypted using SSL 294 | */ 295 | bool get_ssl_flag() const { 296 | return ssl_flag; 297 | } 298 | 299 | /** 300 | * Sets the lifecycle for the connection 301 | * 302 | * @param lcycle lifecycle type name 303 | */ 304 | void set_lifecycle(lifecycle lcycle) { 305 | current_lifecycle = lcycle; 306 | } 307 | 308 | /** 309 | * Returns true if the connection should be kept alive 310 | * 311 | * @return 312 | */ 313 | bool get_keep_alive() const { 314 | return current_lifecycle != lifecycle::close; 315 | } 316 | 317 | /** 318 | * Returns true if the HTTP requests are pipelined 319 | * 320 | * @return true if the HTTP requests are pipelined 321 | */ 322 | bool is_pipelined() const { 323 | return current_lifecycle == lifecycle::pipelined; 324 | } 325 | 326 | /** 327 | * Returns the buffer used for reading data from the TCP connection 328 | * 329 | * @return buffer used for reading data from the TCP connection 330 | */ 331 | read_buffer_type& get_read_buffer() { 332 | return read_buffer; 333 | } 334 | 335 | /** 336 | * Saves a read position bookmark 337 | * 338 | * @param read_ptr points to the next character to be consumed in the read_buffer 339 | * @param read_end_ptr points to the end of the read_buffer (last byte + 1) 340 | */ 341 | void save_read_pos(const char *read_ptr, const char *read_end_ptr) { 342 | read_position.first = read_ptr; 343 | read_position.second = read_end_ptr; 344 | } 345 | 346 | /** 347 | * Loads a read position bookmark 348 | * 349 | * @param read_ptr points to the next character to be consumed in the read_buffer 350 | * @param read_end_ptr points to the end of the read_buffer (last byte + 1) 351 | */ 352 | void load_read_pos(const char *&read_ptr, const char *&read_end_ptr) const { 353 | read_ptr = read_position.first; 354 | read_end_ptr = read_position.second; 355 | } 356 | 357 | /** 358 | * Returns an ASIO endpoint for the client connection 359 | * 360 | * @return endpoint 361 | */ 362 | asio::ip::tcp::endpoint get_remote_endpoint() const { 363 | asio::ip::tcp::endpoint remote_endpoint; 364 | try { 365 | // const_cast is required since lowest_layer() is only defined non-const in asio 366 | remote_endpoint = const_cast (ssl_socket).lowest_layer().remote_endpoint(); 367 | } catch (asio::system_error& /* e */) { 368 | // do nothing 369 | } 370 | return remote_endpoint; 371 | } 372 | 373 | /** 374 | * Returns the client's IP address 375 | * 376 | * @return client's IP address 377 | */ 378 | asio::ip::address get_remote_ip() const { 379 | return get_remote_endpoint().address(); 380 | } 381 | 382 | /** 383 | * Returns the client's port number 384 | * 385 | * @return client's port number 386 | */ 387 | unsigned short get_remote_port() const { 388 | return get_remote_endpoint().port(); 389 | } 390 | 391 | /** 392 | * Returns reference to the io_service used for async operations 393 | * 394 | * @return io_service used for async operations 395 | */ 396 | asio::io_service& get_io_service() { 397 | #if ASIO_VERSION >= 101400 398 | return static_cast(ssl_socket.lowest_layer().get_executor().context()); 399 | #else 400 | return ssl_socket.lowest_layer().get_io_service(); 401 | #endif 402 | } 403 | 404 | /** 405 | * Returns non-const reference to underlying TCP socket object 406 | * 407 | * @return underlying TCP socket object 408 | */ 409 | socket_type& get_socket() { 410 | return ssl_socket.next_layer(); 411 | } 412 | 413 | /** 414 | * Returns non-const reference to underlying SSL socket object 415 | * 416 | * @return underlying SSL socket object 417 | */ 418 | ssl_socket_type& get_ssl_socket() { 419 | return ssl_socket; 420 | } 421 | 422 | /** 423 | * Returns the strand that can be used with this connection 424 | * 425 | * @return the strand that can be used with this connection 426 | */ 427 | asio::io_service::strand& get_strand() { 428 | return strand; 429 | } 430 | 431 | /** 432 | * Returns the timer that can be used with this connection 433 | * 434 | * @return the timer that can be used with this connection 435 | */ 436 | asio::steady_timer& get_timer() { 437 | return timer; 438 | } 439 | 440 | }; 441 | 442 | /** 443 | * Data type for a connection pointer 444 | */ 445 | using tcp_connection_ptr = std::shared_ptr; 446 | 447 | } // namespace 448 | } 449 | 450 | #endif // STATICLIB_PION_TCP_CONNECTION_HPP 451 | -------------------------------------------------------------------------------- /include/staticlib/pion/tcp_server.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // --------------------------------------------------------------------- 18 | // pion: a Boost C++ framework for building lightweight HTTP interfaces 19 | // --------------------------------------------------------------------- 20 | // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion) 21 | // 22 | // Distributed under the Boost Software License, Version 1.0. 23 | // See http://www.boost.org/LICENSE_1_0.txt 24 | // 25 | 26 | #ifndef STATICLIB_PION_TCP_SERVER_HPP 27 | #define STATICLIB_PION_TCP_SERVER_HPP 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include "asio.hpp" 34 | 35 | #include "staticlib/config.hpp" 36 | 37 | #include "staticlib/pion/scheduler.hpp" 38 | #include "staticlib/pion/tcp_connection.hpp" 39 | 40 | namespace staticlib { 41 | namespace pion { 42 | 43 | /** 44 | * Multi-threaded, asynchronous TCP server 45 | */ 46 | class tcp_server { 47 | 48 | protected: 49 | /** 50 | * Reference to the active scheduler object used to manage worker threads 51 | */ 52 | scheduler active_scheduler; 53 | 54 | /** 55 | * Manages async TCP connections 56 | */ 57 | asio::ip::tcp::acceptor tcp_acceptor; 58 | 59 | /** 60 | * Context used for SSL configuration 61 | */ 62 | tcp_connection::ssl_context_type ssl_context; 63 | 64 | /** 65 | * Condition triggered when the server has stopped listening for connections 66 | */ 67 | std::condition_variable server_has_stopped; 68 | 69 | /** 70 | * Condition triggered when the connection pool is empty 71 | */ 72 | std::condition_variable no_more_connections; 73 | 74 | /** 75 | * Pool of active connections associated with this server 76 | */ 77 | std::set conn_pool; 78 | 79 | /** 80 | * TCP endpoint used to listen for new connections 81 | */ 82 | asio::ip::tcp::endpoint tcp_endpoint; 83 | 84 | /** 85 | * true if the server uses SSL to encrypt connections 86 | */ 87 | bool ssl_flag; 88 | 89 | /** 90 | * Set to true when the server is listening for new connections 91 | */ 92 | bool listening; 93 | 94 | /** 95 | * Mutex to make class thread-safe 96 | */ 97 | mutable std::mutex mutex; 98 | 99 | public: 100 | 101 | /** 102 | * Protected constructor so that only derived objects may be created 103 | * 104 | * @param endpoint TCP endpoint used to listen for new connections (see ASIO docs) 105 | */ 106 | tcp_server(const asio::ip::tcp::endpoint& endpoint, uint32_t number_of_threads) : 107 | active_scheduler(number_of_threads), 108 | tcp_acceptor(active_scheduler.get_io_service()), 109 | ssl_context(asio::ssl::context::sslv23), 110 | tcp_endpoint(endpoint), 111 | ssl_flag(false), 112 | listening(false) { } 113 | 114 | /** 115 | * Deleted copy constructor 116 | */ 117 | tcp_server(const tcp_server&) = delete; 118 | 119 | /** 120 | * Deleted copy assignment operator 121 | */ 122 | tcp_server& operator=(const tcp_server&) = delete; 123 | 124 | /** 125 | * Virtual destructor 126 | */ 127 | virtual ~tcp_server() STATICLIB_NOEXCEPT { 128 | if (listening) { 129 | try { 130 | stop(false); 131 | } catch (const std::exception& e) { 132 | (void) e; 133 | // STATICLIB_PION_LOG_WARN("Exception thrown in tcp::server destructor: " << e.message()); 134 | } 135 | } 136 | } 137 | 138 | /** 139 | * Starts listening for new connections 140 | */ 141 | void start(); 142 | 143 | /** 144 | * Stops listening for new connections 145 | * 146 | * @param wait_until_finished if true, blocks until all pending connections have closed 147 | */ 148 | void stop(bool wait_until_finished = false); 149 | 150 | /** 151 | * Returns true if the server is listening for connections 152 | * 153 | * @return true if the server is listening for connections 154 | */ 155 | bool is_listening() const { 156 | return listening; 157 | } 158 | 159 | /** 160 | * Handles a new TCP connection; derived classes SHOULD override this 161 | * since the default behavior does nothing 162 | * 163 | * @param tcp_conn the new TCP connection to handle 164 | */ 165 | virtual void handle_connection(tcp_connection_ptr& tcp_conn) { 166 | tcp_conn->set_lifecycle(tcp_connection::lifecycle::close); // make sure it will get closed 167 | tcp_conn->finish(); 168 | } 169 | 170 | /** 171 | * Returns an async I/O service used to schedule work 172 | * 173 | * @return asio service 174 | */ 175 | asio::io_service& get_io_service() { 176 | return active_scheduler.get_io_service(); 177 | } 178 | 179 | /** 180 | * Return active scheduler 181 | * 182 | * @return scheduler 183 | */ 184 | scheduler& get_scheduler() { 185 | return active_scheduler; 186 | } 187 | 188 | /** 189 | * Return active endpoint 190 | * 191 | * @return endpoint 192 | */ 193 | asio::ip::tcp::endpoint& get_tcp_endpoint() { 194 | return tcp_endpoint; 195 | } 196 | 197 | private: 198 | 199 | /** 200 | * Handles a request to stop the server 201 | */ 202 | void handle_stop_request(); 203 | 204 | /** 205 | * Listens for a new connection 206 | */ 207 | void listen(); 208 | 209 | /** 210 | * Handles new connections (checks if there was an accept error) 211 | * 212 | * @param tcp_conn the new TCP connection (if no error occurred) 213 | * @param accept_error true if an error occurred while accepting connections 214 | */ 215 | void handle_accept(tcp_connection_ptr& tcp_conn, const std::error_code& accept_error); 216 | 217 | /** 218 | * Handles new connections following an SSL handshake (checks for errors) 219 | * 220 | * @param tcp_conn the new TCP connection (if no error occurred) 221 | * @param handshake_error true if an error occurred during the SSL handshake 222 | */ 223 | void handle_ssl_handshake(tcp_connection_ptr& tcp_conn, const std::error_code& handshake_error); 224 | 225 | /** 226 | * This will be called by connection::finish() after a server has 227 | * finished handling a connection. If the keep_alive flag is true, 228 | * it will call handle_connection(); otherwise, it will close the 229 | * connection and remove it from the server's management pool 230 | * 231 | * @param tcp_conn TCP connection 232 | */ 233 | void finish_connection(tcp_connection_ptr& tcp_conn); 234 | 235 | /** 236 | * Prunes orphaned connections that did not close cleanly 237 | * and returns the remaining number of connections in the pool 238 | * 239 | * @return remaining number of connections in the pool 240 | */ 241 | std::size_t prune_connections(); 242 | 243 | }; 244 | 245 | } // namespace 246 | } 247 | 248 | #endif // STATICLIB_PION_TCP_SERVER_HPP 249 | -------------------------------------------------------------------------------- /resources/Doxyfile.in: -------------------------------------------------------------------------------- 1 | # Copyright 2015, alex at staticlibs.net 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Doxyfile 1.8.1.2 16 | 17 | DOXYFILE_ENCODING = UTF-8 18 | PROJECT_NAME = ${PROJECT_NAME} 19 | PROJECT_NUMBER = ${${PROJECT_NAME}_STATICLIB_VERSION} 20 | PROJECT_LOGO = ${CMAKE_CURRENT_LIST_DIR}/resources/logo.png 21 | OUTPUT_DIRECTORY = ${CMAKE_CURRENT_BINARY_DIR}/docs 22 | FULL_PATH_NAMES = YES 23 | STRIP_FROM_PATH = ${CMAKE_CURRENT_LIST_DIR}/include/ 24 | STRIP_FROM_INC_PATH = ${CMAKE_CURRENT_LIST_DIR}/include/ 25 | EXTRACT_ALL = YES 26 | EXTRACT_STATIC = YES 27 | JAVADOC_AUTOBRIEF = YES 28 | INPUT = ${CMAKE_CURRENT_LIST_DIR}/include 29 | INPUT_ENCODING = UTF-8 30 | RECURSIVE = YES 31 | GENERATE_LATEX = NO 32 | -------------------------------------------------------------------------------- /resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticlibs/staticlib_pion/ce3633f7c2c0838b0fffea8d2edc65329986024c/resources/logo.png -------------------------------------------------------------------------------- /resources/macros.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2015, alex at staticlibs.net 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | cmake_minimum_required ( VERSION 2.8.12 ) 16 | 17 | # enhanced version of pkg_check_modules macro with PKG_CONFIG_PATH logic 18 | # PKG_CONFIG_PATH handling through CMAKE_PREFIX_PATH was added in newer versions of CMake 19 | macro ( ${PROJECT_NAME}_pkg_check_modules _out_var_name _modifier _modules_list_var_name ) 20 | find_package ( PkgConfig ) 21 | if ( WIN32 ) 22 | set ( PATHENV_SEPARATOR ";" ) 23 | else ( ) 24 | set ( PATHENV_SEPARATOR ":" ) 25 | endif ( ) 26 | set (_pkgconfig_path $ENV{PKG_CONFIG_PATH} ) 27 | if ( STATICLIB_USE_DEPLIBS_CACHE ) 28 | set ( ENV{PKG_CONFIG_PATH} "${STATICLIB_DEPLIBS_CACHE_DIR}/pkgconfig${PATHENV_SEPARATOR}$ENV{PKG_CONFIG_PATH}" ) 29 | endif ( ) 30 | set ( ENV{PKG_CONFIG_PATH} "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pkgconfig${PATHENV_SEPARATOR}$ENV{PKG_CONFIG_PATH}" ) 31 | pkg_check_modules ( ${_out_var_name} ${_modifier} ${${_modules_list_var_name}} ) 32 | set ( ENV{PKG_CONFIG_PATH} ${_pkgconfig_path} ) 33 | endmacro ( ) 34 | 35 | # converts list to space-separated string with a prefix to each element 36 | macro ( ${PROJECT_NAME}_list_to_string _out_var_name _prefix _list_var_name ) 37 | set ( ${_out_var_name} "" ) 38 | foreach ( _el ${${_list_var_name}} ) 39 | set ( ${_out_var_name} "${${_out_var_name}}${_prefix}${_el} " ) 40 | endforeach ( ) 41 | endmacro ( ) 42 | 43 | # call add_subdirectory using only if specified module is not yet added to main project 44 | macro ( ${PROJECT_NAME}_add_subdirectory _project_path ) 45 | string ( REGEX REPLACE "^.*/" "" _target_name ${_project_path} ) 46 | if ( NOT TARGET ${_target_name} ) 47 | message ( STATUS "Adding dependency: [${_target_name}], path: [${_project_path}]" ) 48 | add_subdirectory ( ${_project_path} ${CMAKE_BINARY_DIR}/${_target_name} ) 49 | set_target_properties ( ${_target_name} PROPERTIES FOLDER "deps" ) 50 | endif ( ) 51 | endmacro ( ) 52 | -------------------------------------------------------------------------------- /resources/pkg-config.in: -------------------------------------------------------------------------------- 1 | # Copyright 2015, alex at staticlibs.net 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | Name: ${PROJECT_NAME} 16 | Description: ${${PROJECT_NAME}_DESCRIPTION} 17 | URL: ${${PROJECT_NAME}_URL} 18 | Version: ${${PROJECT_NAME}_STATICLIB_VERSION} 19 | 20 | Requires: ${${PROJECT_NAME}_PC_REQUIRES} 21 | Requires.private: ${${PROJECT_NAME}_PC_REQUIRES_PRIVATE} 22 | Libs: ${${PROJECT_NAME}_PC_LIBS} 23 | Libs.private: ${${PROJECT_NAME}_PC_LIBS_PRIVATE} 24 | Cflags: ${${PROJECT_NAME}_PC_CFLAGS} 25 | -------------------------------------------------------------------------------- /src/http_message.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // --------------------------------------------------------------------- 18 | // pion: a Boost C++ framework for building lightweight HTTP interfaces 19 | // --------------------------------------------------------------------- 20 | // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion) 21 | // 22 | // Distributed under the Boost Software License, Version 1.0. 23 | // See http://www.boost.org/LICENSE_1_0.txt 24 | // 25 | 26 | #include "staticlib/pion/http_message.hpp" 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "asio.hpp" 36 | 37 | #include "staticlib/support.hpp" 38 | #include "staticlib/utils.hpp" 39 | 40 | #include "staticlib/pion/http_request.hpp" 41 | #include "staticlib/pion/http_parser.hpp" 42 | #include "staticlib/pion/tcp_connection.hpp" 43 | 44 | namespace staticlib { 45 | namespace pion { 46 | 47 | // static members of message 48 | 49 | // generic strings used by HTTP 50 | const std::string http_message::STRING_EMPTY; 51 | const std::string http_message::STRING_CRLF("\x0D\x0A"); 52 | const std::string http_message::STRING_HTTP_VERSION("HTTP/"); 53 | const std::string http_message::HEADER_NAME_VALUE_DELIMITER(": "); 54 | const std::string http_message::COOKIE_NAME_VALUE_DELIMITER("="); 55 | 56 | // common HTTP header names 57 | const std::string http_message::HEADER_HOST("Host"); 58 | const std::string http_message::HEADER_COOKIE("Cookie"); 59 | const std::string http_message::HEADER_SET_COOKIE("Set-Cookie"); 60 | const std::string http_message::HEADER_CONNECTION("Connection"); 61 | const std::string http_message::HEADER_CONTENT_TYPE("Content-Type"); 62 | const std::string http_message::HEADER_CONTENT_LENGTH("Content-Length"); 63 | const std::string http_message::HEADER_CONTENT_LOCATION("Content-Location"); 64 | const std::string http_message::HEADER_CONTENT_ENCODING("Content-Encoding"); 65 | const std::string http_message::HEADER_CONTENT_DISPOSITION("Content-Disposition"); 66 | const std::string http_message::HEADER_LAST_MODIFIED("Last-Modified"); 67 | const std::string http_message::HEADER_IF_MODIFIED_SINCE("If-Modified-Since"); 68 | const std::string http_message::HEADER_TRANSFER_ENCODING("Transfer-Encoding"); 69 | const std::string http_message::HEADER_LOCATION("Location"); 70 | const std::string http_message::HEADER_AUTHORIZATION("Authorization"); 71 | const std::string http_message::HEADER_REFERER("Referer"); 72 | const std::string http_message::HEADER_USER_AGENT("User-Agent"); 73 | const std::string http_message::HEADER_X_FORWARDED_FOR("X-Forwarded-For"); 74 | const std::string http_message::HEADER_CLIENT_IP("Client-IP"); 75 | 76 | // common HTTP content types 77 | const std::string http_message::CONTENT_TYPE_HTML("text/html"); 78 | const std::string http_message::CONTENT_TYPE_TEXT("text/plain"); 79 | const std::string http_message::CONTENT_TYPE_XML("text/xml"); 80 | const std::string http_message::CONTENT_TYPE_URLENCODED("application/x-www-form-urlencoded"); 81 | const std::string http_message::CONTENT_TYPE_MULTIPART_FORM_DATA("multipart/form-data"); 82 | 83 | // common HTTP request methods 84 | const std::string http_message::REQUEST_METHOD_HEAD("HEAD"); 85 | const std::string http_message::REQUEST_METHOD_GET("GET"); 86 | const std::string http_message::REQUEST_METHOD_PUT("PUT"); 87 | const std::string http_message::REQUEST_METHOD_POST("POST"); 88 | const std::string http_message::REQUEST_METHOD_DELETE("DELETE"); 89 | const std::string http_message::REQUEST_METHOD_OPTIONS("OPTIONS"); 90 | 91 | // common HTTP response messages 92 | const std::string http_message::RESPONSE_MESSAGE_OK("OK"); 93 | const std::string http_message::RESPONSE_MESSAGE_CREATED("Created"); 94 | const std::string http_message::RESPONSE_MESSAGE_ACCEPTED("Accepted"); 95 | const std::string http_message::RESPONSE_MESSAGE_NO_CONTENT("No Content"); 96 | const std::string http_message::RESPONSE_MESSAGE_FOUND("Found"); 97 | const std::string http_message::RESPONSE_MESSAGE_UNAUTHORIZED("Unauthorized"); 98 | const std::string http_message::RESPONSE_MESSAGE_FORBIDDEN("Forbidden"); 99 | const std::string http_message::RESPONSE_MESSAGE_NOT_FOUND("Not Found"); 100 | const std::string http_message::RESPONSE_MESSAGE_METHOD_NOT_ALLOWED("Method Not Allowed"); 101 | const std::string http_message::RESPONSE_MESSAGE_NOT_MODIFIED("Not Modified"); 102 | const std::string http_message::RESPONSE_MESSAGE_BAD_REQUEST("Bad Request"); 103 | const std::string http_message::RESPONSE_MESSAGE_SERVER_ERROR("Server Error"); 104 | const std::string http_message::RESPONSE_MESSAGE_NOT_IMPLEMENTED("Not Implemented"); 105 | const std::string http_message::RESPONSE_MESSAGE_CONTINUE("Continue"); 106 | 107 | // common HTTP response codes 108 | const unsigned int http_message::RESPONSE_CODE_OK = 200; 109 | const unsigned int http_message::RESPONSE_CODE_CREATED = 201; 110 | const unsigned int http_message::RESPONSE_CODE_ACCEPTED = 202; 111 | const unsigned int http_message::RESPONSE_CODE_NO_CONTENT = 204; 112 | const unsigned int http_message::RESPONSE_CODE_FOUND = 302; 113 | const unsigned int http_message::RESPONSE_CODE_UNAUTHORIZED = 401; 114 | const unsigned int http_message::RESPONSE_CODE_FORBIDDEN = 403; 115 | const unsigned int http_message::RESPONSE_CODE_NOT_FOUND = 404; 116 | const unsigned int http_message::RESPONSE_CODE_METHOD_NOT_ALLOWED = 405; 117 | const unsigned int http_message::RESPONSE_CODE_NOT_MODIFIED = 304; 118 | const unsigned int http_message::RESPONSE_CODE_BAD_REQUEST = 400; 119 | const unsigned int http_message::RESPONSE_CODE_SERVER_ERROR = 500; 120 | const unsigned int http_message::RESPONSE_CODE_NOT_IMPLEMENTED = 501; 121 | const unsigned int http_message::RESPONSE_CODE_CONTINUE = 100; 122 | 123 | // response to "Expect: 100-Continue" header 124 | // see https://groups.google.com/d/msg/mongoose-users/92fD1Elk5m4/Op6fPLZtlrEJ 125 | const std::string http_message::RESPONSE_FULLMESSAGE_100_CONTINUE("HTTP/1.1 100 Continue\r\n\r\n"); 126 | 127 | } // namespace 128 | } 129 | -------------------------------------------------------------------------------- /src/http_request_reader.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "staticlib/pion/http_request_reader.hpp" 18 | 19 | #include "asio.hpp" 20 | 21 | #include "staticlib/pion/http_server.hpp" 22 | 23 | namespace staticlib { 24 | namespace pion { 25 | 26 | namespace { // anonymous 27 | 28 | const std::string log = "staticlib.pion.http_request_reader"; 29 | 30 | } // namespace 31 | 32 | // reader member functions 33 | 34 | void http_request_reader::receive(std::unique_ptr self) { 35 | if (self->tcp_conn->is_pipelined()) { 36 | // there are pipelined messages available in the connection's read buffer 37 | self->tcp_conn->set_lifecycle(tcp_connection::lifecycle::close); // default to close the connection 38 | self->tcp_conn->load_read_pos(self->m_read_ptr, self->m_read_end_ptr); 39 | consume_bytes(std::move(self)); 40 | } else { 41 | // no pipelined messages available in the read buffer -> read bytes from the socket 42 | self->tcp_conn->set_lifecycle(tcp_connection::lifecycle::close); // default to close the connection 43 | read_bytes_with_timeout(std::move(self)); 44 | } 45 | } 46 | 47 | void http_request_reader::consume_bytes(std::unique_ptr self, 48 | const std::error_code& read_error, std::size_t bytes_read) { 49 | if (read_error) { 50 | // a read error occured 51 | self->handle_read_error(read_error); 52 | return; 53 | } 54 | 55 | STATICLIB_PION_LOG_DEBUG(log, "Read " << bytes_read << " bytes from HTTP request"); 56 | 57 | // set pointers for new HTTP header data to be consumed 58 | self->set_read_buffer(self->tcp_conn->get_read_buffer().data(), bytes_read); 59 | 60 | consume_bytes(std::move(self)); 61 | } 62 | 63 | void http_request_reader::consume_bytes(std::unique_ptr self) { 64 | // parse the bytes read from the last operation 65 | // 66 | // note that tribool may have one of THREE states: 67 | // 68 | // false: encountered an error while parsing message 69 | // true: finished successfully parsing the message 70 | // indeterminate: parsed bytes, but the message is not yet finished 71 | // 72 | std::error_code ec; 73 | sl::support::tribool result = self->parse(*self->request, ec); 74 | 75 | if (self->gcount() > 0) { 76 | // parsed > 0 bytes in HTTP headers 77 | STATICLIB_PION_LOG_DEBUG(log, "Parsed " << self->gcount() << " HTTP bytes"); 78 | } 79 | 80 | if (result == true) { 81 | // finished reading HTTP message and it is valid 82 | 83 | // set the connection's lifecycle type 84 | if (self->request->check_keep_alive()) { 85 | if (self->eof()) { 86 | // the connection should be kept alive, but does not have pipelined messages 87 | self->tcp_conn->set_lifecycle(tcp_connection::lifecycle::keepalive); 88 | } else { 89 | // the connection has pipelined messages 90 | self->tcp_conn->set_lifecycle(tcp_connection::lifecycle::pipelined); 91 | 92 | // save the read position as a bookmark so that it can be retrieved 93 | // by a new HTTP parser, which will be created after the current 94 | // message has been handled 95 | self->tcp_conn->save_read_pos(self->m_read_ptr, self->m_read_end_ptr); 96 | 97 | STATICLIB_PION_LOG_DEBUG(log, "HTTP pipelined request(" 98 | << self->bytes_available() << " bytes available)"); 99 | } 100 | } else { 101 | self->tcp_conn->set_lifecycle(tcp_connection::lifecycle::close); 102 | } 103 | 104 | // we have finished parsing the HTTP message 105 | self->finished_reading(ec); 106 | 107 | } else if (result == false) { 108 | // the message is invalid or an error occured 109 | self->tcp_conn->set_lifecycle(tcp_connection::lifecycle::close); // make sure it will get closed 110 | self->request->set_is_valid(false); 111 | self->finished_reading(ec); 112 | } else { 113 | // not yet finished parsing the message -> read more data 114 | read_bytes_with_timeout(std::move(self)); 115 | } 116 | } 117 | 118 | void http_request_reader::read_bytes_with_timeout(std::unique_ptr self) { 119 | // setup timer 120 | auto& timer = self->tcp_conn->get_timer(); 121 | auto& strand = self->tcp_conn->get_strand(); 122 | timer.expires_from_now(std::chrono::milliseconds(self->read_timeout_millis)); 123 | auto conn = self->tcp_conn; 124 | auto timeout_handler = 125 | [conn] (const std::error_code& ec) { 126 | if (asio::error::operation_aborted != ec.value()) { 127 | conn->cancel(); 128 | } 129 | }; 130 | auto timeout_handler_stranded = strand.wrap(std::move(timeout_handler)); 131 | // setup read 132 | auto self_shared = sl::support::make_shared_with_release_deleter(self.release()); 133 | auto read_handler = 134 | [self_shared](const std::error_code& ec, std::size_t bytes_read) { 135 | auto self = sl::support::make_unique_from_shared_with_release_deleter(self_shared); 136 | if (nullptr != self.get()) { 137 | if(asio::error::operation_aborted != ec.value()) { 138 | self->tcp_conn->cancel_timer(); 139 | } 140 | consume_bytes(std::move(self), ec, bytes_read); 141 | } else { 142 | STATICLIB_PION_LOG_WARN(log, "Lost context detected in 'async_read_some'"); 143 | } 144 | }; 145 | auto read_handler_standed = strand.wrap(std::move(read_handler)); 146 | // fire 147 | conn->async_read_some(std::move(read_handler_standed)); 148 | timer.async_wait(std::move(timeout_handler_stranded)); 149 | } 150 | 151 | void http_request_reader::handle_read_error(const std::error_code& read_error) { 152 | // close the connection, forcing the client to establish a new one 153 | tcp_conn->set_lifecycle(tcp_connection::lifecycle::close); // make sure it will get closed 154 | 155 | // check if this is just a message with unknown content length 156 | if (!check_premature_eof(*request)) { 157 | std::error_code ec; // clear error code 158 | finished_reading(ec); 159 | return; 160 | } 161 | 162 | // only log errors if the parsing has already begun 163 | if (get_total_bytes_read() > 0) { 164 | if (read_error == asio::error::operation_aborted) { 165 | // if the operation was aborted, the acceptor was stopped, 166 | // which means another thread is shutting-down the server 167 | STATICLIB_PION_LOG_INFO(log, "HTTP request parsing aborted (shutting down)"); 168 | } else { 169 | STATICLIB_PION_LOG_INFO(log, "HTTP request parsing aborted (" << read_error.message() << ')'); 170 | } 171 | } 172 | 173 | finished_reading(read_error); 174 | } 175 | 176 | void http_request_reader::finished_parsing_headers(const std::error_code& ec, sl::support::tribool& rc) { 177 | server.handle_request_after_headers_parsed(request, tcp_conn, ec, rc); 178 | } 179 | 180 | void http_request_reader::finished_reading(const std::error_code& ec) { 181 | server.handle_request(std::move(request), tcp_conn, ec); 182 | } 183 | 184 | } // namespace 185 | } 186 | -------------------------------------------------------------------------------- /src/scheduler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // --------------------------------------------------------------------- 18 | // pion: a Boost C++ framework for building lightweight HTTP interfaces 19 | // --------------------------------------------------------------------- 20 | // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion) 21 | // 22 | // Distributed under the Boost Software License, Version 1.0. 23 | // See http://www.boost.org/LICENSE_1_0.txt 24 | // 25 | 26 | #include "staticlib/pion/scheduler.hpp" 27 | 28 | #include "staticlib/pion/logger.hpp" 29 | 30 | namespace staticlib { 31 | namespace pion { 32 | 33 | namespace { // anonymous 34 | 35 | const std::string log = "staticlib.pion.scheduler"; 36 | 37 | } // namespace 38 | 39 | // members of scheduler 40 | 41 | void scheduler::startup() { 42 | // lock mutex for thread safety 43 | std::lock_guard scheduler_lock(mutex); 44 | 45 | if (!running) { 46 | STATICLIB_PION_LOG_INFO(log, "Starting thread scheduler"); 47 | running = true; 48 | 49 | // schedule a work item to make sure that the service doesn't complete 50 | asio_service.reset(); 51 | keep_running(asio_service, timer); 52 | 53 | // start multiple threads to handle async tasks 54 | for (uint32_t n = 0; n < num_threads; ++n) { 55 | std::unique_ptr new_thread(new std::thread([this]() { 56 | this->process_service_work(this->asio_service); 57 | this->thread_stop_hook(); 58 | })); 59 | thread_pool.emplace_back(std::move(new_thread)); 60 | } 61 | } 62 | } 63 | 64 | void scheduler::shutdown(void) { 65 | // lock mutex for thread safety 66 | std::unique_lock scheduler_lock{mutex}; 67 | 68 | if (running) { 69 | 70 | STATICLIB_PION_LOG_INFO(log, "Shutting down the thread scheduler"); 71 | 72 | while (active_users > 0) { 73 | // first, wait for any active users to exit 74 | STATICLIB_PION_LOG_INFO(log, "Waiting for " << active_users << " scheduler users to finish"); 75 | no_more_active_users.wait(scheduler_lock); 76 | } 77 | 78 | // shut everything down 79 | running = false; 80 | asio_service.stop(); 81 | stop_threads(); 82 | asio_service.reset(); 83 | thread_pool.clear(); 84 | 85 | STATICLIB_PION_LOG_INFO(log, "The thread scheduler has shutdown"); 86 | 87 | // Make sure anyone waiting on shutdown gets notified 88 | scheduler_has_stopped.notify_all(); 89 | 90 | } else { 91 | 92 | // stop and finish everything to be certain that no events are pending 93 | asio_service.stop(); 94 | stop_threads(); 95 | asio_service.reset(); 96 | thread_pool.clear(); 97 | 98 | // Make sure anyone waiting on shutdown gets notified 99 | // even if the scheduler did not startup successfully 100 | scheduler_has_stopped.notify_all(); 101 | } 102 | } 103 | 104 | void scheduler::join(void) { 105 | std::unique_lock scheduler_lock(mutex); 106 | while (running) { 107 | // sleep until scheduler_has_stopped condition is signaled 108 | scheduler_has_stopped.wait(scheduler_lock); 109 | } 110 | } 111 | 112 | void scheduler::keep_running(asio::io_service& my_service, asio::steady_timer& my_timer) { 113 | if (running) { 114 | // schedule this again to make sure the service doesn't complete 115 | my_timer.expires_from_now(std::chrono::seconds(5)); 116 | auto cb = [this, &my_service, &my_timer](const std::error_code&){ 117 | this->keep_running(my_service, my_timer); 118 | }; 119 | my_timer.async_wait(std::move(cb)); 120 | } 121 | } 122 | 123 | void scheduler::add_active_user() { 124 | if (!running) startup(); 125 | std::lock_guard scheduler_lock(mutex); 126 | ++active_users; 127 | } 128 | 129 | void scheduler::remove_active_user() { 130 | std::lock_guard scheduler_lock(mutex); 131 | if (--active_users == 0) { 132 | no_more_active_users.notify_all(); 133 | } 134 | } 135 | 136 | void scheduler::process_service_work(asio::io_service& service) { 137 | while (running) { 138 | try { 139 | service.run(); 140 | } catch (std::exception& e) { 141 | (void) e; 142 | STATICLIB_PION_LOG_ERROR(log, e.what()); 143 | } catch (...) { 144 | STATICLIB_PION_LOG_ERROR(log, "caught unrecognized exception"); 145 | } 146 | } 147 | } 148 | 149 | void scheduler::stop_threads() { 150 | if (!thread_pool.empty()) { 151 | STATICLIB_PION_LOG_DEBUG(log, "Waiting for threads to shutdown"); 152 | 153 | // wait until all threads in the pool have stopped 154 | auto current_id = std::this_thread::get_id(); 155 | for (auto& th_ptr : thread_pool) { 156 | // make sure we do not call join() for the current thread, 157 | // since this may yield "undefined behavior" 158 | std::thread::id tid = th_ptr->get_id(); 159 | if (tid != current_id) { 160 | th_ptr->join(); 161 | } 162 | } 163 | } 164 | } 165 | 166 | } // namespace 167 | } 168 | -------------------------------------------------------------------------------- /src/tcp_server.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // --------------------------------------------------------------------- 18 | // pion: a Boost C++ framework for building lightweight HTTP interfaces 19 | // --------------------------------------------------------------------- 20 | // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion) 21 | // 22 | // Distributed under the Boost Software License, Version 1.0. 23 | // See http://www.boost.org/LICENSE_1_0.txt 24 | // 25 | 26 | #include "staticlib/pion/tcp_server.hpp" 27 | 28 | #include 29 | #include 30 | 31 | #include "asio.hpp" 32 | 33 | #include "staticlib/pion/logger.hpp" 34 | #include "staticlib/pion/scheduler.hpp" 35 | #include "staticlib/pion/tcp_connection.hpp" 36 | 37 | namespace staticlib { 38 | namespace pion { 39 | 40 | namespace { // anonymous 41 | 42 | const std::string log = "staticlib.pion.tcp_server"; 43 | 44 | } // namespace 45 | 46 | // tcp::server member functions 47 | 48 | void tcp_server::start() { 49 | // lock mutex for thread safety 50 | std::unique_lock server_lock(mutex); 51 | 52 | if (! listening) { 53 | STATICLIB_PION_LOG_INFO(log, "Starting server on port " << tcp_endpoint.port()); 54 | 55 | // before_starting(); 56 | 57 | // configure the acceptor service 58 | try { 59 | // get admin permissions in case we're binding to a privileged port 60 | // admin_rights use_admin_rights(m_endpoint.port() > 0 && m_endpoint.port() < 1024); 61 | tcp_acceptor.open(tcp_endpoint.protocol()); 62 | // allow the acceptor to reuse the address (i.e. SO_REUSEADDR) 63 | // ...except when running not on Windows - see http://msdn.microsoft.com/en-us/library/ms740621%28VS.85%29.aspx 64 | #ifndef _MSC_VER 65 | tcp_acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true)); 66 | #endif 67 | tcp_acceptor.bind(tcp_endpoint); 68 | if (tcp_endpoint.port() == 0) { 69 | // update the endpoint to reflect the port chosen by bind 70 | tcp_endpoint = tcp_acceptor.local_endpoint(); 71 | } 72 | tcp_acceptor.listen(); 73 | } catch (std::exception& e) { 74 | (void) e; 75 | STATICLIB_PION_LOG_ERROR(log, "Unable to bind to port " << tcp_endpoint.port() << ": " << e.what()); 76 | throw; 77 | } 78 | 79 | listening = true; 80 | 81 | // unlock the mutex since listen() requires its own lock 82 | server_lock.unlock(); 83 | listen(); 84 | 85 | // notify the thread scheduler that we need it now 86 | active_scheduler.add_active_user(); 87 | } 88 | } 89 | 90 | void tcp_server::stop(bool wait_until_finished) { 91 | // lock mutex for thread safety 92 | std::unique_lock server_lock(mutex); 93 | 94 | if (listening) { 95 | STATICLIB_PION_LOG_INFO(log, "Shutting down server on port " << tcp_endpoint.port()); 96 | 97 | listening = false; 98 | 99 | // this terminates any connections waiting to be accepted 100 | tcp_acceptor.close(); 101 | 102 | if (! wait_until_finished) { 103 | // this terminates any other open connections 104 | for (tcp_connection_ptr conn : conn_pool) { 105 | conn->close(); 106 | } 107 | } 108 | 109 | // wait for all pending connections to complete 110 | while (!conn_pool.empty()) { 111 | // try to prun connections that didn't finish cleanly 112 | if (prune_connections() == 0) { 113 | break; // if no more left, then we can stop waiting 114 | } 115 | // sleep for up to a quarter second to give open connections a chance to finish 116 | STATICLIB_PION_LOG_INFO(log, "Waiting for open connections to finish"); 117 | no_more_connections.wait_for(server_lock, std::chrono::milliseconds(250)); 118 | } 119 | 120 | // notify the thread scheduler that we no longer need it 121 | active_scheduler.remove_active_user(); 122 | 123 | // all done! 124 | // after_stopping(); 125 | server_has_stopped.notify_all(); 126 | } 127 | } 128 | 129 | void tcp_server::listen() { 130 | // lock mutex for thread safety 131 | std::lock_guard server_lock(mutex); 132 | 133 | if (listening) { 134 | // create a new TCP connection object 135 | tcp_connection::connection_handler fc = [this](std::shared_ptr& conn) { 136 | this->finish_connection(conn); 137 | }; 138 | auto new_connection = std::make_shared( 139 | get_io_service(), ssl_context, ssl_flag, std::move(fc)); 140 | 141 | // prune connections that finished uncleanly 142 | prune_connections(); 143 | 144 | // keep track of the object in the server's connection pool 145 | conn_pool.insert(new_connection); 146 | 147 | // use the object to accept a new connection 148 | auto cb = [this, new_connection](const std::error_code& ec) mutable { 149 | this->handle_accept(new_connection, ec); 150 | }; 151 | new_connection->async_accept(tcp_acceptor, std::move(cb)); 152 | } 153 | } 154 | 155 | void tcp_server::handle_accept(tcp_connection_ptr& tcp_conn, const std::error_code& accept_error) { 156 | if (accept_error) { 157 | // an error occured while trying to a accept a new connection 158 | // this happens when the server is being shut down 159 | if (listening) { 160 | listen(); // schedule acceptance of another connection 161 | STATICLIB_PION_LOG_WARN(log, "Accept error on port " << tcp_endpoint.port() << ": " << accept_error.message()); 162 | } 163 | finish_connection(tcp_conn); 164 | } else { 165 | // got a new TCP connection 166 | STATICLIB_PION_LOG_DEBUG(log, "New" << (tcp_conn->get_ssl_flag() ? " SSL " : " ") 167 | << "connection on port " << tcp_endpoint.port()); 168 | 169 | // schedule the acceptance of another new connection 170 | // (this returns immediately since it schedules it as an event) 171 | if (listening) { 172 | listen(); 173 | } 174 | 175 | // handle the new connection 176 | if (tcp_conn->get_ssl_flag()) { 177 | auto cb = [this, tcp_conn](const std::error_code & ec) mutable { 178 | this->handle_ssl_handshake(tcp_conn, ec); 179 | }; 180 | tcp_conn->async_handshake_server(std::move(cb)); 181 | } else { 182 | // not SSL -> call the handler immediately 183 | handle_connection(tcp_conn); 184 | } 185 | } 186 | } 187 | 188 | void tcp_server::handle_ssl_handshake(tcp_connection_ptr& tcp_conn, 189 | const std::error_code& handshake_error) { 190 | if (handshake_error) { 191 | // an error occured while trying to establish the SSL connection 192 | STATICLIB_PION_LOG_WARN(log, "SSL handshake failed on port " << tcp_endpoint.port() 193 | << " (" << handshake_error.message() << ')'); 194 | finish_connection(tcp_conn); 195 | } else { 196 | // handle the new connection 197 | STATICLIB_PION_LOG_DEBUG(log, "SSL handshake succeeded on port " << tcp_endpoint.port()); 198 | handle_connection(tcp_conn); 199 | } 200 | } 201 | 202 | void tcp_server::finish_connection(tcp_connection_ptr& tcp_conn) { 203 | std::lock_guard server_lock(mutex); 204 | if (listening && tcp_conn->get_keep_alive()) { 205 | 206 | // keep the connection alive 207 | handle_connection(tcp_conn); 208 | 209 | } else { 210 | STATICLIB_PION_LOG_DEBUG(log, "Closing connection on port " << tcp_endpoint.port()); 211 | 212 | // remove the connection from the server's management pool 213 | std::set::iterator conn_itr = conn_pool.find(tcp_conn); 214 | if (conn_itr != conn_pool.end()) { 215 | conn_pool.erase(conn_itr); 216 | } 217 | 218 | // trigger the no more connections condition if we're waiting to stop 219 | if (!listening && conn_pool.empty()) { 220 | no_more_connections.notify_all(); 221 | } 222 | } 223 | } 224 | 225 | std::size_t tcp_server::prune_connections() { 226 | // assumes that a server lock has already been acquired 227 | std::set::iterator conn_itr = conn_pool.begin(); 228 | while (conn_itr != conn_pool.end()) { 229 | if (conn_itr->unique()) { 230 | STATICLIB_PION_LOG_WARN(log, "Closing orphaned connection on port " << tcp_endpoint.port()); 231 | std::set::iterator erase_itr = conn_itr; 232 | ++conn_itr; 233 | (*erase_itr)->close(); 234 | conn_pool.erase(erase_itr); 235 | } else { 236 | ++conn_itr; 237 | } 238 | } 239 | 240 | // return the number of connections remaining 241 | return conn_pool.size(); 242 | } 243 | 244 | } // namespace 245 | } 246 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2015, alex at staticlibs.net 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | cmake_minimum_required ( VERSION 2.8.12 ) 16 | 17 | # toolchain setup 18 | set ( STATICLIB_TOOLCHAIN linux_amd64_gcc CACHE STRING "toolchain triplet" ) 19 | if ( NOT DEFINED STATICLIB_CMAKE ) 20 | set ( STATICLIB_CMAKE ${CMAKE_CURRENT_LIST_DIR}/../../cmake CACHE INTERNAL "" ) 21 | endif ( ) 22 | set ( CMAKE_TOOLCHAIN_FILE ${STATICLIB_CMAKE}/toolchains/${STATICLIB_TOOLCHAIN}.cmake CACHE INTERNAL "" ) 23 | 24 | # project 25 | project ( staticlib_pion_test CXX ) 26 | include ( ${STATICLIB_CMAKE}/staticlibs_common.cmake ) 27 | 28 | # dependencies 29 | if ( NOT DEFINED STATICLIB_DEPS ) 30 | set ( STATICLIB_DEPS ${CMAKE_CURRENT_LIST_DIR}/../../ CACHE INTERNAL "" ) 31 | endif ( ) 32 | if ( NOT STATICLIB_TOOLCHAIN MATCHES "linux_[^_]+_[^_]+" ) 33 | staticlib_add_subdirectory ( ${STATICLIB_DEPS}/external_asio ) 34 | staticlib_add_subdirectory ( ${STATICLIB_DEPS}/external_openssl ) 35 | else ( ) 36 | configure_file ( ${CMAKE_CURRENT_LIST_DIR}/asio.pc 37 | ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/pkgconfig/asio.pc 38 | COPYONLY ) 39 | endif ( ) 40 | staticlib_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../../staticlib_config ) 41 | staticlib_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../../staticlib_support ) 42 | staticlib_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../../staticlib_io ) 43 | staticlib_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../../staticlib_endian ) 44 | staticlib_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../../staticlib_utils ) 45 | staticlib_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../../staticlib_crypto ) 46 | staticlib_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../../staticlib_websocket ) 47 | staticlib_add_subdirectory ( ${CMAKE_CURRENT_LIST_DIR}/../../staticlib_pion ) 48 | set ( ${PROJECT_NAME}_DEPS staticlib_pion ) 49 | staticlib_pkg_check_modules ( ${PROJECT_NAME}_DEPS_PC REQUIRED ${PROJECT_NAME}_DEPS ) 50 | 51 | # tests 52 | set ( ${PROJECT_NAME}_TEST_INCLUDES ${${PROJECT_NAME}_DEPS_PC_INCLUDE_DIRS} ) 53 | set ( ${PROJECT_NAME}_TEST_LIBS ${${PROJECT_NAME}_DEPS_PC_STATIC_LIBRARIES} ) 54 | set ( ${PROJECT_NAME}_TEST_OPTS ${${PROJECT_NAME}_DEPS_PC_CFLAGS_OTHER} ) 55 | if ( ${CMAKE_CXX_COMPILER_ID} MATCHES "(Clang|GNU)" ) 56 | list ( APPEND ${PROJECT_NAME}_TEST_OPTS -Wno-deprecated-declarations ) 57 | endif ( ) 58 | staticlib_enable_testing ( ${PROJECT_NAME}_TEST_INCLUDES ${PROJECT_NAME}_TEST_LIBS ${PROJECT_NAME}_TEST_OPTS ) 59 | -------------------------------------------------------------------------------- /test/asio.pc: -------------------------------------------------------------------------------- 1 | # Copyright 2017, alex at staticlibs.net 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | Name: asio 16 | Version: 11.10.8 17 | Description:C++ library for network programming 18 | Requires: 19 | Libs: 20 | Libs.private: 21 | Cflags: -DASIO_STANDALONE -DASIO_HAS_STD_CHRONO -DASIO_HAS_STD_SYSTEM_ERROR 22 | -------------------------------------------------------------------------------- /test/certificates/client/staticlibs_test_ca.cer: -------------------------------------------------------------------------------- 1 | Certificate: 2 | Data: 3 | Version: 3 (0x2) 4 | Serial Number: 12065728203692723648 (0xa77213dfd1844dc0) 5 | Signature Algorithm: sha1WithRSAEncryption 6 | Issuer: C=IE, ST=Dublin, O=staticlibs.net, OU=Development, CN=staticlibs_test_ca/emailAddress=alex@staticlibs.net 7 | Validity 8 | Not Before: Jul 12 11:25:08 2015 GMT 9 | Not After : Jul 9 11:25:08 2025 GMT 10 | Subject: C=IE, ST=Dublin, O=staticlibs.net, OU=Development, CN=staticlibs_test_ca/emailAddress=alex@staticlibs.net 11 | Subject Public Key Info: 12 | Public Key Algorithm: rsaEncryption 13 | Public-Key: (2048 bit) 14 | Modulus: 15 | 00:d8:38:ce:d0:ed:9c:dc:6f:65:6f:8e:0f:a4:85: 16 | a9:08:3d:53:49:7d:65:af:04:a6:dd:02:9f:7d:89: 17 | 44:30:1a:72:1d:2f:26:d5:77:2d:2e:f8:e8:cd:6f: 18 | d9:dd:a7:93:b5:b6:8f:c2:a3:4b:cf:99:94:d8:e6: 19 | 98:db:21:6d:f3:6c:e4:7d:a2:15:4d:46:0a:c8:24: 20 | 40:a3:c1:8e:09:2f:7f:b1:1d:13:a7:8b:71:4f:23: 21 | c4:a2:a5:4c:2e:22:9c:3e:d6:4a:a5:3f:40:1b:81: 22 | e5:e8:3a:7c:a8:35:fb:24:ff:f8:3c:80:4a:2a:22: 23 | 91:d9:8b:80:49:be:be:a9:ec:ac:95:14:6b:c3:c5: 24 | bf:a2:57:11:83:a5:40:0c:2f:4d:d4:ee:16:12:7d: 25 | 66:30:88:81:77:15:2d:3e:75:7e:bf:c5:da:a2:9e: 26 | 49:92:33:ed:eb:ee:db:45:34:61:77:fc:72:f1:08: 27 | 67:57:a4:86:bc:2e:89:b2:56:a6:de:dc:cd:b3:c8: 28 | 93:73:a5:ab:1d:e8:99:55:14:62:2e:f5:9f:51:c6: 29 | 9e:eb:0b:ae:c6:68:e2:8d:3f:8b:16:b4:d0:48:96: 30 | d0:b4:bf:15:1e:27:89:71:86:5c:d4:0c:f1:0b:8e: 31 | 56:81:e8:35:72:29:67:ff:83:d2:2f:51:fb:3d:29: 32 | 43:df 33 | Exponent: 65537 (0x10001) 34 | X509v3 extensions: 35 | X509v3 Subject Key Identifier: 36 | 4E:48:42:4C:50:2C:55:E4:0A:C0:59:2C:E8:5F:62:A3:EC:18:BA:DE 37 | X509v3 Authority Key Identifier: 38 | keyid:4E:48:42:4C:50:2C:55:E4:0A:C0:59:2C:E8:5F:62:A3:EC:18:BA:DE 39 | 40 | X509v3 Basic Constraints: 41 | CA:TRUE 42 | Signature Algorithm: sha1WithRSAEncryption 43 | b3:99:d8:ef:4d:4d:fd:5b:64:aa:7a:c1:f5:97:a7:29:6a:8d: 44 | 73:59:49:c2:e2:3f:6c:4e:da:e7:4e:10:26:1a:88:8a:70:87: 45 | f4:7c:e1:10:e7:db:25:8a:15:78:ba:8b:f2:a3:c0:9b:90:9d: 46 | 03:ec:36:11:10:a7:61:92:1b:91:6f:f8:a5:a4:ff:e6:1c:05: 47 | ec:a0:07:e3:b7:ce:d1:9a:81:5b:6b:1f:59:c1:98:be:67:ee: 48 | ab:fb:ee:46:cb:12:ce:78:3e:0e:75:01:e8:79:2e:37:c2:dc: 49 | 93:fc:61:ab:f5:d9:0c:ff:1a:98:3a:17:6a:7e:e6:60:66:53: 50 | cd:3d:ca:9d:2f:6e:08:75:c1:af:59:bd:e4:68:81:c4:73:53: 51 | fd:ad:bf:88:30:d5:25:b1:00:e9:2d:ee:b6:8b:f3:ae:d0:91: 52 | 20:81:89:3d:b5:ff:cb:62:79:32:7f:42:25:39:77:b0:b9:60: 53 | d5:e7:79:aa:cf:e4:9e:47:97:a9:ab:86:e3:fc:c2:74:fc:42: 54 | ba:14:51:11:8e:80:2f:c4:b6:5d:30:b8:9f:34:b9:4f:d2:e5: 55 | 71:1e:50:4f:4d:22:46:07:44:83:c8:3f:86:24:f6:88:c6:58: 56 | 97:8e:06:0c:ab:96:90:bf:71:40:04:07:78:fe:53:93:5f:c1: 57 | 52:09:48:f8 58 | -----BEGIN CERTIFICATE----- 59 | MIID8TCCAtmgAwIBAgIJAKdyE9/RhE3AMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYD 60 | VQQGEwJJRTEPMA0GA1UECAwGRHVibGluMRcwFQYDVQQKDA5zdGF0aWNsaWJzLm5l 61 | dDEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxGzAZBgNVBAMMEnN0YXRpY2xpYnNfdGVz 62 | dF9jYTEiMCAGCSqGSIb3DQEJARYTYWxleEBzdGF0aWNsaWJzLm5ldDAeFw0xNTA3 63 | MTIxMTI1MDhaFw0yNTA3MDkxMTI1MDhaMIGOMQswCQYDVQQGEwJJRTEPMA0GA1UE 64 | CAwGRHVibGluMRcwFQYDVQQKDA5zdGF0aWNsaWJzLm5ldDEUMBIGA1UECwwLRGV2 65 | ZWxvcG1lbnQxGzAZBgNVBAMMEnN0YXRpY2xpYnNfdGVzdF9jYTEiMCAGCSqGSIb3 66 | DQEJARYTYWxleEBzdGF0aWNsaWJzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEP 67 | ADCCAQoCggEBANg4ztDtnNxvZW+OD6SFqQg9U0l9Za8Ept0Cn32JRDAach0vJtV3 68 | LS746M1v2d2nk7W2j8KjS8+ZlNjmmNshbfNs5H2iFU1GCsgkQKPBjgkvf7EdE6eL 69 | cU8jxKKlTC4inD7WSqU/QBuB5eg6fKg1+yT/+DyASioikdmLgEm+vqnsrJUUa8PF 70 | v6JXEYOlQAwvTdTuFhJ9ZjCIgXcVLT51fr/F2qKeSZIz7evu20U0YXf8cvEIZ1ek 71 | hrwuibJWpt7czbPIk3Olqx3omVUUYi71n1HGnusLrsZo4o0/ixa00EiW0LS/FR4n 72 | iXGGXNQM8QuOVoHoNXIpZ/+D0i9R+z0pQ98CAwEAAaNQME4wHQYDVR0OBBYEFE5I 73 | QkxQLFXkCsBZLOhfYqPsGLreMB8GA1UdIwQYMBaAFE5IQkxQLFXkCsBZLOhfYqPs 74 | GLreMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBALOZ2O9NTf1bZKp6 75 | wfWXpylqjXNZScLiP2xO2udOECYaiIpwh/R84RDn2yWKFXi6i/KjwJuQnQPsNhEQ 76 | p2GSG5Fv+KWk/+YcBeygB+O3ztGagVtrH1nBmL5n7qv77kbLEs54Pg51Aeh5LjfC 77 | 3JP8Yav12Qz/Gpg6F2p+5mBmU809yp0vbgh1wa9ZveRogcRzU/2tv4gw1SWxAOkt 78 | 7raL867QkSCBiT21/8tieTJ/QiU5d7C5YNXnearP5J5Hl6mrhuP8wnT8QroUURGO 79 | gC/Etl0wuJ80uU/S5XEeUE9NIkYHRIPIP4Yk9ojGWJeOBgyrlpC/cUAEB3j+U5Nf 80 | wVIJSPg= 81 | -----END CERTIFICATE----- 82 | -------------------------------------------------------------------------------- /test/certificates/client/staticlibs_test_ca.crt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticlibs/staticlib_pion/ce3633f7c2c0838b0fffea8d2edc65329986024c/test/certificates/client/staticlibs_test_ca.crt -------------------------------------------------------------------------------- /test/certificates/client/testclient.cer: -------------------------------------------------------------------------------- 1 | Certificate: 2 | Data: 3 | Version: 3 (0x2) 4 | Serial Number: 12065728203692723650 (0xa77213dfd1844dc2) 5 | Signature Algorithm: sha1WithRSAEncryption 6 | Issuer: C=IE, ST=Dublin, O=staticlibs.net, OU=Development, CN=staticlibs_test_ca/emailAddress=alex@staticlibs.net 7 | Validity 8 | Not Before: Jul 12 14:08:02 2015 GMT 9 | Not After : Jul 9 14:08:02 2025 GMT 10 | Subject: C=IE, ST=Dublin, L=Dublin, O=staticlibs.net, OU=Development, CN=testclient/emailAddress=alex@staticlibs.net 11 | Subject Public Key Info: 12 | Public Key Algorithm: rsaEncryption 13 | Public-Key: (2048 bit) 14 | Modulus: 15 | 00:c4:5c:8b:dd:cb:68:0f:92:1e:98:1d:6c:59:ff: 16 | be:95:e9:ed:f4:88:87:04:0c:99:c9:35:96:cf:5f: 17 | 7c:bd:0a:93:8e:8d:63:fa:4e:80:30:3f:0d:d1:35: 18 | 8b:53:e6:75:ff:d0:93:b4:4a:3b:93:8d:1c:03:9e: 19 | 3a:6f:b5:ab:89:fd:4a:4d:87:bf:14:08:f5:26:94: 20 | a5:3e:cd:78:b8:d6:cc:b7:86:73:5d:29:4b:03:9f: 21 | 85:85:b2:9f:81:ab:1c:3d:c8:11:fb:5a:dc:20:a0: 22 | 33:bf:d6:42:f6:64:72:3d:8f:75:e7:4b:b8:39:27: 23 | 72:a3:38:87:42:d8:79:72:be:51:41:2c:c5:d3:7f: 24 | 0f:dc:7f:59:81:a3:a9:62:4e:23:c3:1b:15:49:cb: 25 | 9c:69:13:be:0b:37:84:39:e5:99:e2:f6:60:66:6d: 26 | 95:8f:3d:d7:b6:79:aa:ad:c8:56:5d:79:09:8f:29: 27 | e9:df:7b:1e:aa:02:10:e0:51:47:98:71:b9:53:f3: 28 | c2:36:11:cd:21:7c:27:43:15:64:bf:fb:70:e8:20: 29 | 51:ad:29:4e:29:61:59:5f:18:ba:e6:93:52:7b:bb: 30 | a8:cf:41:cc:53:5d:d7:62:fa:dc:81:e7:31:8f:2c: 31 | 8d:52:24:1e:1f:20:4a:cc:e5:4d:1b:dc:0d:0b:3d: 32 | 99:4b 33 | Exponent: 65537 (0x10001) 34 | X509v3 extensions: 35 | X509v3 Basic Constraints: 36 | CA:FALSE 37 | Netscape Comment: 38 | OpenSSL Generated Certificate 39 | X509v3 Subject Key Identifier: 40 | 0A:F1:34:F1:73:C9:A4:C3:AD:CA:86:C4:B3:97:5D:16:A0:21:90:EB 41 | X509v3 Authority Key Identifier: 42 | keyid:4E:48:42:4C:50:2C:55:E4:0A:C0:59:2C:E8:5F:62:A3:EC:18:BA:DE 43 | 44 | Signature Algorithm: sha1WithRSAEncryption 45 | 52:77:6c:c3:9b:ba:46:76:a8:3d:6e:d9:49:2e:31:95:37:92: 46 | b1:3d:1c:9d:12:4d:bc:31:45:17:a0:14:b8:a8:f1:5e:88:45: 47 | 01:8e:60:14:0b:10:14:01:37:47:9c:5a:af:0e:64:dc:96:fd: 48 | 3b:6a:66:86:c5:bd:4a:a5:28:9a:58:72:82:05:12:63:3a:8b: 49 | b1:93:04:6b:6f:d4:a2:d2:20:af:dc:37:3b:ae:c9:d9:d7:c3: 50 | 71:6a:a8:66:3a:8b:9b:7a:6f:73:fd:81:7f:de:52:df:95:23: 51 | 8f:41:aa:0b:b5:9b:7b:93:18:18:5a:38:4a:1c:ac:81:4a:e3: 52 | 96:b6:24:35:a9:a2:31:46:ed:ed:86:e8:7d:76:00:94:83:d2: 53 | f1:8a:9e:e8:0c:b6:cf:ba:22:72:64:f4:36:6d:71:59:4b:38: 54 | cb:39:71:bf:d6:a8:47:b0:28:b4:ee:11:48:7e:9c:4b:5e:c9: 55 | 75:5a:89:e1:a2:9d:2d:cf:65:13:13:11:1d:4d:44:82:23:10: 56 | f0:8f:07:a9:da:3d:04:89:d3:97:36:98:54:0f:54:3c:c1:ab: 57 | 08:2a:76:bc:6e:02:bb:0a:9d:50:59:09:43:f4:83:77:a8:c9: 58 | 38:13:03:41:8d:7c:3a:85:27:c1:97:4d:94:81:d3:d0:6a:a4: 59 | 74:1a:9b:26 60 | -----BEGIN CERTIFICATE----- 61 | MIIEJTCCAw2gAwIBAgIJAKdyE9/RhE3CMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYD 62 | VQQGEwJJRTEPMA0GA1UECAwGRHVibGluMRcwFQYDVQQKDA5zdGF0aWNsaWJzLm5l 63 | dDEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxGzAZBgNVBAMMEnN0YXRpY2xpYnNfdGVz 64 | dF9jYTEiMCAGCSqGSIb3DQEJARYTYWxleEBzdGF0aWNsaWJzLm5ldDAeFw0xNTA3 65 | MTIxNDA4MDJaFw0yNTA3MDkxNDA4MDJaMIGXMQswCQYDVQQGEwJJRTEPMA0GA1UE 66 | CAwGRHVibGluMQ8wDQYDVQQHDAZEdWJsaW4xFzAVBgNVBAoMDnN0YXRpY2xpYnMu 67 | bmV0MRQwEgYDVQQLDAtEZXZlbG9wbWVudDETMBEGA1UEAwwKdGVzdGNsaWVudDEi 68 | MCAGCSqGSIb3DQEJARYTYWxleEBzdGF0aWNsaWJzLm5ldDCCASIwDQYJKoZIhvcN 69 | AQEBBQADggEPADCCAQoCggEBAMRci93LaA+SHpgdbFn/vpXp7fSIhwQMmck1ls9f 70 | fL0Kk46NY/pOgDA/DdE1i1Pmdf/Qk7RKO5ONHAOeOm+1q4n9Sk2HvxQI9SaUpT7N 71 | eLjWzLeGc10pSwOfhYWyn4GrHD3IEfta3CCgM7/WQvZkcj2PdedLuDkncqM4h0LY 72 | eXK+UUEsxdN/D9x/WYGjqWJOI8MbFUnLnGkTvgs3hDnlmeL2YGZtlY8917Z5qq3I 73 | Vl15CY8p6d97HqoCEOBRR5hxuVPzwjYRzSF8J0MVZL/7cOggUa0pTilhWV8YuuaT 74 | Unu7qM9BzFNd12L63IHnMY8sjVIkHh8gSszlTRvcDQs9mUsCAwEAAaN7MHkwCQYD 75 | VR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlm 76 | aWNhdGUwHQYDVR0OBBYEFArxNPFzyaTDrcqGxLOXXRagIZDrMB8GA1UdIwQYMBaA 77 | FE5IQkxQLFXkCsBZLOhfYqPsGLreMA0GCSqGSIb3DQEBBQUAA4IBAQBSd2zDm7pG 78 | dqg9btlJLjGVN5KxPRydEk28MUUXoBS4qPFeiEUBjmAUCxAUATdHnFqvDmTclv07 79 | amaGxb1KpSiaWHKCBRJjOouxkwRrb9Si0iCv3Dc7rsnZ18NxaqhmOoubem9z/YF/ 80 | 3lLflSOPQaoLtZt7kxgYWjhKHKyBSuOWtiQ1qaIxRu3thuh9dgCUg9Lxip7oDLbP 81 | uiJyZPQ2bXFZSzjLOXG/1qhHsCi07hFIfpxLXsl1Wonhop0tz2UTExEdTUSCIxDw 82 | jwep2j0EidOXNphUD1Q8wasIKna8bgK7Cp1QWQlD9IN3qMk4EwNBjXw6hSfBl02U 83 | gdPQaqR0Gpsm 84 | -----END CERTIFICATE----- 85 | -------------------------------------------------------------------------------- /test/certificates/client/testclient.key: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIpkSA+Ze4GhkCAggA 3 | MBQGCCqGSIb3DQMHBAi5tzIzVLokFQSCBMgM6toMsipeKgAv4XDkwt1L5GViTASm 4 | am3KPBp7GC9tWZOEGN+69cVIEuGAozY5Sf6tkZvLLVpfh8w7xXXpzcONhG27v9Ze 5 | G5z5kVECqMUVHKtHYcOfKMQm4Y8Cb//9x9gf8+hfQEeIKC9HP60rurBcOJV2BeVA 6 | kEFW5tKiIRH8d1+wFJo9c59dXukamihzOyC/gVN1BzntXghOLfsEmBcQaIXhyCf0 7 | qn5hBX55a6DzxZCRFu3LVkF5rJcUyptOeVqnO9zbOEGao7RxGc3937XV81IJTx23 8 | iYyAxZD1FUm5/u7qcshZKEuqt7yVXVTQOePYoEiLKaQWwPNR07Wuenr7vEDLy99Y 9 | A/1E7JCYvU+ie7hBpcvrxs5TzNyXJm2s8DMPeG5wLTT97WcbfIoW0SIUt2bwYdQr 10 | rPoL2X2cx3EC+WlaM+BoIn/qHxwEKbSQg3VCPfnQviponsPVBBfeFgRPh4+0ZqtM 11 | O4kt839c6j7WO/KlwMz4VKD4FpayQeQ53LwPrRA/vmWskXpVtwAaRGKQMB75uQOs 12 | Aw/uy3+Y+r/Xaet2DEOVAEflm0j4gwcPkE2F4rT+1DYbHNxyA/W/jWwXyAu9f6YH 13 | D2vLuupZZyHSoxPwp23UNtYIRjy8r3bK+PcASnXMixXpc3bwsaHDuRwUf6e6nD0A 14 | BhKJwDQlj49EvuEhInVk6CNUUS7+xBwuObUnDaLJnCarqwukSHHbGLM+Ga3Usil1 15 | JaEaWadKq588R19h4YGqTdhUYGMQVIeew3LdKvh6NZm4/9m/XAWLlpp3H02/HwtN 16 | EuGr/t8zVX88HcuiMISH3NvCg/CfDLc/GNZByNtlOy4KF5MpwH5tUIiMpnrfozDZ 17 | xP6J4jbYH34txjLLzgxc7zPJkkGjswm+gbY7dGmrwldgMC9AbIhuWovrzfpQEP2L 18 | kLJKpiMx3dx0eu32soexcFsiS+pXlmY2b2g0HYkONSDt+oR68mjP8jzBTq/h8K3d 19 | pJGrKRM9P46p2tFaKc2ncehLOVaBIWIvymG32LQmIIV4bMv/xhAeDr8+OddO/djg 20 | app48m7yYxq3OpDY420teCyCDxhVY83x4tvi3AxhVR1v/BWIYsgpORCBkFiz26UC 21 | /3lwxoaOEv5H1zX/r2p4HSPqV7lpEKw/O6HvYH8Y5u5aXBfMXmnu+D0G0bfg/vX3 22 | BcxMhv9zDSehqvtNDXCAUQW7cj2wt1qYwQsRs6Ub1fXX2DLUxe1M8LMkW8mzXDct 23 | dOSltTeOESYar5DwDIf2VmPSwK3Utn7ahngn/ug4fd+EMWcxHFmObpHP+ctU6ATo 24 | kcvtd846/00iLfppazqii+QlKc9RClY2po8xmcN3yui6xtzbAm0/CPKupT57KpZY 25 | WVW1Gg5fXu9SdHy28rn9hR7ls4nx6+3470X1L+fEK67MerD9tsRSr/AgS7BRX9Fh 26 | Az9X4RUc/odjs0VzBVsDSxKTG3KueYLLxr1JpDNqDDDLuQvGj7AQ+yQVI6DLKcJJ 27 | vh6J36hRJt/3KL+V4BhD+nqDMrdmIJIlHM2FOrYq4qPezqaRjJ9FaFcGbHfBRQ4g 28 | w91Mj6p2gYs9xDs5srXNRFuz+PPV/QJRsSJcZUJogIwlrqSW6bNieJ8tihn40UcZ 29 | wI0= 30 | -----END ENCRYPTED PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /test/certificates/client/testclient.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staticlibs/staticlib_pion/ce3633f7c2c0838b0fffea8d2edc65329986024c/test/certificates/client/testclient.p12 -------------------------------------------------------------------------------- /test/certificates/client/testclient.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIpkSA+Ze4GhkCAggA 3 | MBQGCCqGSIb3DQMHBAi5tzIzVLokFQSCBMgM6toMsipeKgAv4XDkwt1L5GViTASm 4 | am3KPBp7GC9tWZOEGN+69cVIEuGAozY5Sf6tkZvLLVpfh8w7xXXpzcONhG27v9Ze 5 | G5z5kVECqMUVHKtHYcOfKMQm4Y8Cb//9x9gf8+hfQEeIKC9HP60rurBcOJV2BeVA 6 | kEFW5tKiIRH8d1+wFJo9c59dXukamihzOyC/gVN1BzntXghOLfsEmBcQaIXhyCf0 7 | qn5hBX55a6DzxZCRFu3LVkF5rJcUyptOeVqnO9zbOEGao7RxGc3937XV81IJTx23 8 | iYyAxZD1FUm5/u7qcshZKEuqt7yVXVTQOePYoEiLKaQWwPNR07Wuenr7vEDLy99Y 9 | A/1E7JCYvU+ie7hBpcvrxs5TzNyXJm2s8DMPeG5wLTT97WcbfIoW0SIUt2bwYdQr 10 | rPoL2X2cx3EC+WlaM+BoIn/qHxwEKbSQg3VCPfnQviponsPVBBfeFgRPh4+0ZqtM 11 | O4kt839c6j7WO/KlwMz4VKD4FpayQeQ53LwPrRA/vmWskXpVtwAaRGKQMB75uQOs 12 | Aw/uy3+Y+r/Xaet2DEOVAEflm0j4gwcPkE2F4rT+1DYbHNxyA/W/jWwXyAu9f6YH 13 | D2vLuupZZyHSoxPwp23UNtYIRjy8r3bK+PcASnXMixXpc3bwsaHDuRwUf6e6nD0A 14 | BhKJwDQlj49EvuEhInVk6CNUUS7+xBwuObUnDaLJnCarqwukSHHbGLM+Ga3Usil1 15 | JaEaWadKq588R19h4YGqTdhUYGMQVIeew3LdKvh6NZm4/9m/XAWLlpp3H02/HwtN 16 | EuGr/t8zVX88HcuiMISH3NvCg/CfDLc/GNZByNtlOy4KF5MpwH5tUIiMpnrfozDZ 17 | xP6J4jbYH34txjLLzgxc7zPJkkGjswm+gbY7dGmrwldgMC9AbIhuWovrzfpQEP2L 18 | kLJKpiMx3dx0eu32soexcFsiS+pXlmY2b2g0HYkONSDt+oR68mjP8jzBTq/h8K3d 19 | pJGrKRM9P46p2tFaKc2ncehLOVaBIWIvymG32LQmIIV4bMv/xhAeDr8+OddO/djg 20 | app48m7yYxq3OpDY420teCyCDxhVY83x4tvi3AxhVR1v/BWIYsgpORCBkFiz26UC 21 | /3lwxoaOEv5H1zX/r2p4HSPqV7lpEKw/O6HvYH8Y5u5aXBfMXmnu+D0G0bfg/vX3 22 | BcxMhv9zDSehqvtNDXCAUQW7cj2wt1qYwQsRs6Ub1fXX2DLUxe1M8LMkW8mzXDct 23 | dOSltTeOESYar5DwDIf2VmPSwK3Utn7ahngn/ug4fd+EMWcxHFmObpHP+ctU6ATo 24 | kcvtd846/00iLfppazqii+QlKc9RClY2po8xmcN3yui6xtzbAm0/CPKupT57KpZY 25 | WVW1Gg5fXu9SdHy28rn9hR7ls4nx6+3470X1L+fEK67MerD9tsRSr/AgS7BRX9Fh 26 | Az9X4RUc/odjs0VzBVsDSxKTG3KueYLLxr1JpDNqDDDLuQvGj7AQ+yQVI6DLKcJJ 27 | vh6J36hRJt/3KL+V4BhD+nqDMrdmIJIlHM2FOrYq4qPezqaRjJ9FaFcGbHfBRQ4g 28 | w91Mj6p2gYs9xDs5srXNRFuz+PPV/QJRsSJcZUJogIwlrqSW6bNieJ8tihn40UcZ 29 | wI0= 30 | -----END ENCRYPTED PRIVATE KEY----- 31 | Certificate: 32 | Data: 33 | Version: 3 (0x2) 34 | Serial Number: 12065728203692723650 (0xa77213dfd1844dc2) 35 | Signature Algorithm: sha1WithRSAEncryption 36 | Issuer: C=IE, ST=Dublin, O=staticlibs.net, OU=Development, CN=staticlibs_test_ca/emailAddress=alex@staticlibs.net 37 | Validity 38 | Not Before: Jul 12 14:08:02 2015 GMT 39 | Not After : Jul 9 14:08:02 2025 GMT 40 | Subject: C=IE, ST=Dublin, L=Dublin, O=staticlibs.net, OU=Development, CN=testclient/emailAddress=alex@staticlibs.net 41 | Subject Public Key Info: 42 | Public Key Algorithm: rsaEncryption 43 | Public-Key: (2048 bit) 44 | Modulus: 45 | 00:c4:5c:8b:dd:cb:68:0f:92:1e:98:1d:6c:59:ff: 46 | be:95:e9:ed:f4:88:87:04:0c:99:c9:35:96:cf:5f: 47 | 7c:bd:0a:93:8e:8d:63:fa:4e:80:30:3f:0d:d1:35: 48 | 8b:53:e6:75:ff:d0:93:b4:4a:3b:93:8d:1c:03:9e: 49 | 3a:6f:b5:ab:89:fd:4a:4d:87:bf:14:08:f5:26:94: 50 | a5:3e:cd:78:b8:d6:cc:b7:86:73:5d:29:4b:03:9f: 51 | 85:85:b2:9f:81:ab:1c:3d:c8:11:fb:5a:dc:20:a0: 52 | 33:bf:d6:42:f6:64:72:3d:8f:75:e7:4b:b8:39:27: 53 | 72:a3:38:87:42:d8:79:72:be:51:41:2c:c5:d3:7f: 54 | 0f:dc:7f:59:81:a3:a9:62:4e:23:c3:1b:15:49:cb: 55 | 9c:69:13:be:0b:37:84:39:e5:99:e2:f6:60:66:6d: 56 | 95:8f:3d:d7:b6:79:aa:ad:c8:56:5d:79:09:8f:29: 57 | e9:df:7b:1e:aa:02:10:e0:51:47:98:71:b9:53:f3: 58 | c2:36:11:cd:21:7c:27:43:15:64:bf:fb:70:e8:20: 59 | 51:ad:29:4e:29:61:59:5f:18:ba:e6:93:52:7b:bb: 60 | a8:cf:41:cc:53:5d:d7:62:fa:dc:81:e7:31:8f:2c: 61 | 8d:52:24:1e:1f:20:4a:cc:e5:4d:1b:dc:0d:0b:3d: 62 | 99:4b 63 | Exponent: 65537 (0x10001) 64 | X509v3 extensions: 65 | X509v3 Basic Constraints: 66 | CA:FALSE 67 | Netscape Comment: 68 | OpenSSL Generated Certificate 69 | X509v3 Subject Key Identifier: 70 | 0A:F1:34:F1:73:C9:A4:C3:AD:CA:86:C4:B3:97:5D:16:A0:21:90:EB 71 | X509v3 Authority Key Identifier: 72 | keyid:4E:48:42:4C:50:2C:55:E4:0A:C0:59:2C:E8:5F:62:A3:EC:18:BA:DE 73 | 74 | Signature Algorithm: sha1WithRSAEncryption 75 | 52:77:6c:c3:9b:ba:46:76:a8:3d:6e:d9:49:2e:31:95:37:92: 76 | b1:3d:1c:9d:12:4d:bc:31:45:17:a0:14:b8:a8:f1:5e:88:45: 77 | 01:8e:60:14:0b:10:14:01:37:47:9c:5a:af:0e:64:dc:96:fd: 78 | 3b:6a:66:86:c5:bd:4a:a5:28:9a:58:72:82:05:12:63:3a:8b: 79 | b1:93:04:6b:6f:d4:a2:d2:20:af:dc:37:3b:ae:c9:d9:d7:c3: 80 | 71:6a:a8:66:3a:8b:9b:7a:6f:73:fd:81:7f:de:52:df:95:23: 81 | 8f:41:aa:0b:b5:9b:7b:93:18:18:5a:38:4a:1c:ac:81:4a:e3: 82 | 96:b6:24:35:a9:a2:31:46:ed:ed:86:e8:7d:76:00:94:83:d2: 83 | f1:8a:9e:e8:0c:b6:cf:ba:22:72:64:f4:36:6d:71:59:4b:38: 84 | cb:39:71:bf:d6:a8:47:b0:28:b4:ee:11:48:7e:9c:4b:5e:c9: 85 | 75:5a:89:e1:a2:9d:2d:cf:65:13:13:11:1d:4d:44:82:23:10: 86 | f0:8f:07:a9:da:3d:04:89:d3:97:36:98:54:0f:54:3c:c1:ab: 87 | 08:2a:76:bc:6e:02:bb:0a:9d:50:59:09:43:f4:83:77:a8:c9: 88 | 38:13:03:41:8d:7c:3a:85:27:c1:97:4d:94:81:d3:d0:6a:a4: 89 | 74:1a:9b:26 90 | -----BEGIN CERTIFICATE----- 91 | MIIEJTCCAw2gAwIBAgIJAKdyE9/RhE3CMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYD 92 | VQQGEwJJRTEPMA0GA1UECAwGRHVibGluMRcwFQYDVQQKDA5zdGF0aWNsaWJzLm5l 93 | dDEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxGzAZBgNVBAMMEnN0YXRpY2xpYnNfdGVz 94 | dF9jYTEiMCAGCSqGSIb3DQEJARYTYWxleEBzdGF0aWNsaWJzLm5ldDAeFw0xNTA3 95 | MTIxNDA4MDJaFw0yNTA3MDkxNDA4MDJaMIGXMQswCQYDVQQGEwJJRTEPMA0GA1UE 96 | CAwGRHVibGluMQ8wDQYDVQQHDAZEdWJsaW4xFzAVBgNVBAoMDnN0YXRpY2xpYnMu 97 | bmV0MRQwEgYDVQQLDAtEZXZlbG9wbWVudDETMBEGA1UEAwwKdGVzdGNsaWVudDEi 98 | MCAGCSqGSIb3DQEJARYTYWxleEBzdGF0aWNsaWJzLm5ldDCCASIwDQYJKoZIhvcN 99 | AQEBBQADggEPADCCAQoCggEBAMRci93LaA+SHpgdbFn/vpXp7fSIhwQMmck1ls9f 100 | fL0Kk46NY/pOgDA/DdE1i1Pmdf/Qk7RKO5ONHAOeOm+1q4n9Sk2HvxQI9SaUpT7N 101 | eLjWzLeGc10pSwOfhYWyn4GrHD3IEfta3CCgM7/WQvZkcj2PdedLuDkncqM4h0LY 102 | eXK+UUEsxdN/D9x/WYGjqWJOI8MbFUnLnGkTvgs3hDnlmeL2YGZtlY8917Z5qq3I 103 | Vl15CY8p6d97HqoCEOBRR5hxuVPzwjYRzSF8J0MVZL/7cOggUa0pTilhWV8YuuaT 104 | Unu7qM9BzFNd12L63IHnMY8sjVIkHh8gSszlTRvcDQs9mUsCAwEAAaN7MHkwCQYD 105 | VR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlm 106 | aWNhdGUwHQYDVR0OBBYEFArxNPFzyaTDrcqGxLOXXRagIZDrMB8GA1UdIwQYMBaA 107 | FE5IQkxQLFXkCsBZLOhfYqPsGLreMA0GCSqGSIb3DQEBBQUAA4IBAQBSd2zDm7pG 108 | dqg9btlJLjGVN5KxPRydEk28MUUXoBS4qPFeiEUBjmAUCxAUATdHnFqvDmTclv07 109 | amaGxb1KpSiaWHKCBRJjOouxkwRrb9Si0iCv3Dc7rsnZ18NxaqhmOoubem9z/YF/ 110 | 3lLflSOPQaoLtZt7kxgYWjhKHKyBSuOWtiQ1qaIxRu3thuh9dgCUg9Lxip7oDLbP 111 | uiJyZPQ2bXFZSzjLOXG/1qhHsCi07hFIfpxLXsl1Wonhop0tz2UTExEdTUSCIxDw 112 | jwep2j0EidOXNphUD1Q8wasIKna8bgK7Cp1QWQlD9IN3qMk4EwNBjXw6hSfBl02U 113 | gdPQaqR0Gpsm 114 | -----END CERTIFICATE----- 115 | -------------------------------------------------------------------------------- /test/certificates/client/testclient_nopwd.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAxFyL3ctoD5IemB1sWf++lent9IiHBAyZyTWWz198vQqTjo1j 3 | +k6AMD8N0TWLU+Z1/9CTtEo7k40cA546b7Wrif1KTYe/FAj1JpSlPs14uNbMt4Zz 4 | XSlLA5+FhbKfgascPcgR+1rcIKAzv9ZC9mRyPY9150u4OSdyoziHQth5cr5RQSzF 5 | 038P3H9ZgaOpYk4jwxsVScucaRO+CzeEOeWZ4vZgZm2Vjz3XtnmqrchWXXkJjynp 6 | 33seqgIQ4FFHmHG5U/PCNhHNIXwnQxVkv/tw6CBRrSlOKWFZXxi65pNSe7uoz0HM 7 | U13XYvrcgecxjyyNUiQeHyBKzOVNG9wNCz2ZSwIDAQABAoIBAHyZhR8eXU/UFpnL 8 | wd9yCwuxvw72O0Z0gHlPCf1YyBxkw7EnQxOoEGuM90WTxm9cw++p+K/kkt1UIzyg 9 | gNA15T3Qff+obbVW4cizdg/d7gbMNmcWZ8nr0+/en6lw6Qos++SwOcjXpOsG/Q9z 10 | 9FXI8zzg9Z3pTGLoBzRPQHVIS/hkcY4YCD4kVktDfSF1AAr136SxJyXinTupt5tZ 11 | A2VKzWTxiHpnLQZSUkU1I4zuEfp5ebUwWI1Ulstb83xQnHtzq7rAxK85caFW/2ks 12 | g7raIPhCDHJ/QhCQeZGjib3ItPhuADbI81RzEMDVFXiha8NfdfoQiox3sM/3cofR 13 | 4QMjLZECgYEA+e/maNkIQJleH2vV2HPnvv/kD/v34eJEq9fdHldBdlKeeCtyKIou 14 | 5Mw4hkzxz2ZbG+/rrcDPL2crM8UZG/a5GgrNrH+TAaIh3h5IoQTZQnUj2bx3B2Hh 15 | BVIjM5Gj7/Ot/dM3bK7g0VuuPSp06KozjZiP1uodqhQ/1Pe7/vyjlE0CgYEAyR/x 16 | oY3h6FgJYF6BKm0dKLoAMnUacOAgGYtRPud3WB/n7z+gNgN5ZLQ1iijoXIkNbeH1 17 | 6q3TnWmOMay4WBO6U4dFbyiNJS8y4hrdWvk17kPjHTYAZEFDE3yVbR/B7MlP/ODG 18 | Yw59qAc9HrWTxUBbGofcX1tPl/HuhlEJSQMdD/cCgYB2cAhvhukyM3s2yJL9j28y 19 | Q3B/YpeEowSHqjNOPWr39w7BQ1VFgLXYFi5y9eNgtNBX3MmB/OwxOmJulefgKHpu 20 | rM/p/kpba8lAyHkCVJnftELY20ZMaUWIj/O+bDWTb5XzwjNxfS1sCFX5BjWAS6dC 21 | YhlHbonAHvhgo0SjAHVDwQKBgHgae1DeSWlWKUNDLB8Jyb/oUvXOuFtve7vFVl8a 22 | Gkqlwvs8I5AdwwBAHTjD9P5NWZekuBXMd/IodqFzYyI1pa77uJsIvEDYTqp3IHiT 23 | GYGPSLDI7rLvxf59Bz6DGGsuTHXWRKIipScSK42LIRNJux28w/ytqnoyHx5WhhTz 24 | pwdBAoGBAN+0ZzYR/UoRucWajsbyaovpS6urgPYXXujteHIxXXzcg7AIyCEL+Ag6 25 | RiH9ESenSjJYg3aUtRgPi2TUElmYwow+yhMuEJXXWiaHev7cE1smd0KVQtW+dil3 26 | /Rkg3DEZLDFMjKxB2vtiswDk1y6OmWz8/3XDE7CrSN87Kw2WwP34 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /test/certificates/server/localhost.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIJ0JjZl7VECYCAggA 3 | MBQGCCqGSIb3DQMHBAiSDurxuXfI+wSCBMjQfRt060fm01Nlg1w56pqi6ig/fCNs 4 | EBhcGRJRi0W2RKHjaDTarEcCYcioGwW3ghwHK73mdHyC4nrJvZjXRJAT5PGK2h6h 5 | mr/e1gMoTGJ0mMgOOO94AWH866mGW9YR7DF9NG07Pw0Fy34ujlulBxf8H1m4CM5X 6 | DYgufkWHoACCRcT+dFFDpjGD3zOEs/DDgp/VBxs6/LDiBTxsM6xSqnUf+4kkx8N2 7 | cXNYgacXC/4eqqyivJikT6nV3v80ucCK7bhZrW+DnkkPZNjM7bwmiqc08cd7SSGA 8 | YG7FRFO//6EQBGd81GaY6h3TpAn7t/JUNhtdgfpU3eJCfuPc7YKoWvlEON0maPlA 9 | Xio4pSE/FbETH3avCAffvItOOttM4pPciQdVpsdxgg1CuNGwPkuZSWHnY6tCvU4n 10 | svdRER5GviUfFOzEHhtsyVlCZujRurxetDoOs1gmOl46fiMOS0+9WxZfgKKhVufz 11 | AywLlOICMbnqdqbOsWZzvgld3CU8w/NM7SeY91McgE9eJ2N3q1K07OoHPvc5p11D 12 | 0Otg6rnDu3tbI5mH1CJNsjo+kTPDAnj7yzIziwfwq6qXMqLlaTLCILv/DwCQeuAZ 13 | hUinM3TqplD8iw9aJJyr3XmO4+vZCcVSJSHmfOTW7kWbgdUkWmm/sz0yLIU1oasz 14 | a0L3mKiGFE3VyfnjwNXpdZPyDfNdjh7njZr3+yBQ+y7hW7PWz0uyvO2ZfkQFyjHC 15 | SokCeADtETHbBC1eGCECyGwDo1MgOQJtgFHH6ItBVFOVf1WYvZ+F5M0jeTiUYh9i 16 | kuApqHt6OmIqGiwWn9CAIVxVDCA8DP1GHuexGIjE9DkEmnUvSxHm/7XFRPUwZZbI 17 | QuywI20xiW8yfSWW+x0Jyq6uguH87RgSLW0RkoMdf9XXXFSUeB+lEZsvDOshezxa 18 | V868nkv3U4TnKjxPREpGedYC9kT6/sPaiFajF4fQLWhVW0WHBlhp0mnvilZda4aW 19 | oOV8yXgjEoSRxu5NGXcqpB/h2wNlgOXMxOaCVUrTtnS2nMIJXjocjx6LMi9eqgCT 20 | Ml/tzyiAVkPAuMsWQWzHqj7aftprSV3twtPLui/511HipRuHZQPc+j0iYvnaVw9C 21 | id1lwanIH+ymKFcGFwBf/tM/I8f8iXlSr28vu+wdASNxe5PgzVob5pQe3k6kwdaD 22 | FvZ1VrhvgnPuFTcucPY+GIBE9lLBTu/b3rI6jXiLYA4hAX09QhDZC/O21AUaVnCU 23 | hgLwVjFyj/K9AoEYU8hu9YtquNGsqqJmfb6gtV818wy80Xh1eGcIiGPTEVFJ+qWz 24 | gofA4eL9qlepQRoXYwlfBssdiQBKEpK7HeUiBsyCS87OS83K9TmzsFeovVkD+vwo 25 | aBzxyfEpRUlBUumaB++48cDjES3R27dsgh2y1bExxlcT25/XzEKId/7FdF0YCHhZ 26 | AzhBs9OgzO0nDzifWTOvJ98Jb3blhpMeBrzqw7bmspvIJqIluJ5Wg+/C1SWwiHEi 27 | cm/ocCGTvdy+zDmPYCokbJgE0uxKLNFdtJw+/z9M3NSwlBSrbmPkfF4HsiwHMgrk 28 | aT5JEWwwsBifmLNCBO4Lv6Lsb4ZvVUs9CfWCykd5dpgg85fAu9Iktz65/GcLFmX+ 29 | fzE= 30 | -----END ENCRYPTED PRIVATE KEY----- 31 | Certificate: 32 | Data: 33 | Version: 3 (0x2) 34 | Serial Number: 12065728203692723649 (0xa77213dfd1844dc1) 35 | Signature Algorithm: sha1WithRSAEncryption 36 | Issuer: C=IE, ST=Dublin, O=staticlibs.net, OU=Development, CN=staticlibs_test_ca/emailAddress=alex@staticlibs.net 37 | Validity 38 | Not Before: Jul 12 11:43:06 2015 GMT 39 | Not After : Jul 9 11:43:06 2025 GMT 40 | Subject: C=IE, ST=Dublin, L=Dublin, O=staticlibs.net, OU=Development, CN=localhost/emailAddress=alex@staticlibs.net 41 | Subject Public Key Info: 42 | Public Key Algorithm: rsaEncryption 43 | Public-Key: (2048 bit) 44 | Modulus: 45 | 00:bc:8c:93:f3:4f:fa:b2:2e:de:cf:01:ae:d7:66: 46 | e1:b2:87:d7:f7:6e:b3:67:47:3d:3e:f2:12:1e:7b: 47 | 8b:39:7b:9f:f7:81:e4:94:86:69:e4:25:3f:6b:94: 48 | a4:fa:95:0b:a0:d7:ea:b2:83:89:57:09:87:74:af: 49 | 86:15:dd:68:cd:a1:f1:8e:2a:9f:f6:29:d0:62:0d: 50 | 58:81:37:c2:02:fb:d1:90:51:0d:39:f8:23:25:98: 51 | bb:63:a6:e8:8f:8a:8d:bd:0a:9b:ed:7b:4c:10:9a: 52 | ed:e3:fc:75:69:e8:8b:41:62:ce:99:6f:91:9b:46: 53 | 2a:34:83:7c:82:93:08:e6:d5:0b:0a:26:36:24:28: 54 | b0:4e:94:3c:aa:a2:e0:67:a0:33:65:56:71:a9:e0: 55 | 5c:fa:eb:5f:18:77:c1:6a:dd:41:a6:6d:95:c9:e7: 56 | e1:d8:38:6f:a4:f2:41:d0:e8:e0:e9:34:c9:67:88: 57 | 22:43:45:1a:36:6c:36:95:21:c5:ad:ee:f2:48:50: 58 | f2:dc:46:29:c9:0e:89:f5:64:9b:d2:5b:63:37:e5: 59 | 64:fb:4f:68:6e:60:30:5e:f6:80:f6:8a:20:b2:42: 60 | 29:64:23:e7:53:59:3d:63:fb:a3:52:c2:f5:a5:e9: 61 | 93:d6:f8:a7:2a:91:8e:ff:be:7d:42:8a:32:f0:27: 62 | cf:07 63 | Exponent: 65537 (0x10001) 64 | X509v3 extensions: 65 | X509v3 Basic Constraints: 66 | CA:FALSE 67 | Netscape Comment: 68 | OpenSSL Generated Certificate 69 | X509v3 Subject Key Identifier: 70 | 7F:5C:DE:B1:FF:FB:C9:A9:61:DA:08:24:03:3B:E8:A5:3A:63:05:3D 71 | X509v3 Authority Key Identifier: 72 | keyid:4E:48:42:4C:50:2C:55:E4:0A:C0:59:2C:E8:5F:62:A3:EC:18:BA:DE 73 | 74 | Signature Algorithm: sha1WithRSAEncryption 75 | d1:85:da:79:25:19:a1:ac:6c:09:37:08:0a:27:c6:81:5a:f2: 76 | be:b0:c8:cf:3c:70:79:28:fa:6e:6c:9b:f3:0c:4a:e5:7e:8a: 77 | 34:97:89:29:43:19:1a:55:e6:74:ba:13:6e:c2:42:6c:2f:d6: 78 | 65:fd:48:7c:8e:d0:36:ae:48:50:41:6a:16:ed:9e:88:04:6f: 79 | 39:fb:f5:ee:53:d7:5d:5e:27:15:ad:ec:41:6d:e2:34:2d:2c: 80 | 24:b0:9f:d6:ac:42:53:48:44:4a:65:de:a7:29:93:d7:ee:58: 81 | 6b:bc:80:4f:86:56:c4:df:e6:0c:ae:86:66:d4:fc:aa:35:07: 82 | 19:ff:8b:1b:9e:0d:3e:56:d1:8b:51:e1:43:77:d1:76:a8:03: 83 | 1f:06:56:f0:4d:aa:a5:5f:f8:a0:ca:49:0c:60:3a:af:cc:71: 84 | e9:26:0e:b6:b8:70:40:69:ed:2d:b9:96:1c:d3:7b:dc:23:19: 85 | 77:c9:16:7f:14:7f:b5:c6:1b:b6:be:52:bb:fa:88:0f:36:e6: 86 | 46:43:6f:2b:12:77:29:f9:86:5f:1d:29:89:a3:d8:40:78:7c: 87 | 52:e3:40:e2:a7:b2:e5:70:75:20:c9:63:26:c0:c4:95:41:de: 88 | 2d:bd:2a:70:2e:92:a6:66:eb:8f:45:d4:68:64:70:36:e3:f2: 89 | 05:38:8c:c1 90 | -----BEGIN CERTIFICATE----- 91 | MIIEJDCCAwygAwIBAgIJAKdyE9/RhE3BMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYD 92 | VQQGEwJJRTEPMA0GA1UECAwGRHVibGluMRcwFQYDVQQKDA5zdGF0aWNsaWJzLm5l 93 | dDEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxGzAZBgNVBAMMEnN0YXRpY2xpYnNfdGVz 94 | dF9jYTEiMCAGCSqGSIb3DQEJARYTYWxleEBzdGF0aWNsaWJzLm5ldDAeFw0xNTA3 95 | MTIxMTQzMDZaFw0yNTA3MDkxMTQzMDZaMIGWMQswCQYDVQQGEwJJRTEPMA0GA1UE 96 | CAwGRHVibGluMQ8wDQYDVQQHDAZEdWJsaW4xFzAVBgNVBAoMDnN0YXRpY2xpYnMu 97 | bmV0MRQwEgYDVQQLDAtEZXZlbG9wbWVudDESMBAGA1UEAwwJbG9jYWxob3N0MSIw 98 | IAYJKoZIhvcNAQkBFhNhbGV4QHN0YXRpY2xpYnMubmV0MIIBIjANBgkqhkiG9w0B 99 | AQEFAAOCAQ8AMIIBCgKCAQEAvIyT80/6si7ezwGu12bhsofX926zZ0c9PvISHnuL 100 | OXuf94HklIZp5CU/a5Sk+pULoNfqsoOJVwmHdK+GFd1ozaHxjiqf9inQYg1YgTfC 101 | AvvRkFENOfgjJZi7Y6boj4qNvQqb7XtMEJrt4/x1aeiLQWLOmW+Rm0YqNIN8gpMI 102 | 5tULCiY2JCiwTpQ8qqLgZ6AzZVZxqeBc+utfGHfBat1Bpm2Vyefh2DhvpPJB0Ojg 103 | 6TTJZ4giQ0UaNmw2lSHFre7ySFDy3EYpyQ6J9WSb0ltjN+Vk+09obmAwXvaA9oog 104 | skIpZCPnU1k9Y/ujUsL1pemT1vinKpGO/759Qooy8CfPBwIDAQABo3sweTAJBgNV 105 | HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp 106 | Y2F0ZTAdBgNVHQ4EFgQUf1zesf/7yalh2ggkAzvopTpjBT0wHwYDVR0jBBgwFoAU 107 | TkhCTFAsVeQKwFks6F9io+wYut4wDQYJKoZIhvcNAQEFBQADggEBANGF2nklGaGs 108 | bAk3CAonxoFa8r6wyM88cHko+m5sm/MMSuV+ijSXiSlDGRpV5nS6E27CQmwv1mX9 109 | SHyO0DauSFBBahbtnogEbzn79e5T111eJxWt7EFt4jQtLCSwn9asQlNIREpl3qcp 110 | k9fuWGu8gE+GVsTf5gyuhmbU/Ko1Bxn/ixueDT5W0YtR4UN30XaoAx8GVvBNqqVf 111 | +KDKSQxgOq/McekmDra4cEBp7S25lhzTe9wjGXfJFn8Uf7XGG7a+Urv6iA825kZD 112 | bysSdyn5hl8dKYmj2EB4fFLjQOKnsuVwdSDJYybAxJVB3i29KnAukqZm649F1Ghk 113 | cDbj8gU4jME= 114 | -----END CERTIFICATE----- 115 | -------------------------------------------------------------------------------- /test/certificates/server/localhost_nopwd.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAvIyT80/6si7ezwGu12bhsofX926zZ0c9PvISHnuLOXuf94Hk 3 | lIZp5CU/a5Sk+pULoNfqsoOJVwmHdK+GFd1ozaHxjiqf9inQYg1YgTfCAvvRkFEN 4 | OfgjJZi7Y6boj4qNvQqb7XtMEJrt4/x1aeiLQWLOmW+Rm0YqNIN8gpMI5tULCiY2 5 | JCiwTpQ8qqLgZ6AzZVZxqeBc+utfGHfBat1Bpm2Vyefh2DhvpPJB0Ojg6TTJZ4gi 6 | Q0UaNmw2lSHFre7ySFDy3EYpyQ6J9WSb0ltjN+Vk+09obmAwXvaA9oogskIpZCPn 7 | U1k9Y/ujUsL1pemT1vinKpGO/759Qooy8CfPBwIDAQABAoIBAAs9ijhwJS7oMmo+ 8 | 3HCE9qGRDaP3moRmr9UH02Kz1Mn5f8DeooTkOn3aZpyAQRGbPxU4qgo4Y0CoFcY0 9 | DJdTGsNfiyoBioW/WmfuCb+yVkOdRZIH8vTowRelsk4vjh+4j9icQE15E0DOK65y 10 | x4En1t1wCYcGKrUKCswUpqCWKWqxYGMGCdybr1XVLDdr+TFC5/4Cmy+a5uvK0bc7 11 | TkIxPd5vEL8CIfe81t91SXMfzJc33b3HkNVX8SigNi0YSen7QZyDBOzxwJiloF8E 12 | dhO+WXweeEVooi5obs0r1wqLm3qHYeKY47i3YnEPNXmUzYDF6CIPgxLbG6WbaqV+ 13 | KUAPkGkCgYEA8p+NXN/7VRuEV9IR7Sdrrhqj4CbGq66apbrh2v3oINFYITThAcKk 14 | wxVWI0ptY3vjqzfTUCBvD3MIPGO53BqYwa2u/IdHsw2gC3jYWIVRA61Vo1FjFApB 15 | SJ2T+3KnmHi++OjA84uTajWZy4YsgPVLdYFK5PUpz4PcX1yw3hvg1vMCgYEAxvHP 16 | PZsXR0/b7j4MrwaJwAGZho5Mkd3s5gyY4c5scUA4CjuYZ4eZqYcEC6Cs6c02lWWL 17 | 5OG4dURhwzLh6pswNoQurYmyKLut2qLCUELbPzUfOitWkeo0+RRcafhX0UY7rRve 18 | Pxe0Ud/Xr0EBMB1cE7jWxHpS8bGK9Dsbht/jFJ0CgYAjoPqJYPrvjJLqspafVOKj 19 | NpZKHGegXounOsJf/llQOG3Qsos4TvUTENcNZ6iYq2DLi+8kHR8yDZpwA9UPVXiJ 20 | OJAx1UvaJ24RQTXECg/Tkmi5CwKZtsfPehR5IGUsJs8kjkmHej+zoRtsn895QIxM 21 | PShaZwY0yxBZkKsIct+ZsQKBgHDYfIsfS8cBf2jV/W/SL5Sf06vFT5112ohrINUE 22 | t/JNUPxM7ZfcDMdidGL8EtjTtGBtpzp+5pht315PoGHpASILPEbnUg1U17qqk7nf 23 | Emn6AeqG5qYByWZ3rCvX2Eg2pGb+5cO3+Gpwo/Ee2EOog7AUKo5sLFw4Lu92D5kj 24 | qbTpAoGBAKez/siacPoxSzOh/9QEMsq4abMbauCeGZumeFSMHmmyhJ564thTwC8Y 25 | SJmp0NCnmx9bGnpYtvgfFsy9Q0sCDgZLRGlwHoXzV82JgnDfQ4n+ZRe5nfnO2shm 26 | mAhDpzU6k/XnZDLkU/2L0rlYgUfi1tiQxD8/mO0w0OjcY+khJL9K 27 | -----END RSA PRIVATE KEY----- 28 | Certificate: 29 | Data: 30 | Version: 3 (0x2) 31 | Serial Number: 12065728203692723649 (0xa77213dfd1844dc1) 32 | Signature Algorithm: sha1WithRSAEncryption 33 | Issuer: C=IE, ST=Dublin, O=staticlibs.net, OU=Development, CN=staticlibs_test_ca/emailAddress=alex@staticlibs.net 34 | Validity 35 | Not Before: Jul 12 11:43:06 2015 GMT 36 | Not After : Jul 9 11:43:06 2025 GMT 37 | Subject: C=IE, ST=Dublin, L=Dublin, O=staticlibs.net, OU=Development, CN=localhost/emailAddress=alex@staticlibs.net 38 | Subject Public Key Info: 39 | Public Key Algorithm: rsaEncryption 40 | Public-Key: (2048 bit) 41 | Modulus: 42 | 00:bc:8c:93:f3:4f:fa:b2:2e:de:cf:01:ae:d7:66: 43 | e1:b2:87:d7:f7:6e:b3:67:47:3d:3e:f2:12:1e:7b: 44 | 8b:39:7b:9f:f7:81:e4:94:86:69:e4:25:3f:6b:94: 45 | a4:fa:95:0b:a0:d7:ea:b2:83:89:57:09:87:74:af: 46 | 86:15:dd:68:cd:a1:f1:8e:2a:9f:f6:29:d0:62:0d: 47 | 58:81:37:c2:02:fb:d1:90:51:0d:39:f8:23:25:98: 48 | bb:63:a6:e8:8f:8a:8d:bd:0a:9b:ed:7b:4c:10:9a: 49 | ed:e3:fc:75:69:e8:8b:41:62:ce:99:6f:91:9b:46: 50 | 2a:34:83:7c:82:93:08:e6:d5:0b:0a:26:36:24:28: 51 | b0:4e:94:3c:aa:a2:e0:67:a0:33:65:56:71:a9:e0: 52 | 5c:fa:eb:5f:18:77:c1:6a:dd:41:a6:6d:95:c9:e7: 53 | e1:d8:38:6f:a4:f2:41:d0:e8:e0:e9:34:c9:67:88: 54 | 22:43:45:1a:36:6c:36:95:21:c5:ad:ee:f2:48:50: 55 | f2:dc:46:29:c9:0e:89:f5:64:9b:d2:5b:63:37:e5: 56 | 64:fb:4f:68:6e:60:30:5e:f6:80:f6:8a:20:b2:42: 57 | 29:64:23:e7:53:59:3d:63:fb:a3:52:c2:f5:a5:e9: 58 | 93:d6:f8:a7:2a:91:8e:ff:be:7d:42:8a:32:f0:27: 59 | cf:07 60 | Exponent: 65537 (0x10001) 61 | X509v3 extensions: 62 | X509v3 Basic Constraints: 63 | CA:FALSE 64 | Netscape Comment: 65 | OpenSSL Generated Certificate 66 | X509v3 Subject Key Identifier: 67 | 7F:5C:DE:B1:FF:FB:C9:A9:61:DA:08:24:03:3B:E8:A5:3A:63:05:3D 68 | X509v3 Authority Key Identifier: 69 | keyid:4E:48:42:4C:50:2C:55:E4:0A:C0:59:2C:E8:5F:62:A3:EC:18:BA:DE 70 | 71 | Signature Algorithm: sha1WithRSAEncryption 72 | d1:85:da:79:25:19:a1:ac:6c:09:37:08:0a:27:c6:81:5a:f2: 73 | be:b0:c8:cf:3c:70:79:28:fa:6e:6c:9b:f3:0c:4a:e5:7e:8a: 74 | 34:97:89:29:43:19:1a:55:e6:74:ba:13:6e:c2:42:6c:2f:d6: 75 | 65:fd:48:7c:8e:d0:36:ae:48:50:41:6a:16:ed:9e:88:04:6f: 76 | 39:fb:f5:ee:53:d7:5d:5e:27:15:ad:ec:41:6d:e2:34:2d:2c: 77 | 24:b0:9f:d6:ac:42:53:48:44:4a:65:de:a7:29:93:d7:ee:58: 78 | 6b:bc:80:4f:86:56:c4:df:e6:0c:ae:86:66:d4:fc:aa:35:07: 79 | 19:ff:8b:1b:9e:0d:3e:56:d1:8b:51:e1:43:77:d1:76:a8:03: 80 | 1f:06:56:f0:4d:aa:a5:5f:f8:a0:ca:49:0c:60:3a:af:cc:71: 81 | e9:26:0e:b6:b8:70:40:69:ed:2d:b9:96:1c:d3:7b:dc:23:19: 82 | 77:c9:16:7f:14:7f:b5:c6:1b:b6:be:52:bb:fa:88:0f:36:e6: 83 | 46:43:6f:2b:12:77:29:f9:86:5f:1d:29:89:a3:d8:40:78:7c: 84 | 52:e3:40:e2:a7:b2:e5:70:75:20:c9:63:26:c0:c4:95:41:de: 85 | 2d:bd:2a:70:2e:92:a6:66:eb:8f:45:d4:68:64:70:36:e3:f2: 86 | 05:38:8c:c1 87 | -----BEGIN CERTIFICATE----- 88 | MIIEJDCCAwygAwIBAgIJAKdyE9/RhE3BMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYD 89 | VQQGEwJJRTEPMA0GA1UECAwGRHVibGluMRcwFQYDVQQKDA5zdGF0aWNsaWJzLm5l 90 | dDEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxGzAZBgNVBAMMEnN0YXRpY2xpYnNfdGVz 91 | dF9jYTEiMCAGCSqGSIb3DQEJARYTYWxleEBzdGF0aWNsaWJzLm5ldDAeFw0xNTA3 92 | MTIxMTQzMDZaFw0yNTA3MDkxMTQzMDZaMIGWMQswCQYDVQQGEwJJRTEPMA0GA1UE 93 | CAwGRHVibGluMQ8wDQYDVQQHDAZEdWJsaW4xFzAVBgNVBAoMDnN0YXRpY2xpYnMu 94 | bmV0MRQwEgYDVQQLDAtEZXZlbG9wbWVudDESMBAGA1UEAwwJbG9jYWxob3N0MSIw 95 | IAYJKoZIhvcNAQkBFhNhbGV4QHN0YXRpY2xpYnMubmV0MIIBIjANBgkqhkiG9w0B 96 | AQEFAAOCAQ8AMIIBCgKCAQEAvIyT80/6si7ezwGu12bhsofX926zZ0c9PvISHnuL 97 | OXuf94HklIZp5CU/a5Sk+pULoNfqsoOJVwmHdK+GFd1ozaHxjiqf9inQYg1YgTfC 98 | AvvRkFENOfgjJZi7Y6boj4qNvQqb7XtMEJrt4/x1aeiLQWLOmW+Rm0YqNIN8gpMI 99 | 5tULCiY2JCiwTpQ8qqLgZ6AzZVZxqeBc+utfGHfBat1Bpm2Vyefh2DhvpPJB0Ojg 100 | 6TTJZ4giQ0UaNmw2lSHFre7ySFDy3EYpyQ6J9WSb0ltjN+Vk+09obmAwXvaA9oog 101 | skIpZCPnU1k9Y/ujUsL1pemT1vinKpGO/759Qooy8CfPBwIDAQABo3sweTAJBgNV 102 | HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp 103 | Y2F0ZTAdBgNVHQ4EFgQUf1zesf/7yalh2ggkAzvopTpjBT0wHwYDVR0jBBgwFoAU 104 | TkhCTFAsVeQKwFks6F9io+wYut4wDQYJKoZIhvcNAQEFBQADggEBANGF2nklGaGs 105 | bAk3CAonxoFa8r6wyM88cHko+m5sm/MMSuV+ijSXiSlDGRpV5nS6E27CQmwv1mX9 106 | SHyO0DauSFBBahbtnogEbzn79e5T111eJxWt7EFt4jQtLCSwn9asQlNIREpl3qcp 107 | k9fuWGu8gE+GVsTf5gyuhmbU/Ko1Bxn/ixueDT5W0YtR4UN30XaoAx8GVvBNqqVf 108 | +KDKSQxgOq/McekmDra4cEBp7S25lhzTe9wjGXfJFn8Uf7XGG7a+Urv6iA825kZD 109 | bysSdyn5hl8dKYmj2EB4fFLjQOKnsuVwdSDJYybAxJVB3i29KnAukqZm649F1Ghk 110 | cDbj8gU4jME= 111 | -----END CERTIFICATE----- 112 | -------------------------------------------------------------------------------- /test/certificates/server/staticlibs_test_ca.cer: -------------------------------------------------------------------------------- 1 | Certificate: 2 | Data: 3 | Version: 3 (0x2) 4 | Serial Number: 12065728203692723648 (0xa77213dfd1844dc0) 5 | Signature Algorithm: sha1WithRSAEncryption 6 | Issuer: C=IE, ST=Dublin, O=staticlibs.net, OU=Development, CN=staticlibs_test_ca/emailAddress=alex@staticlibs.net 7 | Validity 8 | Not Before: Jul 12 11:25:08 2015 GMT 9 | Not After : Jul 9 11:25:08 2025 GMT 10 | Subject: C=IE, ST=Dublin, O=staticlibs.net, OU=Development, CN=staticlibs_test_ca/emailAddress=alex@staticlibs.net 11 | Subject Public Key Info: 12 | Public Key Algorithm: rsaEncryption 13 | Public-Key: (2048 bit) 14 | Modulus: 15 | 00:d8:38:ce:d0:ed:9c:dc:6f:65:6f:8e:0f:a4:85: 16 | a9:08:3d:53:49:7d:65:af:04:a6:dd:02:9f:7d:89: 17 | 44:30:1a:72:1d:2f:26:d5:77:2d:2e:f8:e8:cd:6f: 18 | d9:dd:a7:93:b5:b6:8f:c2:a3:4b:cf:99:94:d8:e6: 19 | 98:db:21:6d:f3:6c:e4:7d:a2:15:4d:46:0a:c8:24: 20 | 40:a3:c1:8e:09:2f:7f:b1:1d:13:a7:8b:71:4f:23: 21 | c4:a2:a5:4c:2e:22:9c:3e:d6:4a:a5:3f:40:1b:81: 22 | e5:e8:3a:7c:a8:35:fb:24:ff:f8:3c:80:4a:2a:22: 23 | 91:d9:8b:80:49:be:be:a9:ec:ac:95:14:6b:c3:c5: 24 | bf:a2:57:11:83:a5:40:0c:2f:4d:d4:ee:16:12:7d: 25 | 66:30:88:81:77:15:2d:3e:75:7e:bf:c5:da:a2:9e: 26 | 49:92:33:ed:eb:ee:db:45:34:61:77:fc:72:f1:08: 27 | 67:57:a4:86:bc:2e:89:b2:56:a6:de:dc:cd:b3:c8: 28 | 93:73:a5:ab:1d:e8:99:55:14:62:2e:f5:9f:51:c6: 29 | 9e:eb:0b:ae:c6:68:e2:8d:3f:8b:16:b4:d0:48:96: 30 | d0:b4:bf:15:1e:27:89:71:86:5c:d4:0c:f1:0b:8e: 31 | 56:81:e8:35:72:29:67:ff:83:d2:2f:51:fb:3d:29: 32 | 43:df 33 | Exponent: 65537 (0x10001) 34 | X509v3 extensions: 35 | X509v3 Subject Key Identifier: 36 | 4E:48:42:4C:50:2C:55:E4:0A:C0:59:2C:E8:5F:62:A3:EC:18:BA:DE 37 | X509v3 Authority Key Identifier: 38 | keyid:4E:48:42:4C:50:2C:55:E4:0A:C0:59:2C:E8:5F:62:A3:EC:18:BA:DE 39 | 40 | X509v3 Basic Constraints: 41 | CA:TRUE 42 | Signature Algorithm: sha1WithRSAEncryption 43 | b3:99:d8:ef:4d:4d:fd:5b:64:aa:7a:c1:f5:97:a7:29:6a:8d: 44 | 73:59:49:c2:e2:3f:6c:4e:da:e7:4e:10:26:1a:88:8a:70:87: 45 | f4:7c:e1:10:e7:db:25:8a:15:78:ba:8b:f2:a3:c0:9b:90:9d: 46 | 03:ec:36:11:10:a7:61:92:1b:91:6f:f8:a5:a4:ff:e6:1c:05: 47 | ec:a0:07:e3:b7:ce:d1:9a:81:5b:6b:1f:59:c1:98:be:67:ee: 48 | ab:fb:ee:46:cb:12:ce:78:3e:0e:75:01:e8:79:2e:37:c2:dc: 49 | 93:fc:61:ab:f5:d9:0c:ff:1a:98:3a:17:6a:7e:e6:60:66:53: 50 | cd:3d:ca:9d:2f:6e:08:75:c1:af:59:bd:e4:68:81:c4:73:53: 51 | fd:ad:bf:88:30:d5:25:b1:00:e9:2d:ee:b6:8b:f3:ae:d0:91: 52 | 20:81:89:3d:b5:ff:cb:62:79:32:7f:42:25:39:77:b0:b9:60: 53 | d5:e7:79:aa:cf:e4:9e:47:97:a9:ab:86:e3:fc:c2:74:fc:42: 54 | ba:14:51:11:8e:80:2f:c4:b6:5d:30:b8:9f:34:b9:4f:d2:e5: 55 | 71:1e:50:4f:4d:22:46:07:44:83:c8:3f:86:24:f6:88:c6:58: 56 | 97:8e:06:0c:ab:96:90:bf:71:40:04:07:78:fe:53:93:5f:c1: 57 | 52:09:48:f8 58 | -----BEGIN CERTIFICATE----- 59 | MIID8TCCAtmgAwIBAgIJAKdyE9/RhE3AMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYD 60 | VQQGEwJJRTEPMA0GA1UECAwGRHVibGluMRcwFQYDVQQKDA5zdGF0aWNsaWJzLm5l 61 | dDEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxGzAZBgNVBAMMEnN0YXRpY2xpYnNfdGVz 62 | dF9jYTEiMCAGCSqGSIb3DQEJARYTYWxleEBzdGF0aWNsaWJzLm5ldDAeFw0xNTA3 63 | MTIxMTI1MDhaFw0yNTA3MDkxMTI1MDhaMIGOMQswCQYDVQQGEwJJRTEPMA0GA1UE 64 | CAwGRHVibGluMRcwFQYDVQQKDA5zdGF0aWNsaWJzLm5ldDEUMBIGA1UECwwLRGV2 65 | ZWxvcG1lbnQxGzAZBgNVBAMMEnN0YXRpY2xpYnNfdGVzdF9jYTEiMCAGCSqGSIb3 66 | DQEJARYTYWxleEBzdGF0aWNsaWJzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEP 67 | ADCCAQoCggEBANg4ztDtnNxvZW+OD6SFqQg9U0l9Za8Ept0Cn32JRDAach0vJtV3 68 | LS746M1v2d2nk7W2j8KjS8+ZlNjmmNshbfNs5H2iFU1GCsgkQKPBjgkvf7EdE6eL 69 | cU8jxKKlTC4inD7WSqU/QBuB5eg6fKg1+yT/+DyASioikdmLgEm+vqnsrJUUa8PF 70 | v6JXEYOlQAwvTdTuFhJ9ZjCIgXcVLT51fr/F2qKeSZIz7evu20U0YXf8cvEIZ1ek 71 | hrwuibJWpt7czbPIk3Olqx3omVUUYi71n1HGnusLrsZo4o0/ixa00EiW0LS/FR4n 72 | iXGGXNQM8QuOVoHoNXIpZ/+D0i9R+z0pQ98CAwEAAaNQME4wHQYDVR0OBBYEFE5I 73 | QkxQLFXkCsBZLOhfYqPsGLreMB8GA1UdIwQYMBaAFE5IQkxQLFXkCsBZLOhfYqPs 74 | GLreMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBALOZ2O9NTf1bZKp6 75 | wfWXpylqjXNZScLiP2xO2udOECYaiIpwh/R84RDn2yWKFXi6i/KjwJuQnQPsNhEQ 76 | p2GSG5Fv+KWk/+YcBeygB+O3ztGagVtrH1nBmL5n7qv77kbLEs54Pg51Aeh5LjfC 77 | 3JP8Yav12Qz/Gpg6F2p+5mBmU809yp0vbgh1wa9ZveRogcRzU/2tv4gw1SWxAOkt 78 | 7raL867QkSCBiT21/8tieTJ/QiU5d7C5YNXnearP5J5Hl6mrhuP8wnT8QroUURGO 79 | gC/Etl0wuJ80uU/S5XEeUE9NIkYHRIPIP4Yk9ojGWJeOBgyrlpC/cUAEB3j+U5Nf 80 | wVIJSPg= 81 | -----END CERTIFICATE----- 82 | -------------------------------------------------------------------------------- /test/https_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * File: https_test.cpp 19 | * Author: alex 20 | * 21 | * Created on July 12, 2015, 5:17 PM 22 | */ 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #include "asio.hpp" 31 | 32 | #include "staticlib/pion/tcp_connection.hpp" 33 | #include "staticlib/pion/http_request.hpp" 34 | #include "staticlib/pion/http_response_writer.hpp" 35 | #include "staticlib/pion/http_server.hpp" 36 | 37 | const uint16_t SECONDS_TO_RUN = 1; 38 | const uint16_t TCP_PORT = 8443; 39 | 40 | void test_https() { 41 | auto certpath = "../test/certificates/server/localhost.pem"; 42 | auto pwdcb = [](std::size_t, asio::ssl::context::password_purpose) { 43 | return "test"; 44 | }; 45 | auto capath = "../test/certificates/server/staticlibs_test_ca.cer"; 46 | auto verifier = [](bool, asio::ssl::verify_context&) { 47 | return true; 48 | }; 49 | sl::pion::http_server server(2, TCP_PORT, asio::ip::address_v4::any(), 10000, certpath, pwdcb, capath, verifier); 50 | server.add_handler("GET", "/", 51 | [] (sl::pion::http_request_ptr, sl::pion::response_writer_ptr resp) { 52 | resp->write("Hello pion\n"); 53 | resp->send(std::move(resp)); 54 | }); 55 | server.start(); 56 | std::this_thread::sleep_for(std::chrono::seconds{SECONDS_TO_RUN}); 57 | server.stop(true); 58 | } 59 | 60 | int main() { 61 | try { 62 | test_https(); 63 | } catch (const std::exception& e) { 64 | std::cout << e.what() << std::endl; 65 | return 1; 66 | } 67 | return 0; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /test/pion_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * File: pion_test.cpp 19 | * Author: alex 20 | * 21 | * Created on March 3, 2015, 9:22 AM 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "asio.hpp" 34 | 35 | #include "staticlib/io.hpp" 36 | #include "staticlib/support.hpp" 37 | 38 | #include "staticlib/pion/logger.hpp" 39 | #include "staticlib/pion/http_response_writer.hpp" 40 | #include "staticlib/pion/http_server.hpp" 41 | 42 | const uint16_t SECONDS_TO_RUN = 1; 43 | const uint16_t TCP_PORT = 8080; 44 | 45 | std::string page = R"( 46 | 47 | 48 | 73 | 74 | 75 | 77 |
78 |
79 | 81 |
82 |
83 | 84 | 85 | 86 | 87 | 88 | )"; 89 | 90 | void hello_service(sl::pion::http_request_ptr, sl::pion::response_writer_ptr resp) { 91 | resp->write("Hello World!\n"); 92 | resp->send(std::move(resp)); 93 | } 94 | 95 | void hello_service_post(sl::pion::http_request_ptr, sl::pion::response_writer_ptr resp) { 96 | resp->write("Hello POST!\n"); 97 | resp->send(std::move(resp)); 98 | } 99 | 100 | void wspage(sl::pion::http_request_ptr, sl::pion::response_writer_ptr resp) { 101 | resp->write_nocopy(page); 102 | resp->send(std::move(resp)); 103 | } 104 | 105 | void wsopen(sl::pion::websocket_ptr ws) { 106 | std::cout << "open" << std::endl; 107 | ws->write("open"); 108 | ws->send(std::move(ws)); 109 | } 110 | 111 | void wsmsg(sl::pion::websocket_ptr ws) { 112 | auto src = ws->message_data(); 113 | auto sink = sl::io::string_sink(); 114 | sl::io::copy_all(src, sink); 115 | ws->write(sink.get_string()); 116 | ws->send(std::move(ws)); 117 | } 118 | 119 | void wsclose(sl::pion::websocket_ptr ws) { 120 | (void) ws; 121 | std::cout << "close" << std::endl; 122 | } 123 | 124 | class file_writer { 125 | mutable std::unique_ptr stream; 126 | 127 | public: 128 | // copy constructor is required due to std::function limitations 129 | // but it doesn't used by server implementation 130 | // move-only payload handlers can use move logic 131 | // instead of copy one (with mutable member fields) 132 | // in MSVC only moved-to instance will be used 133 | // in GCC copy constructor won't be called at all 134 | file_writer(const file_writer& other) : 135 | stream(std::move(other.stream)) { } 136 | 137 | file_writer& operator=(const file_writer&) = delete; 138 | 139 | file_writer(file_writer&& other) : 140 | stream(std::move(other.stream)) { } 141 | 142 | file_writer& operator=(file_writer&&) = delete; 143 | 144 | file_writer(const std::string& filename) { 145 | stream = std::unique_ptr{new std::ofstream{filename, std::ios::out | std::ios::binary}}; 146 | stream->exceptions(std::ofstream::failbit | std::ofstream::badbit); 147 | } 148 | 149 | void operator()(const char* s, std::size_t n) { 150 | stream->write(s, n); 151 | } 152 | 153 | void close() { 154 | std::cout << "I am closed" << std::endl; 155 | stream->close(); 156 | } 157 | }; 158 | 159 | class file_sender { 160 | sl::pion::response_writer_ptr writer; 161 | std::ifstream stream; 162 | std::array buf; 163 | 164 | public: 165 | file_sender(const std::string& filename, sl::pion::response_writer_ptr writer) : 166 | writer(std::move(writer)), 167 | stream(filename, std::ios::in | std::ios::binary) { 168 | stream.exceptions(std::ifstream::badbit); 169 | } 170 | 171 | static void send(std::unique_ptr self) { 172 | std::error_code ec; 173 | handle_write(std::move(self), ec, 0); 174 | } 175 | 176 | static void handle_write(std::unique_ptr self, 177 | const std::error_code& ec, std::size_t /* bytes_written */) { 178 | if (!ec) { 179 | self->stream.read(self->buf.data(), self->buf.size()); 180 | self->writer->clear(); 181 | self->writer->write_nocopy({self->buf.data(), self->stream.gcount()}); 182 | if (self->stream) { 183 | auto& wr = self->writer; 184 | auto self_shared = sl::support::make_shared_with_release_deleter(self.release()); 185 | wr->send_chunk( 186 | [self_shared](const std::error_code& ec, size_t bt) { 187 | auto self = sl::support::make_unique_from_shared_with_release_deleter(self_shared); 188 | if (self.get()) { 189 | handle_write(std::move(self), ec, bt); 190 | } 191 | }); 192 | } else { 193 | self->writer->send_final_chunk(std::move(self->writer)); 194 | } 195 | } else { 196 | // make sure it will get closed 197 | self->writer->get_connection()->set_lifecycle(sl::pion::tcp_connection::lifecycle::close); 198 | } 199 | } 200 | }; 201 | 202 | void file_upload_resource(sl::pion::http_request_ptr req, sl::pion::response_writer_ptr resp) { 203 | auto ph = req->get_payload_handler(); 204 | if (ph) { 205 | ph->close(); 206 | } else { 207 | std::cout << "No payload handler found in main handler" << std::endl; 208 | } 209 | auto fs = sl::support::make_unique("uploaded.dat", std::move(resp)); 210 | fs->send(std::move(fs)); 211 | } 212 | 213 | file_writer file_upload_payload_handler_creator(sl::pion::http_request_ptr& req) { 214 | (void) req; 215 | return file_writer{"uploaded.dat"}; 216 | } 217 | 218 | void test_pion() { 219 | // pion 220 | sl::pion::http_server server(4, TCP_PORT); 221 | server.add_handler("GET", "/hello", hello_service); 222 | server.add_handler("POST", "/hello/post", hello_service_post); 223 | server.add_handler("POST", "/fu", file_upload_resource); 224 | server.add_payload_handler("POST", "/fu", file_upload_payload_handler_creator); 225 | server.add_handler("POST", "/fu1", file_upload_resource); 226 | server.get_scheduler().set_thread_stop_hook([]() STATICLIB_NOEXCEPT { 227 | std::cout << "Thread stopped. " << std::endl; 228 | }); 229 | server.add_handler("GET", "/wspage.html", wspage); 230 | server.add_websocket_handler("WSOPEN", "/hello", wsopen); 231 | server.add_websocket_handler("WSMESSAGE", "/hello", wsmsg); 232 | server.add_websocket_handler("WSCLOSE", "/hello", wsclose); 233 | server.start(); 234 | std::this_thread::sleep_for(std::chrono::seconds(SECONDS_TO_RUN)); 235 | // for (size_t i = 0; i < SECONDS_TO_RUN; i++) { 236 | // if (0 == i % 10) { 237 | // auto msg = std::string("ping") + sl::support::to_string(i); 238 | // server.broadcast_websocket("/hello", msg); 239 | // } 240 | // std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 241 | // } 242 | server.stop(); 243 | } 244 | 245 | int main() { 246 | try { 247 | test_pion(); 248 | } catch (const std::exception& e) { 249 | std::cout << e.what() << std::endl; 250 | return 1; 251 | } 252 | return 0; 253 | } 254 | -------------------------------------------------------------------------------- /test/websocket_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018, alex at staticlibs.net 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * File: websocket_test.cpp 19 | * Author: alex 20 | * 21 | * Created on June 19, 2018, 10:45 AM 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "asio.hpp" 31 | 32 | #include "staticlib/config/assert.hpp" 33 | #include "staticlib/io.hpp" 34 | #include "staticlib/support.hpp" 35 | #include "staticlib/websocket.hpp" 36 | 37 | #include "staticlib/pion/http_server.hpp" 38 | 39 | const uint16_t TCP_PORT = 8080; 40 | 41 | void wsopen(sl::pion::websocket_ptr ws) { 42 | std::cout << "open" << std::endl; 43 | ws->write("open"); 44 | ws->send(std::move(ws)); 45 | } 46 | 47 | void wsmsg(sl::pion::websocket_ptr ws) { 48 | auto src = ws->message_data(); 49 | auto sink = sl::io::string_sink(); 50 | sl::io::copy_all(src, sink); 51 | if ("closeme" == sink.get_string()) { 52 | ws->close(std::move(ws)); 53 | } else { 54 | ws->write(sink.get_string()); 55 | ws->send(std::move(ws)); 56 | } 57 | } 58 | 59 | void wsclose(sl::pion::websocket_ptr ws) { 60 | (void) ws; 61 | std::cout << "closed" << std::endl; 62 | } 63 | 64 | std::string make_handshake() { 65 | auto res = sl::websocket::handshake::make_request_line("/mirror"); 66 | auto vec = sl::websocket::handshake::make_request_headers( 67 | "127.0.0.1", TCP_PORT, sl::io::string_from_hex("0102030405060708090a0b0c0d0e0f10")); 68 | for (auto& el : vec) { 69 | res += el.first; 70 | res += ": "; 71 | res += el.second; 72 | res += "\r\n"; 73 | } 74 | res += "\r\n"; 75 | return res; 76 | } 77 | 78 | std::string make_frame(const std::string& msg, bool final = true, bool cont = false) { 79 | std::array hbuf; 80 | auto ftype = cont ? sl::websocket::frame_type::continuation : sl::websocket::frame_type::text; 81 | auto header = sl::websocket::frame::make_header(hbuf, ftype, msg.size(), true, !final); 82 | auto res = std::string(header.data(), header.size()); 83 | auto mask = 0x12345678; 84 | char* mask_ptr = reinterpret_cast(std::addressof(mask)); 85 | for (size_t i = 0; i < 4; i++) { 86 | res.push_back(mask_ptr[3-i]); 87 | } 88 | auto msg_masked = std::string(); 89 | msg_masked.resize(msg.size()); 90 | for (size_t i = 0; i < msg.size(); i++) { 91 | msg_masked[i] = msg[i] ^ mask_ptr[3 - i%4]; 92 | } 93 | res += msg_masked; 94 | return res; 95 | } 96 | 97 | std::string receive(asio::ip::tcp::socket& socket) { 98 | auto buf = std::string(); 99 | buf.resize(1024); 100 | auto buf_len = socket.receive(asio::buffer(std::addressof(buf.front()), buf.length())); 101 | buf.resize(buf_len); 102 | auto frame = sl::websocket::frame({buf.data(), buf.length()}); 103 | return std::string(frame.payload().data(), frame.payload().size()); 104 | } 105 | 106 | void check_hello(asio::ip::tcp::socket& socket) { 107 | auto msg = std::string("hello"); 108 | auto hello = make_frame(msg); 109 | socket.send(asio::buffer(hello)); 110 | slassert(msg == receive(socket)); 111 | } 112 | 113 | void check_tcp_fragment_1_byte(asio::ip::tcp::socket& socket) { 114 | auto msg = std::string("hello"); 115 | auto hello = make_frame(msg); 116 | for (size_t i = 0; i < hello.length(); i++) { 117 | socket.send(asio::buffer(hello.data() + i, 1)); 118 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 119 | } 120 | slassert(msg == receive(socket)); 121 | } 122 | 123 | void check_tcp_fragment_split(asio::ip::tcp::socket& socket) { 124 | auto msg1 = std::string("hello"); 125 | auto hello = make_frame(msg1); 126 | auto msg2 = std::string("bye"); 127 | auto bye = make_frame(msg2); 128 | auto send_buf = hello + bye; 129 | socket.send(asio::buffer(send_buf.data(), send_buf.length() - 1)); 130 | slassert(msg1 == receive(socket)); 131 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 132 | socket.send(asio::buffer(send_buf.data() + (send_buf.length() - 1), 1)); 133 | slassert(msg2 == receive(socket)); 134 | } 135 | 136 | void check_continuation(asio::ip::tcp::socket& socket) { 137 | auto msg = std::string("hello"); 138 | auto he = make_frame(msg.substr(0, 2), false, false); 139 | auto l = make_frame(msg.substr(2, 1), false, true); 140 | auto lo = make_frame(msg.substr(3, 2), true, true); 141 | auto send_buf = he + l + lo; 142 | socket.send(asio::buffer(send_buf)); 143 | slassert(msg == receive(socket)); 144 | } 145 | 146 | void check_broadcast(sl::pion::http_server& server, asio::ip::tcp::socket& socket) { 147 | auto msg = std::string("hello_broadcast"); 148 | server.broadcast_websocket("/mirror", msg); 149 | slassert(msg == receive(socket)); 150 | } 151 | 152 | void check_long(asio::ip::tcp::socket& socket) { 153 | auto msg = std::string(); 154 | for(size_t i = 0; msg.size() < (1<<17); i++) { 155 | msg += sl::support::to_string(i); 156 | } 157 | auto numbers = make_frame(msg); 158 | socket.send(asio::buffer(numbers)); 159 | auto buf = std::string(); 160 | buf.resize(numbers.size() - 4); 161 | size_t received = 0; 162 | while (received < buf.length()) { 163 | received += socket.receive(asio::buffer(std::addressof(buf.front()) + received, buf.length() - received)); 164 | } 165 | auto frame = sl::websocket::frame({buf.data(), buf.length()}); 166 | auto retmsg = std::string(frame.payload().data(), frame.payload().size()); 167 | slassert(msg == retmsg); 168 | } 169 | 170 | void check_close(asio::ip::tcp::socket& socket) { 171 | auto msg = std::string("closeme"); 172 | auto hello = make_frame(msg); 173 | socket.send(asio::buffer(hello)); 174 | auto resp = receive(socket); 175 | slassert("03e8" == sl::io::hex_from_string(resp)); 176 | } 177 | 178 | void test_websocket() { 179 | // start server 180 | sl::pion::http_server server(2, TCP_PORT); 181 | // server.add_websocket_handler("WSOPEN", "/mirror", wsopen); 182 | server.add_websocket_handler("WSMESSAGE", "/mirror", wsmsg); 183 | // server.add_websocket_handler("WSCLOSE", "/mirror", wsclose); 184 | server.start(); 185 | 186 | // connect to server 187 | asio::io_service io_service; 188 | asio::ip::tcp::socket socket{io_service}; 189 | asio::ip::tcp::endpoint endpoint{asio::ip::address_v4::from_string("127.0.0.1"), TCP_PORT}; 190 | socket.connect(endpoint); 191 | 192 | // ws handshake 193 | auto buf = std::string(); 194 | buf.resize(1024); 195 | auto handshake = make_handshake(); 196 | socket.send(asio::buffer(handshake)); 197 | socket.receive(asio::buffer(std::addressof(buf.front()), buf.length())); 198 | 199 | // checks 200 | // for (size_t i = 0; i < 3; i++) { 201 | check_hello(socket); 202 | check_tcp_fragment_1_byte(socket); 203 | check_tcp_fragment_split(socket); 204 | check_continuation(socket); 205 | check_broadcast(server, socket); 206 | check_long(socket); 207 | // } 208 | check_close(socket); 209 | 210 | socket.close(); 211 | server.stop(); 212 | } 213 | 214 | int main() { 215 | try { 216 | test_websocket(); 217 | } catch (const std::exception& e) { 218 | std::cout << e.what() << std::endl; 219 | return 1; 220 | } 221 | return 0; 222 | } 223 | --------------------------------------------------------------------------------