├── web
├── test.html
└── index.html
├── .clang-format
├── .gitignore
├── .travis.yml
├── tests
├── CMakeLists.txt
├── status_code_test.cpp
├── crypto_test.cpp
├── parse_test.cpp
└── io_test.cpp
├── LICENSE
├── README.md
├── server_https.hpp
├── CMakeLists.txt
├── client_https.hpp
├── status_code.hpp
├── crypto.hpp
├── http_examples.cpp
├── https_examples.cpp
├── utility.hpp
├── client_http.hpp
└── server_http.hpp
/web/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Simple-Web-Server html-file
4 |
5 |
6 | This is the content of test.html
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Simple-Web-Server html-file
4 |
5 |
6 | This is the content of index.html
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.clang-format:
--------------------------------------------------------------------------------
1 | IndentWidth: 2
2 | AccessModifierOffset: -2
3 | UseTab: Never
4 | ColumnLimit: 0
5 | MaxEmptyLinesToKeep: 2
6 | SpaceBeforeParens: Never
7 | BreakBeforeBraces: Custom
8 | BraceWrapping: {BeforeElse: true, BeforeCatch: true}
9 | NamespaceIndentation: All
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # https://github.com/github/gitignore/blob/master/CMake.gitignore
2 | CMakeCache.txt
3 | CMakeFiles
4 | CMakeScripts
5 | Makefile
6 | cmake_install.cmake
7 | install_manifest.txt
8 | *.cmake
9 | #Additions to https://github.com/github/gitignore/blob/master/CMake.gitignore
10 | Testing
11 | compile_commands.json
12 | .usages_clang
13 |
14 | *.crt
15 | *.key
16 |
17 | # executables
18 | http_examples
19 | https_examples
20 | io_test
21 | parse_test
22 | crypto_test
23 | status_code_test
24 |
25 | # Visual Studio 2015/2017 cache/options directory
26 | .vs
27 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 |
3 | services:
4 | - docker
5 |
6 | script:
7 | - sudo docker run -it -v "$PWD:/repository" eidheim/testing sh -c "
8 | cd /repository && mkdir build && cd build &&
9 | scan-build cmake -DCMAKE_CXX_FLAGS=-Werror .. &&
10 | scan-build --status-bugs make &&
11 | rm -r * &&
12 | CXX=clang++ cmake -DCMAKE_CXX_FLAGS=-Werror .. &&
13 | make &&
14 | rm -r * &&
15 | CXX=g++ cmake -DCMAKE_CXX_FLAGS=-Werror .. &&
16 | make &&
17 | CTEST_OUTPUT_ON_FAILURE=1 make test &&
18 | rm -r * &&
19 | CXX=g++ cmake -DUSE_STANDALONE_ASIO=ON -DCMAKE_CXX_FLAGS=\"-Werror -O3\" .. &&
20 | make &&
21 | CTEST_OUTPUT_ON_FAILURE=1 make test
22 | "
23 |
--------------------------------------------------------------------------------
/tests/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | if(NOT MSVC)
2 | add_compile_options(-fno-access-control)
3 |
4 | add_executable(io_test io_test.cpp)
5 | target_link_libraries(io_test simple-web-server)
6 | add_test(io_test io_test)
7 |
8 | add_executable(parse_test parse_test.cpp)
9 | target_link_libraries(parse_test simple-web-server)
10 | add_test(parse_test parse_test)
11 | endif()
12 |
13 | if(OPENSSL_FOUND)
14 | add_executable(crypto_test crypto_test.cpp)
15 | target_link_libraries(crypto_test simple-web-server)
16 | add_test(crypto_test crypto_test)
17 | endif()
18 |
19 | add_executable(status_code_test status_code_test.cpp)
20 | target_link_libraries(status_code_test simple-web-server)
21 | add_test(status_code_test status_code_test)
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014-2018 Ole Christian Eidheim
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/tests/status_code_test.cpp:
--------------------------------------------------------------------------------
1 | #include "status_code.hpp"
2 | #include
3 |
4 | using namespace SimpleWeb;
5 |
6 |
7 | int main() {
8 | assert(status_code("000 Error") == StatusCode::unknown);
9 | assert(status_code(StatusCode::unknown) == "");
10 | assert(status_code("100 Continue") == StatusCode::information_continue);
11 | assert(status_code(StatusCode::information_continue) == "100 Continue");
12 | assert(status_code("200 OK") == StatusCode::success_ok);
13 | assert(status_code(StatusCode::success_ok) == "200 OK");
14 | assert(status_code("208 Already Reported") == StatusCode::success_already_reported);
15 | assert(status_code(StatusCode::success_already_reported) == "208 Already Reported");
16 | assert(status_code("308 Permanent Redirect") == StatusCode::redirection_permanent_redirect);
17 | assert(status_code(StatusCode::redirection_permanent_redirect) == "308 Permanent Redirect");
18 | assert(status_code("404 Not Found") == StatusCode::client_error_not_found);
19 | assert(status_code(StatusCode::client_error_not_found) == "404 Not Found");
20 | assert(status_code("502 Bad Gateway") == StatusCode::server_error_bad_gateway);
21 | assert(status_code(StatusCode::server_error_bad_gateway) == "502 Bad Gateway");
22 | assert(status_code("504 Gateway Timeout") == StatusCode::server_error_gateway_timeout);
23 | assert(status_code(StatusCode::server_error_gateway_timeout) == "504 Gateway Timeout");
24 | assert(status_code("511 Network Authentication Required") == StatusCode::server_error_network_authentication_required);
25 | assert(status_code(StatusCode::server_error_network_authentication_required) == "511 Network Authentication Required");
26 | }
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **_This project has moved to https://gitlab.com/eidheim/Simple-Web-Server._**
2 |
3 | Simple-Web-Server
4 | =================
5 |
6 | A very simple, fast, multithreaded, platform independent HTTP and HTTPS server and client library implemented using C++11 and Asio (both Boost.Asio and standalone Asio can be used). Created to be an easy way to make REST resources available from C++ applications.
7 |
8 | See https://gitlab.com/eidheim/Simple-WebSocket-Server for an easy way to make WebSocket/WebSocket Secure endpoints in C++. Also, feel free to check out the new C++ IDE supporting C++11/14/17: https://gitlab.com/cppit/jucipp.
9 |
10 | ### Features
11 |
12 | * Asynchronous request handling
13 | * Thread pool if needed
14 | * Platform independent
15 | * HTTPS support
16 | * HTTP persistent connection (for HTTP/1.1)
17 | * Client supports chunked transfer encoding
18 | * Timeouts, if any of Server::timeout_request and Server::timeout_content are >0 (default: Server::timeout_request=5 seconds, and Server::timeout_content=300 seconds)
19 | * Simple way to add REST resources using regex for path, and anonymous functions
20 |
21 | ### Usage
22 |
23 | See http_examples.cpp or https_examples.cpp for example usage.
24 |
25 | See particularly the JSON-POST (using Boost.PropertyTree) and the GET /match/[number] examples, which are most relevant.
26 |
27 | ### Dependencies
28 |
29 | * Boost.Asio or standalone Asio
30 | * Boost is required to compile the examples
31 | * For HTTPS: OpenSSL libraries
32 |
33 | ### Compile and run
34 |
35 | Compile with a C++11 compliant compiler:
36 | ```sh
37 | mkdir build
38 | cd build
39 | cmake ..
40 | make
41 | cd ..
42 | ```
43 |
44 | #### HTTP
45 |
46 | Run the server and client examples: `./build/http_examples`
47 |
48 | Direct your favorite browser to for instance http://localhost:8080/
49 |
50 | #### HTTPS
51 |
52 | Before running the server, an RSA private key (server.key) and an SSL certificate (server.crt) must be created. Follow, for instance, the instructions given here (for a self-signed certificate): http://www.akadia.com/services/ssh_test_certificate.html
53 |
54 | Run the server and client examples: `./build/https_examples`
55 |
56 | Direct your favorite browser to for instance https://localhost:8080/
57 |
58 |
--------------------------------------------------------------------------------
/server_https.hpp:
--------------------------------------------------------------------------------
1 | #ifndef SERVER_HTTPS_HPP
2 | #define SERVER_HTTPS_HPP
3 |
4 | #include "server_http.hpp"
5 |
6 | #ifdef USE_STANDALONE_ASIO
7 | #include
8 | #else
9 | #include
10 | #endif
11 |
12 | #include
13 | #include
14 |
15 | namespace SimpleWeb {
16 | using HTTPS = asio::ssl::stream;
17 |
18 | template <>
19 | class Server : public ServerBase {
20 | bool set_session_id_context = false;
21 |
22 | public:
23 | Server(const std::string &cert_file, const std::string &private_key_file, const std::string &verify_file = std::string())
24 | : ServerBase::ServerBase(443), context(asio::ssl::context::tlsv12) {
25 | context.use_certificate_chain_file(cert_file);
26 | context.use_private_key_file(private_key_file, asio::ssl::context::pem);
27 |
28 | if(verify_file.size() > 0) {
29 | context.load_verify_file(verify_file);
30 | context.set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert | asio::ssl::verify_client_once);
31 | set_session_id_context = true;
32 | }
33 | }
34 |
35 | protected:
36 | asio::ssl::context context;
37 |
38 | void after_bind() override {
39 | if(set_session_id_context) {
40 | // Creating session_id_context from address:port but reversed due to small SSL_MAX_SSL_SESSION_ID_LENGTH
41 | auto session_id_context = std::to_string(acceptor->local_endpoint().port()) + ':';
42 | session_id_context.append(config.address.rbegin(), config.address.rend());
43 | SSL_CTX_set_session_id_context(context.native_handle(), reinterpret_cast(session_id_context.data()),
44 | std::min(session_id_context.size(), SSL_MAX_SSL_SESSION_ID_LENGTH));
45 | }
46 | }
47 |
48 | void accept() override {
49 | auto connection = create_connection(*io_service, context);
50 |
51 | acceptor->async_accept(connection->socket->lowest_layer(), [this, connection](const error_code &ec) {
52 | auto lock = connection->handler_runner->continue_lock();
53 | if(!lock)
54 | return;
55 |
56 | if(ec != asio::error::operation_aborted)
57 | this->accept();
58 |
59 | auto session = std::make_shared(config.max_request_streambuf_size, connection);
60 |
61 | if(!ec) {
62 | asio::ip::tcp::no_delay option(true);
63 | error_code ec;
64 | session->connection->socket->lowest_layer().set_option(option, ec);
65 |
66 | session->connection->set_timeout(config.timeout_request);
67 | session->connection->socket->async_handshake(asio::ssl::stream_base::server, [this, session](const error_code &ec) {
68 | session->connection->cancel_timeout();
69 | auto lock = session->connection->handler_runner->continue_lock();
70 | if(!lock)
71 | return;
72 | if(!ec)
73 | this->read(session);
74 | else if(this->on_error)
75 | this->on_error(session->request, ec);
76 | });
77 | }
78 | else if(this->on_error)
79 | this->on_error(session->request, ec);
80 | });
81 | }
82 | };
83 | } // namespace SimpleWeb
84 |
85 | #endif /* SERVER_HTTPS_HPP */
86 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required (VERSION 3.0)
2 |
3 | project (Simple-Web-Server)
4 |
5 | option(USE_STANDALONE_ASIO "set ON to use standalone Asio instead of Boost.Asio" OFF)
6 | option(BUILD_TESTING "set ON to build library tests" OFF)
7 |
8 | if(NOT MSVC)
9 | add_compile_options(-std=c++11 -Wall -Wextra -Wsign-conversion)
10 | else()
11 | add_compile_options(/W1)
12 | endif()
13 |
14 | add_library(simple-web-server INTERFACE)
15 |
16 | target_include_directories(simple-web-server INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
17 |
18 | find_package(Threads REQUIRED)
19 | target_link_libraries(simple-web-server INTERFACE ${CMAKE_THREAD_LIBS_INIT})
20 |
21 | # TODO 2020 when Debian Jessie LTS ends:
22 | # Remove Boost system, thread, regex components; use Boost:: aliases; remove Boost target_include_directories
23 | if(USE_STANDALONE_ASIO)
24 | target_compile_definitions(simple-web-server INTERFACE USE_STANDALONE_ASIO)
25 | include(CheckIncludeFileCXX)
26 | CHECK_INCLUDE_FILE_CXX(asio.hpp HAVE_ASIO)
27 | if(NOT HAVE_ASIO)
28 | message(FATAL_ERROR "Standalone Asio not found")
29 | endif()
30 | else()
31 | find_package(Boost 1.53.0 COMPONENTS system thread REQUIRED)
32 | target_link_libraries(simple-web-server INTERFACE ${Boost_LIBRARIES})
33 | target_include_directories(simple-web-server INTERFACE ${Boost_INCLUDE_DIR})
34 | if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
35 | target_compile_definitions(simple-web-server INTERFACE USE_BOOST_REGEX)
36 | find_package(Boost 1.53.0 COMPONENTS regex REQUIRED)
37 | target_link_libraries(simple-web-server INTERFACE ${Boost_LIBRARIES})
38 | target_include_directories(simple-web-server INTERFACE ${Boost_INCLUDE_DIR})
39 | endif()
40 | endif()
41 | if(WIN32)
42 | target_link_libraries(simple-web-server INTERFACE ws2_32 wsock32)
43 | endif()
44 |
45 | if(APPLE)
46 | set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl")
47 | endif()
48 | find_package(OpenSSL)
49 | if(OPENSSL_FOUND)
50 | target_compile_definitions(simple-web-server INTERFACE HAVE_OPENSSL)
51 | target_link_libraries(simple-web-server INTERFACE ${OPENSSL_LIBRARIES})
52 | target_include_directories(simple-web-server INTERFACE ${OPENSSL_INCLUDE_DIR})
53 | endif()
54 |
55 | # If Simple-Web-Server is not a sub-project:
56 | if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
57 | add_executable(http_examples http_examples.cpp)
58 | target_link_libraries(http_examples simple-web-server)
59 | find_package(Boost 1.53.0 COMPONENTS system thread filesystem REQUIRED)
60 | target_link_libraries(http_examples ${Boost_LIBRARIES})
61 | target_include_directories(http_examples PRIVATE ${Boost_INCLUDE_DIR})
62 | if(OPENSSL_FOUND)
63 | add_executable(https_examples https_examples.cpp)
64 | target_link_libraries(https_examples simple-web-server)
65 | target_link_libraries(https_examples ${Boost_LIBRARIES})
66 | target_include_directories(https_examples PRIVATE ${Boost_INCLUDE_DIR})
67 | endif()
68 |
69 | set(BUILD_TESTING ON)
70 |
71 | install(FILES server_http.hpp client_http.hpp server_https.hpp client_https.hpp crypto.hpp utility.hpp status_code.hpp DESTINATION include/simple-web-server)
72 | endif()
73 |
74 | if(BUILD_TESTING)
75 | enable_testing()
76 | add_subdirectory(tests)
77 | endif()
78 |
--------------------------------------------------------------------------------
/tests/crypto_test.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "crypto.hpp"
5 |
6 | using namespace std;
7 | using namespace SimpleWeb;
8 |
9 | const vector> base64_string_tests = {
10 | {"", ""},
11 | {"f", "Zg=="},
12 | {"fo", "Zm8="},
13 | {"foo", "Zm9v"},
14 | {"foob", "Zm9vYg=="},
15 | {"fooba", "Zm9vYmE="},
16 | {"foobar", "Zm9vYmFy"},
17 | {"The itsy bitsy spider climbed up the waterspout.\r\nDown came the rain\r\nand washed the spider out.\r\nOut came the sun\r\nand dried up all the rain\r\nand the itsy bitsy spider climbed up the spout again.",
18 | "VGhlIGl0c3kgYml0c3kgc3BpZGVyIGNsaW1iZWQgdXAgdGhlIHdhdGVyc3BvdXQuDQpEb3duIGNhbWUgdGhlIHJhaW4NCmFuZCB3YXNoZWQgdGhlIHNwaWRlciBvdXQuDQpPdXQgY2FtZSB0aGUgc3VuDQphbmQgZHJpZWQgdXAgYWxsIHRoZSByYWluDQphbmQgdGhlIGl0c3kgYml0c3kgc3BpZGVyIGNsaW1iZWQgdXAgdGhlIHNwb3V0IGFnYWluLg=="}};
19 |
20 | const vector> md5_string_tests = {
21 | {"", "d41d8cd98f00b204e9800998ecf8427e"},
22 | {"The quick brown fox jumps over the lazy dog", "9e107d9d372bb6826bd81d3542a419d6"}};
23 |
24 | const vector> sha1_string_tests = {
25 | {"", "da39a3ee5e6b4b0d3255bfef95601890afd80709"},
26 | {"The quick brown fox jumps over the lazy dog", "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"}};
27 |
28 | const vector> sha256_string_tests = {
29 | {"", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
30 | {"The quick brown fox jumps over the lazy dog", "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592"}};
31 |
32 | const vector> sha512_string_tests = {
33 | {"", "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"},
34 | {"The quick brown fox jumps over the lazy dog", "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6"}};
35 |
36 | int main() {
37 | for(auto &string_test : base64_string_tests) {
38 | assert(Crypto::Base64::encode(string_test.first) == string_test.second);
39 | assert(Crypto::Base64::decode(string_test.second) == string_test.first);
40 | }
41 |
42 | for(auto &string_test : md5_string_tests) {
43 | assert(Crypto::to_hex_string(Crypto::md5(string_test.first)) == string_test.second);
44 | stringstream ss(string_test.first);
45 | assert(Crypto::to_hex_string(Crypto::md5(ss)) == string_test.second);
46 | }
47 |
48 | for(auto &string_test : sha1_string_tests) {
49 | assert(Crypto::to_hex_string(Crypto::sha1(string_test.first)) == string_test.second);
50 | stringstream ss(string_test.first);
51 | assert(Crypto::to_hex_string(Crypto::sha1(ss)) == string_test.second);
52 | }
53 |
54 | for(auto &string_test : sha256_string_tests) {
55 | assert(Crypto::to_hex_string(Crypto::sha256(string_test.first)) == string_test.second);
56 | stringstream ss(string_test.first);
57 | assert(Crypto::to_hex_string(Crypto::sha256(ss)) == string_test.second);
58 | }
59 |
60 | for(auto &string_test : sha512_string_tests) {
61 | assert(Crypto::to_hex_string(Crypto::sha512(string_test.first)) == string_test.second);
62 | stringstream ss(string_test.first);
63 | assert(Crypto::to_hex_string(Crypto::sha512(ss)) == string_test.second);
64 | }
65 |
66 | // Testing iterations
67 | assert(Crypto::to_hex_string(Crypto::sha1("Test", 1)) == "640ab2bae07bedc4c163f679a746f7ab7fb5d1fa");
68 | assert(Crypto::to_hex_string(Crypto::sha1("Test", 2)) == "af31c6cbdecd88726d0a9b3798c71ef41f1624d5");
69 | stringstream ss("Test");
70 | assert(Crypto::to_hex_string(Crypto::sha1(ss, 2)) == "af31c6cbdecd88726d0a9b3798c71ef41f1624d5");
71 |
72 | assert(Crypto::to_hex_string(Crypto::pbkdf2("Password", "Salt", 4096, 128 / 8)) == "f66df50f8aaa11e4d9721e1312ff2e66");
73 | assert(Crypto::to_hex_string(Crypto::pbkdf2("Password", "Salt", 8192, 512 / 8)) == "a941ccbc34d1ee8ebbd1d34824a419c3dc4eac9cbc7c36ae6c7ca8725e2b618a6ad22241e787af937b0960cf85aa8ea3a258f243e05d3cc9b08af5dd93be046c");
74 | }
75 |
--------------------------------------------------------------------------------
/client_https.hpp:
--------------------------------------------------------------------------------
1 | #ifndef CLIENT_HTTPS_HPP
2 | #define CLIENT_HTTPS_HPP
3 |
4 | #include "client_http.hpp"
5 |
6 | #ifdef USE_STANDALONE_ASIO
7 | #include
8 | #else
9 | #include
10 | #endif
11 |
12 | namespace SimpleWeb {
13 | using HTTPS = asio::ssl::stream;
14 |
15 | template <>
16 | class Client : public ClientBase {
17 | public:
18 | Client(const std::string &server_port_path, bool verify_certificate = true, const std::string &cert_file = std::string(),
19 | const std::string &private_key_file = std::string(), const std::string &verify_file = std::string())
20 | : ClientBase::ClientBase(server_port_path, 443), context(asio::ssl::context::tlsv12) {
21 | if(cert_file.size() > 0 && private_key_file.size() > 0) {
22 | context.use_certificate_chain_file(cert_file);
23 | context.use_private_key_file(private_key_file, asio::ssl::context::pem);
24 | }
25 |
26 | if(verify_certificate)
27 | context.set_verify_callback(asio::ssl::rfc2818_verification(host));
28 |
29 | if(verify_file.size() > 0)
30 | context.load_verify_file(verify_file);
31 | else
32 | context.set_default_verify_paths();
33 |
34 | if(verify_file.size() > 0 || verify_certificate)
35 | context.set_verify_mode(asio::ssl::verify_peer);
36 | else
37 | context.set_verify_mode(asio::ssl::verify_none);
38 | }
39 |
40 | protected:
41 | asio::ssl::context context;
42 |
43 | std::shared_ptr create_connection() noexcept override {
44 | return std::make_shared(handler_runner, config.timeout, *io_service, context);
45 | }
46 |
47 | void connect(const std::shared_ptr &session) override {
48 | if(!session->connection->socket->lowest_layer().is_open()) {
49 | auto resolver = std::make_shared(*io_service);
50 | resolver->async_resolve(*query, [this, session, resolver](const error_code &ec, asio::ip::tcp::resolver::iterator it) {
51 | auto lock = session->connection->handler_runner->continue_lock();
52 | if(!lock)
53 | return;
54 | if(!ec) {
55 | session->connection->set_timeout(this->config.timeout_connect);
56 | asio::async_connect(session->connection->socket->lowest_layer(), it, [this, session, resolver](const error_code &ec, asio::ip::tcp::resolver::iterator /*it*/) {
57 | session->connection->cancel_timeout();
58 | auto lock = session->connection->handler_runner->continue_lock();
59 | if(!lock)
60 | return;
61 | if(!ec) {
62 | asio::ip::tcp::no_delay option(true);
63 | error_code ec;
64 | session->connection->socket->lowest_layer().set_option(option, ec);
65 |
66 | if(!this->config.proxy_server.empty()) {
67 | auto write_buffer = std::make_shared();
68 | std::ostream write_stream(write_buffer.get());
69 | auto host_port = this->host + ':' + std::to_string(this->port);
70 | write_stream << "CONNECT " + host_port + " HTTP/1.1\r\n"
71 | << "Host: " << host_port << "\r\n\r\n";
72 | session->connection->set_timeout(this->config.timeout_connect);
73 | asio::async_write(session->connection->socket->next_layer(), *write_buffer, [this, session, write_buffer](const error_code &ec, std::size_t /*bytes_transferred*/) {
74 | session->connection->cancel_timeout();
75 | auto lock = session->connection->handler_runner->continue_lock();
76 | if(!lock)
77 | return;
78 | if(!ec) {
79 | std::shared_ptr response(new Response(this->config.max_response_streambuf_size));
80 | session->connection->set_timeout(this->config.timeout_connect);
81 | asio::async_read_until(session->connection->socket->next_layer(), response->streambuf, "\r\n\r\n", [this, session, response](const error_code &ec, std::size_t /*bytes_transferred*/) {
82 | session->connection->cancel_timeout();
83 | auto lock = session->connection->handler_runner->continue_lock();
84 | if(!lock)
85 | return;
86 | if((!ec || ec == asio::error::not_found) && response->streambuf.size() == response->streambuf.max_size()) {
87 | session->callback(session->connection, make_error_code::make_error_code(errc::message_size));
88 | return;
89 | }
90 | if(!ec) {
91 | if(!ResponseMessage::parse(response->content, response->http_version, response->status_code, response->header))
92 | session->callback(session->connection, make_error_code::make_error_code(errc::protocol_error));
93 | else {
94 | if(response->status_code.empty() || response->status_code.compare(0, 3, "200") != 0)
95 | session->callback(session->connection, make_error_code::make_error_code(errc::permission_denied));
96 | else
97 | this->handshake(session);
98 | }
99 | }
100 | else
101 | session->callback(session->connection, ec);
102 | });
103 | }
104 | else
105 | session->callback(session->connection, ec);
106 | });
107 | }
108 | else
109 | this->handshake(session);
110 | }
111 | else
112 | session->callback(session->connection, ec);
113 | });
114 | }
115 | else
116 | session->callback(session->connection, ec);
117 | });
118 | }
119 | else
120 | write(session);
121 | }
122 |
123 | void handshake(const std::shared_ptr &session) {
124 | SSL_set_tlsext_host_name(session->connection->socket->native_handle(), this->host.c_str());
125 |
126 | session->connection->set_timeout(this->config.timeout_connect);
127 | session->connection->socket->async_handshake(asio::ssl::stream_base::client, [this, session](const error_code &ec) {
128 | session->connection->cancel_timeout();
129 | auto lock = session->connection->handler_runner->continue_lock();
130 | if(!lock)
131 | return;
132 | if(!ec)
133 | this->write(session);
134 | else
135 | session->callback(session->connection, ec);
136 | });
137 | }
138 | };
139 | } // namespace SimpleWeb
140 |
141 | #endif /* CLIENT_HTTPS_HPP */
142 |
--------------------------------------------------------------------------------
/status_code.hpp:
--------------------------------------------------------------------------------
1 | #ifndef SIMPLE_WEB_STATUS_CODE_HPP
2 | #define SIMPLE_WEB_STATUS_CODE_HPP
3 |
4 | #include