diff options
-rw-r--r-- | .gitlab-ci.yml | 4 | ||||
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | asio_compatibility.hpp | 4 | ||||
-rw-r--r-- | client_ws.hpp | 62 | ||||
-rw-r--r-- | client_wss.hpp | 18 | ||||
-rw-r--r-- | crypto.hpp | 157 | ||||
-rw-r--r-- | server_ws.hpp | 29 | ||||
-rw-r--r-- | server_wss.hpp | 15 | ||||
-rw-r--r-- | tests/parse_test.cpp | 102 | ||||
-rw-r--r-- | utility.hpp | 10 |
10 files changed, 223 insertions, 180 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e9e8b82..9591259 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,10 +17,6 @@ buster: image: "registry.gitlab.com/eidheim/docker-images:buster" <<: *compile_and_test -jessie: - image: "registry.gitlab.com/eidheim/docker-images:jessie" - <<: *compile_and_test - stretch: image: "registry.gitlab.com/eidheim/docker-images:stretch" <<: *compile_and_test diff --git a/CMakeLists.txt b/CMakeLists.txt index 11e11f1..5c83068 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ target_link_libraries(simple-websocket-server INTERFACE ${CMAKE_THREAD_LIBS_INIT # TODO 2020 when Debian Jessie LTS ends: # Remove Boost system, thread, regex components; use Boost::<component> aliases; remove Boost target_include_directories if(USE_STANDALONE_ASIO) - target_compile_definitions(simple-websocket-server INTERFACE USE_STANDALONE_ASIO) + target_compile_definitions(simple-websocket-server INTERFACE ASIO_STANDALONE) find_path(ASIO_PATH asio.hpp) if(NOT ASIO_PATH) message(FATAL_ERROR "Standalone Asio not found") diff --git a/asio_compatibility.hpp b/asio_compatibility.hpp index c2e0b66..5a7007d 100644 --- a/asio_compatibility.hpp +++ b/asio_compatibility.hpp @@ -3,7 +3,7 @@ #include <memory> -#ifdef USE_STANDALONE_ASIO +#ifdef ASIO_STANDALONE #include <asio.hpp> #include <asio/steady_timer.hpp> namespace SimpleWeb { @@ -27,7 +27,7 @@ namespace SimpleWeb { #endif namespace SimpleWeb { -#if(USE_STANDALONE_ASIO && ASIO_VERSION >= 101300) || BOOST_ASIO_VERSION >= 101300 +#if(ASIO_STANDALONE && ASIO_VERSION >= 101300) || BOOST_ASIO_VERSION >= 101300 using io_context = asio::io_context; using resolver_results = asio::ip::tcp::resolver::results_type; using async_connect_endpoint = asio::ip::tcp::endpoint; diff --git a/client_ws.hpp b/client_ws.hpp index e4a26f6..4b1d4e9 100644 --- a/client_ws.hpp +++ b/client_ws.hpp @@ -70,8 +70,8 @@ namespace SimpleWeb { private: template <typename... Args> - Connection(std::shared_ptr<ScopeRunner> handler_runner_, long timeout_idle, Args &&... args) noexcept - : handler_runner(std::move(handler_runner_)), socket(new socket_type(std::forward<Args>(args)...)), timeout_idle(timeout_idle), closed(false) {} + Connection(std::shared_ptr<ScopeRunner> handler_runner_, long timeout_idle, Args &&...args) noexcept + : handler_runner(std::move(handler_runner_)), socket(new socket_type(std::forward<Args>(args)...)), timeout_idle(timeout_idle), close_sent(false) {} std::shared_ptr<ScopeRunner> handler_runner; @@ -84,16 +84,10 @@ namespace SimpleWeb { Mutex timer_mutex; std::unique_ptr<asio::steady_timer> timer GUARDED_BY(timer_mutex); - std::atomic<bool> closed; + std::atomic<bool> close_sent; asio::ip::tcp::endpoint endpoint; // The endpoint is read in SocketClient::upgrade and must be stored so that it can be read reliably in all handlers, including on_error - void close() noexcept { - error_code ec; - socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec); - socket->lowest_layer().cancel(ec); - } - void set_timeout(long seconds = -1) noexcept { bool use_timeout_idle = false; if(seconds == -1) { @@ -113,8 +107,12 @@ namespace SimpleWeb { timer->async_wait([connection_weak, use_timeout_idle](const error_code &ec) { if(!ec) { if(auto connection = connection_weak.lock()) { - if(use_timeout_idle) - connection->send_close(1000, "idle timeout"); // 1000=normal closure + if(use_timeout_idle) { + if(connection->close_sent) + connection->close(); + else + connection->send_close(1000, "idle timeout"); // 1000=normal closure + } else connection->close(); } @@ -240,9 +238,9 @@ namespace SimpleWeb { void send_close(int status, const std::string &reason = "", std::function<void(const error_code &)> callback = nullptr) { // Send close only once (in case close is initiated by client) - if(closed) + if(close_sent) return; - closed = true; + close_sent = true; auto out_message = std::make_shared<OutMessage>(); @@ -255,6 +253,13 @@ namespace SimpleWeb { send(out_message, std::move(callback), 136); } + /// Force close connection. Use `send_close()` instead for standard compliant connection close. + void close() noexcept { + error_code ec; + socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec); + socket->lowest_layer().cancel(ec); + } + const asio::ip::tcp::endpoint &remote_endpoint() const noexcept { return endpoint; } @@ -279,6 +284,8 @@ namespace SimpleWeb { CaseInsensitiveMultimap header; /// Set proxy server (server:port) std::string proxy_server; + /// Set proxy authorization (username:password) + std::string proxy_auth; }; /// Set before calling start(). Config config; @@ -365,22 +372,33 @@ namespace SimpleWeb { } std::pair<std::string, unsigned short> parse_host_port(const std::string &host_port, unsigned short default_port) const noexcept { - std::pair<std::string, unsigned short> parsed_host_port; - std::size_t host_end = host_port.find(':'); - if(host_end == std::string::npos) { - parsed_host_port.first = host_port; - parsed_host_port.second = default_port; + std::string host, port; + host.reserve(host_port.size()); + bool parse_port = false; + int square_count = 0; // To parse IPv6 addresses + for(auto chr : host_port) { + if(chr == '[') + ++square_count; + else if(chr == ']') + --square_count; + else if(square_count == 0 && chr == ':') + parse_port = true; + else if(!parse_port) + host += chr; + else + port += chr; } + + if(port.empty()) + return {std::move(host), default_port}; else { - parsed_host_port.first = host_port.substr(0, host_end); try { - parsed_host_port.second = static_cast<unsigned short>(stoul(host_port.substr(host_end + 1))); + return {std::move(host), static_cast<unsigned short>(std::stoul(port))}; } catch(...) { - parsed_host_port.second = default_port; + return {std::move(host), default_port}; } } - return parsed_host_port; } virtual void connect() = 0; diff --git a/client_wss.hpp b/client_wss.hpp index 55ee929..0d19fc9 100644 --- a/client_wss.hpp +++ b/client_wss.hpp @@ -3,7 +3,7 @@ #include "client_ws.hpp" -#ifdef USE_STANDALONE_ASIO +#ifdef ASIO_STANDALONE #include <asio/ssl.hpp> #else #include <boost/asio/ssl.hpp> @@ -27,7 +27,16 @@ namespace SimpleWeb { SocketClient(const std::string &server_port_path, bool verify_certificate = true, const std::string &certification_file = std::string(), const std::string &private_key_file = std::string(), const std::string &verify_file = std::string()) - : SocketClientBase<WSS>::SocketClientBase(server_port_path, 443), context(asio::ssl::context::tlsv12) { + : SocketClientBase<WSS>::SocketClientBase(server_port_path, 443), +#if(ASIO_STANDALONE && ASIO_VERSION >= 101300) || BOOST_ASIO_VERSION >= 101300 + context(asio::ssl::context::tls_client) { + // Disabling TLS 1.0 and 1.1 (see RFC 8996) + context.set_options(asio::ssl::context::no_tlsv1); + context.set_options(asio::ssl::context::no_tlsv1_1); +#else + context(asio::ssl::context::tlsv12) { +#endif + if(certification_file.size() > 0 && private_key_file.size() > 0) { context.use_certificate_chain_file(certification_file); context.use_private_key_file(private_key_file, asio::ssl::context::pem); @@ -87,7 +96,10 @@ namespace SimpleWeb { std::ostream ostream(streambuf.get()); auto host_port = this->host + ':' + std::to_string(this->port); ostream << "CONNECT " + host_port + " HTTP/1.1\r\n" - << "Host: " << host_port << "\r\n\r\n"; + << "Host: " << host_port << "\r\n"; + if(!this->config.proxy_auth.empty()) + ostream << "Proxy-Authorization: Basic " << Crypto::Base64::encode(this->config.proxy_auth) << "\r\n"; + ostream << "\r\n"; connection->set_timeout(this->config.timeout_request); asio::async_write(connection->socket->next_layer(), *streambuf, [this, connection, streambuf](const error_code &ec, std::size_t /*bytes_transferred*/) { connection->cancel_timeout(); @@ -32,7 +32,7 @@ namespace SimpleWeb { std::string base64; BIO *bio, *b64; - BUF_MEM *bptr = BUF_MEM_new(); + auto bptr = BUF_MEM_new(); b64 = BIO_new(BIO_f_base64()); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); @@ -62,10 +62,8 @@ namespace SimpleWeb { /// Returns Base64 decoded string from base64 input. static std::string decode(const std::string &base64) noexcept { - std::string ascii; + std::string ascii((6 * base64.size()) / 8, '\0'); // The size is a up to two bytes too large. - // Resize ascii, however, the size is a up to two bytes too large. - ascii.resize((6 * base64.size()) / 8); BIO *b64, *bio; b64 = BIO_new(BIO_f_base64()); @@ -99,133 +97,109 @@ namespace SimpleWeb { return hex_stream.str(); } - /// Returns md5 hash value from input string. - static std::string md5(const std::string &input, std::size_t iterations = 1) noexcept { - std::string hash; + /// Return hash value using specific EVP_MD from input string. + static std::string message_digest(const std::string &str, const EVP_MD *evp_md, std::size_t digest_length) noexcept { + std::string md(digest_length, '\0'); + + auto ctx = EVP_MD_CTX_create(); + EVP_MD_CTX_init(ctx); + EVP_DigestInit_ex(ctx, evp_md, nullptr); + EVP_DigestUpdate(ctx, str.data(), str.size()); + EVP_DigestFinal_ex(ctx, reinterpret_cast<unsigned char *>(&md[0]), nullptr); + EVP_MD_CTX_destroy(ctx); + + return md; + } + + /// Return hash value using specific EVP_MD from input stream. + static std::string stream_digest(std::istream &stream, const EVP_MD *evp_md, std::size_t digest_length) noexcept { + std::string md(digest_length, '\0'); + std::unique_ptr<char[]> buffer(new char[buffer_size]); + std::streamsize read_length; - hash.resize(128 / 8); - MD5(reinterpret_cast<const unsigned char *>(&input[0]), input.size(), reinterpret_cast<unsigned char *>(&hash[0])); + auto ctx = EVP_MD_CTX_create(); + EVP_MD_CTX_init(ctx); + EVP_DigestInit_ex(ctx, evp_md, nullptr); + while((read_length = stream.read(buffer.get(), buffer_size).gcount()) > 0) + EVP_DigestUpdate(ctx, buffer.get(), static_cast<std::size_t>(read_length)); + EVP_DigestFinal_ex(ctx, reinterpret_cast<unsigned char *>(&md[0]), nullptr); + EVP_MD_CTX_destroy(ctx); - for(std::size_t c = 1; c < iterations; ++c) - MD5(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0])); + return md; + } + /// Returns md5 hash value from input string. + static std::string md5(const std::string &input, std::size_t iterations = 1) noexcept { + auto evp_md = EVP_md5(); + auto hash = message_digest(input, evp_md, MD5_DIGEST_LENGTH); + for(std::size_t i = 1; i < iterations; ++i) + hash = message_digest(hash, evp_md, MD5_DIGEST_LENGTH); return hash; } /// Returns md5 hash value from input stream. static std::string md5(std::istream &stream, std::size_t iterations = 1) noexcept { - MD5_CTX context; - MD5_Init(&context); - std::streamsize read_length; - std::vector<char> buffer(buffer_size); - while((read_length = stream.read(&buffer[0], buffer_size).gcount()) > 0) - MD5_Update(&context, buffer.data(), static_cast<std::size_t>(read_length)); - std::string hash; - hash.resize(128 / 8); - MD5_Final(reinterpret_cast<unsigned char *>(&hash[0]), &context); - - for(std::size_t c = 1; c < iterations; ++c) - MD5(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0])); - + auto evp_md = EVP_md5(); + auto hash = stream_digest(stream, evp_md, MD5_DIGEST_LENGTH); + for(std::size_t i = 1; i < iterations; ++i) + hash = message_digest(hash, evp_md, MD5_DIGEST_LENGTH); return hash; } /// Returns sha1 hash value from input string. static std::string sha1(const std::string &input, std::size_t iterations = 1) noexcept { - std::string hash; - - hash.resize(160 / 8); - SHA1(reinterpret_cast<const unsigned char *>(&input[0]), input.size(), reinterpret_cast<unsigned char *>(&hash[0])); - - for(std::size_t c = 1; c < iterations; ++c) - SHA1(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0])); - + auto evp_md = EVP_sha1(); + auto hash = message_digest(input, evp_md, SHA_DIGEST_LENGTH); + for(std::size_t i = 1; i < iterations; ++i) + hash = message_digest(hash, evp_md, SHA_DIGEST_LENGTH); return hash; } /// Returns sha1 hash value from input stream. static std::string sha1(std::istream &stream, std::size_t iterations = 1) noexcept { - SHA_CTX context; - SHA1_Init(&context); - std::streamsize read_length; - std::vector<char> buffer(buffer_size); - while((read_length = stream.read(&buffer[0], buffer_size).gcount()) > 0) - SHA1_Update(&context, buffer.data(), static_cast<std::size_t>(read_length)); - std::string hash; - hash.resize(160 / 8); - SHA1_Final(reinterpret_cast<unsigned char *>(&hash[0]), &context); - - for(std::size_t c = 1; c < iterations; ++c) - SHA1(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0])); - + auto evp_md = EVP_sha1(); + auto hash = stream_digest(stream, evp_md, SHA_DIGEST_LENGTH); + for(std::size_t i = 1; i < iterations; ++i) + hash = message_digest(hash, evp_md, SHA_DIGEST_LENGTH); return hash; } /// Returns sha256 hash value from input string. static std::string sha256(const std::string &input, std::size_t iterations = 1) noexcept { - std::string hash; - - hash.resize(256 / 8); - SHA256(reinterpret_cast<const unsigned char *>(&input[0]), input.size(), reinterpret_cast<unsigned char *>(&hash[0])); - - for(std::size_t c = 1; c < iterations; ++c) - SHA256(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0])); - + auto evp_md = EVP_sha256(); + auto hash = message_digest(input, evp_md, SHA256_DIGEST_LENGTH); + for(std::size_t i = 1; i < iterations; ++i) + hash = message_digest(hash, evp_md, SHA256_DIGEST_LENGTH); return hash; } /// Returns sha256 hash value from input stream. static std::string sha256(std::istream &stream, std::size_t iterations = 1) noexcept { - SHA256_CTX context; - SHA256_Init(&context); - std::streamsize read_length; - std::vector<char> buffer(buffer_size); - while((read_length = stream.read(&buffer[0], buffer_size).gcount()) > 0) - SHA256_Update(&context, buffer.data(), static_cast<std::size_t>(read_length)); - std::string hash; - hash.resize(256 / 8); - SHA256_Final(reinterpret_cast<unsigned char *>(&hash[0]), &context); - - for(std::size_t c = 1; c < iterations; ++c) - SHA256(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0])); - + auto evp_md = EVP_sha256(); + auto hash = stream_digest(stream, evp_md, SHA256_DIGEST_LENGTH); + for(std::size_t i = 1; i < iterations; ++i) + hash = message_digest(hash, evp_md, SHA256_DIGEST_LENGTH); return hash; } /// Returns sha512 hash value from input string. static std::string sha512(const std::string &input, std::size_t iterations = 1) noexcept { - std::string hash; - - hash.resize(512 / 8); - SHA512(reinterpret_cast<const unsigned char *>(&input[0]), input.size(), reinterpret_cast<unsigned char *>(&hash[0])); - - for(std::size_t c = 1; c < iterations; ++c) - SHA512(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0])); - + auto evp_md = EVP_sha512(); + auto hash = message_digest(input, evp_md, SHA512_DIGEST_LENGTH); + for(std::size_t i = 1; i < iterations; ++i) + hash = message_digest(hash, evp_md, SHA512_DIGEST_LENGTH); return hash; } /// Returns sha512 hash value from input stream. static std::string sha512(std::istream &stream, std::size_t iterations = 1) noexcept { - SHA512_CTX context; - SHA512_Init(&context); - std::streamsize read_length; - std::vector<char> buffer(buffer_size); - while((read_length = stream.read(&buffer[0], buffer_size).gcount()) > 0) - SHA512_Update(&context, buffer.data(), static_cast<std::size_t>(read_length)); - std::string hash; - hash.resize(512 / 8); - SHA512_Final(reinterpret_cast<unsigned char *>(&hash[0]), &context); - - for(std::size_t c = 1; c < iterations; ++c) - SHA512(reinterpret_cast<const unsigned char *>(&hash[0]), hash.size(), reinterpret_cast<unsigned char *>(&hash[0])); - + auto evp_md = EVP_sha512(); + auto hash = stream_digest(stream, evp_md, SHA512_DIGEST_LENGTH); + for(std::size_t i = 1; i < iterations; ++i) + hash = message_digest(hash, evp_md, SHA512_DIGEST_LENGTH); return hash; } - /// Returns PBKDF2 hash value from the given password - /// Input parameter key_size number of bytes of the returned key. - /** * Returns PBKDF2 derived key from the given password. * @@ -237,8 +211,7 @@ namespace SimpleWeb { * @return The PBKDF2 derived key. */ static std::string pbkdf2(const std::string &password, const std::string &salt, int iterations, int key_size) noexcept { - std::string key; - key.resize(static_cast<std::size_t>(key_size)); + std::string key(static_cast<std::size_t>(key_size), '\0'); PKCS5_PBKDF2_HMAC_SHA1(password.c_str(), password.size(), reinterpret_cast<const unsigned char *>(salt.c_str()), salt.size(), iterations, key_size, reinterpret_cast<unsigned char *>(&key[0])); diff --git a/server_ws.hpp b/server_ws.hpp index 2256d55..339d65b 100644 --- a/server_ws.hpp +++ b/server_ws.hpp @@ -79,7 +79,7 @@ namespace SimpleWeb { friend class SocketServer<socket_type>; public: - Connection(std::unique_ptr<socket_type> &&socket_) noexcept : socket(std::move(socket_)), timeout_idle(0), closed(false) {} + Connection(std::unique_ptr<socket_type> &&socket_) noexcept : socket(std::move(socket_)), timeout_idle(0), close_sent(false) {} std::string method, path, query_string, http_version; @@ -90,8 +90,8 @@ namespace SimpleWeb { private: /// Used to call SocketServer::upgrade. template <typename... Args> - Connection(std::shared_ptr<ScopeRunner> handler_runner_, long timeout_idle, Args &&... args) noexcept - : handler_runner(std::move(handler_runner_)), socket(new socket_type(std::forward<Args>(args)...)), timeout_idle(timeout_idle), closed(false) {} + Connection(std::shared_ptr<ScopeRunner> handler_runner_, long timeout_idle, Args &&...args) noexcept + : handler_runner(std::move(handler_runner_)), socket(new socket_type(std::forward<Args>(args)...)), timeout_idle(timeout_idle), close_sent(false) {} std::shared_ptr<ScopeRunner> handler_runner; @@ -105,16 +105,10 @@ namespace SimpleWeb { Mutex timer_mutex; std::unique_ptr<asio::steady_timer> timer GUARDED_BY(timer_mutex); - std::atomic<bool> closed; + std::atomic<bool> close_sent; asio::ip::tcp::endpoint endpoint; // The endpoint is read in SocketServer::write_handshake and must be stored so that it can be read reliably in all handlers, including on_error - void close() noexcept { - error_code ec; - socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec); - socket->lowest_layer().cancel(ec); - } - void set_timeout(long seconds = -1) noexcept { if(seconds == -1) seconds = timeout_idle; @@ -244,9 +238,9 @@ namespace SimpleWeb { void send_close(int status, const std::string &reason = "", std::function<void(const error_code &)> callback = nullptr) { // Send close only once (in case close is initiated by server) - if(closed) + if(close_sent) return; - closed = true; + close_sent = true; auto send_stream = std::make_shared<OutMessage>(); @@ -259,6 +253,13 @@ namespace SimpleWeb { send(std::move(send_stream), std::move(callback), 136); } + /// Force close connection. Use `send_close()` instead for standard compliant connection close. + void close() noexcept { + error_code ec; + socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec); + socket->lowest_layer().cancel(ec); + } + const asio::ip::tcp::endpoint &remote_endpoint() const noexcept { return endpoint; } @@ -274,7 +275,7 @@ namespace SimpleWeb { } /// Deprecated, please use remote_endpoint().address().to_string() instead. - DEPRECATED std::string remote_endpoint_address() const noexcept { + SW_DEPRECATED std::string remote_endpoint_address() const noexcept { try { return endpoint.address().to_string(); } @@ -284,7 +285,7 @@ namespace SimpleWeb { } /// Deprecated, please use remote_endpoint().port() instead. - DEPRECATED unsigned short remote_endpoint_port() const noexcept { + SW_DEPRECATED unsigned short remote_endpoint_port() const noexcept { try { return endpoint.port(); } diff --git a/server_wss.hpp b/server_wss.hpp index 05afd85..42d8133 100644 --- a/server_wss.hpp +++ b/server_wss.hpp @@ -5,7 +5,7 @@ #include <algorithm> #include <openssl/ssl.h> -#ifdef USE_STANDALONE_ASIO +#ifdef ASIO_STANDALONE #include <asio/ssl.hpp> #else #include <boost/asio/ssl.hpp> @@ -23,12 +23,21 @@ namespace SimpleWeb { /** * Constructs a server object. * - * @param certification_file If non-empty, sends the given certification file to client. + * @param certification_file Sends the given certification file to client. * @param private_key_file Specifies the file containing the private key for certification_file. * @param verify_file If non-empty, use this certificate authority file to perform verification of client's certificate and hostname according to RFC 2818. */ SocketServer(const std::string &certification_file, const std::string &private_key_file, const std::string &verify_file = std::string()) - : SocketServerBase<WSS>(443), context(asio::ssl::context::tlsv12) { + : SocketServerBase<WSS>(443), +#if(ASIO_STANDALONE && ASIO_VERSION >= 101300) || BOOST_ASIO_VERSION >= 101300 + context(asio::ssl::context::tls_server) { + // Disabling TLS 1.0 and 1.1 (see RFC 8996) + context.set_options(asio::ssl::context::no_tlsv1); + context.set_options(asio::ssl::context::no_tlsv1_1); +#else + context(asio::ssl::context::tlsv12) { +#endif + context.use_certificate_chain_file(certification_file); context.use_private_key_file(private_key_file, asio::ssl::context::pem); diff --git a/tests/parse_test.cpp b/tests/parse_test.cpp index 45f5476..58b8962 100644 --- a/tests/parse_test.cpp +++ b/tests/parse_test.cpp @@ -57,30 +57,6 @@ public: void connect() {} - void constructor_parse_test1() { - ASSERT(path == "/test"); - ASSERT(host == "test.org"); - ASSERT(port == 8080); - } - - void constructor_parse_test2() { - ASSERT(path == "/test"); - ASSERT(host == "test.org"); - ASSERT(port == 80); - } - - void constructor_parse_test3() { - ASSERT(path == "/"); - ASSERT(host == "test.org"); - ASSERT(port == 80); - } - - void constructor_parse_test4() { - ASSERT(path == "/"); - ASSERT(host == "test.org"); - ASSERT(port == 8080); - } - void parse_response_header_test() { auto connection = std::shared_ptr<Connection>(new Connection(handler_runner, config.timeout_idle, *io_service)); connection->in_message = std::shared_ptr<InMessage>(new InMessage()); @@ -136,18 +112,76 @@ int main() { serverTest.parse_request_test(); - SocketClientTest clientTest("test.org:8080/test"); - clientTest.constructor_parse_test1(); + { + SocketClientTest clientTest("test.org:8080/test"); + ASSERT(clientTest.path == "/test"); + ASSERT(clientTest.host == "test.org"); + ASSERT(clientTest.port == 8080); + } + + { + SocketClientTest clientTest("test.org/test"); + ASSERT(clientTest.path == "/test"); + ASSERT(clientTest.host == "test.org"); + ASSERT(clientTest.port == 80); + } + + { + SocketClientTest clientTest("test.org"); + ASSERT(clientTest.path == "/"); + ASSERT(clientTest.host == "test.org"); + ASSERT(clientTest.port == 80); + } + + { + SocketClientTest clientTest("test.org:test"); + ASSERT(clientTest.path == "/"); + ASSERT(clientTest.host == "test.org"); + ASSERT(clientTest.port == 80); + } + + { + SocketClientTest clientTest("[::1]"); + ASSERT(clientTest.path == "/"); + ASSERT(clientTest.host == "::1"); + ASSERT(clientTest.port == 80); + } + + { + SocketClientTest clientTest("[::1]/test"); + ASSERT(clientTest.path == "/test"); + ASSERT(clientTest.host == "::1"); + ASSERT(clientTest.port == 80); + } + + { + SocketClientTest clientTest("[::1]:8080"); + ASSERT(clientTest.path == "/"); + ASSERT(clientTest.host == "::1"); + ASSERT(clientTest.port == 8080); + } - SocketClientTest clientTest2("test.org/test"); - clientTest2.constructor_parse_test2(); + { + SocketClientTest clientTest("[::1]:8080/test"); + ASSERT(clientTest.path == "/test"); + ASSERT(clientTest.host == "::1"); + ASSERT(clientTest.port == 8080); + } - SocketClientTest clientTest3("test.org"); - clientTest3.constructor_parse_test3(); + { + SocketClientTest clientTest("[::1]:test/test"); + ASSERT(clientTest.path == "/test"); + ASSERT(clientTest.host == "::1"); + ASSERT(clientTest.port == 80); + } - SocketClientTest clientTest4("test.org:8080"); - clientTest4.io_service = std::make_shared<io_context>(); - clientTest4.constructor_parse_test4(); + { + SocketClientTest clientTest("test.org:8080"); + clientTest.io_service = std::make_shared<io_context>(); + ASSERT(clientTest.path == "/"); + ASSERT(clientTest.host == "test.org"); + ASSERT(clientTest.port == 8080); - clientTest4.parse_response_header_test(); + clientTest.parse_response_header_test(); + } } diff --git a/utility.hpp b/utility.hpp index 3b41ff3..cac7dfa 100644 --- a/utility.hpp +++ b/utility.hpp @@ -12,13 +12,13 @@ #include <string> #include <unordered_map> -#ifndef DEPRECATED +#ifndef SW_DEPRECATED #if defined(__GNUC__) || defined(__clang__) -#define DEPRECATED __attribute__((deprecated)) +#define SW_DEPRECATED __attribute__((deprecated)) #elif defined(_MSC_VER) -#define DEPRECATED __declspec(deprecated) +#define SW_DEPRECATED __declspec(deprecated) #else -#define DEPRECATED +#define SW_DEPRECATED #endif #endif @@ -27,7 +27,7 @@ namespace SimpleWeb { using string_view = std::string_view; } -#elif !defined(USE_STANDALONE_ASIO) +#elif !defined(ASIO_STANDALONE) #include <boost/utility/string_ref.hpp> namespace SimpleWeb { using string_view = boost::string_ref; |