Compare commits
	
		
			1 Commits
		
	
	
		
			v11.4.4
			...
			revert-370
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | b1a72f6133 | 
							
								
								
									
										19
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| name: Mark stale issues and pull requests | ||||
|  | ||||
| on: | ||||
|   schedule: | ||||
|   - cron: "0 0 * * *" | ||||
|  | ||||
| jobs: | ||||
|   stale: | ||||
|  | ||||
|     runs-on: ubuntu-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/stale@v1 | ||||
|       with: | ||||
|         repo-token: ${{ secrets.GITHUB_TOKEN }} | ||||
|         stale-issue-message: 'Stale issue message' | ||||
|         stale-pr-message: 'Stale pull request message' | ||||
|         stale-issue-label: 'no-issue-activity' | ||||
|         stale-pr-label: 'no-pr-activity' | ||||
| @@ -6,12 +6,11 @@ | ||||
| cmake_minimum_required(VERSION 3.4.1...3.17.2) | ||||
| set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") | ||||
|  | ||||
| project(ixwebsocket LANGUAGES C CXX VERSION 11.4.4) | ||||
| project(ixwebsocket C CXX) | ||||
|  | ||||
| set (CMAKE_CXX_STANDARD 11) | ||||
| set (CXX_STANDARD_REQUIRED ON) | ||||
| set (CMAKE_CXX_EXTENSIONS OFF) | ||||
| set (CMAKE_EXPORT_COMPILE_COMMANDS yes) | ||||
|  | ||||
| option (BUILD_DEMO OFF) | ||||
|  | ||||
| @@ -67,7 +66,6 @@ set( IXWEBSOCKET_SOURCES | ||||
| ) | ||||
|  | ||||
| set( IXWEBSOCKET_HEADERS | ||||
|     ixwebsocket/IXBase64.h | ||||
|     ixwebsocket/IXBench.h | ||||
|     ixwebsocket/IXCancellationRequest.h | ||||
|     ixwebsocket/IXConnectionState.h | ||||
| @@ -136,7 +134,6 @@ if (USE_TLS) | ||||
|     else() # default to OpenSSL on all other platforms | ||||
|       if (NOT USE_MBED_TLS) # Unless mbedtls is requested | ||||
|         set(USE_OPEN_SSL ON) | ||||
|         set(requires "openssl") | ||||
|       endif() | ||||
|     endif() | ||||
|  | ||||
| @@ -168,7 +165,7 @@ if(BUILD_SHARED_LIBS) | ||||
|     ) | ||||
|      | ||||
|     # Set library version | ||||
|     set_target_properties(ixwebsocket PROPERTIES VERSION ${CMAKE_PROJECT_VERSION}) | ||||
|     set_target_properties(ixwebsocket PROPERTIES VERSION 11.3.2) | ||||
|  | ||||
| else() | ||||
|     # Static library | ||||
| @@ -237,7 +234,11 @@ endif() | ||||
| option(USE_ZLIB "Enable zlib support" TRUE) | ||||
|  | ||||
| if (USE_ZLIB) | ||||
|   # This ZLIB_FOUND check is to help find a cmake manually configured zlib | ||||
|   if (NOT ZLIB_FOUND) | ||||
|     find_package(ZLIB REQUIRED) | ||||
|   endif() | ||||
|   target_include_directories(ixwebsocket PUBLIC $<BUILD_INTERFACE:${ZLIB_INCLUDE_DIRS}>) | ||||
|   target_link_libraries(ixwebsocket PRIVATE ZLIB::ZLIB) | ||||
|  | ||||
|   target_compile_definitions(ixwebsocket PUBLIC IXWEBSOCKET_USE_ZLIB) | ||||
| @@ -252,7 +253,7 @@ if (WIN32) | ||||
|   endif() | ||||
| endif() | ||||
|  | ||||
| if (UNIX AND NOT APPLE) | ||||
| if (UNIX) | ||||
|   set(THREADS_PREFER_PTHREAD_FLAG TRUE) | ||||
|   find_package(Threads) | ||||
|   target_link_libraries(ixwebsocket PRIVATE Threads::Threads) | ||||
| @@ -288,18 +289,10 @@ if (IXWEBSOCKET_INSTALL) | ||||
|           PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ixwebsocket/ | ||||
|   ) | ||||
|  | ||||
|   configure_file("${CMAKE_CURRENT_LIST_DIR}/ixwebsocket-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket-config.cmake" @ONLY) | ||||
|   install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket-config.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ixwebsocket") | ||||
|    | ||||
|   set(prefix ${CMAKE_INSTALL_PREFIX}) | ||||
|   configure_file("${CMAKE_CURRENT_LIST_DIR}/ixwebsocket.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket.pc" @ONLY) | ||||
|   install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ixwebsocket.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") | ||||
|  | ||||
|   install(EXPORT ixwebsocket | ||||
|           FILE ixwebsocket-targets.cmake | ||||
|           FILE ixwebsocket-config.cmake | ||||
|           NAMESPACE ixwebsocket:: | ||||
|           DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ixwebsocket | ||||
|   ) | ||||
|           DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ixwebsocket) | ||||
| endif() | ||||
|  | ||||
| if (USE_WS OR USE_TEST) | ||||
|   | ||||
| @@ -35,7 +35,6 @@ int main() | ||||
|  | ||||
|     // Connect to a server with encryption | ||||
|     // See https://machinezone.github.io/IXWebSocket/usage/#tls-support-and-configuration | ||||
|     //     https://github.com/machinezone/IXWebSocket/issues/386#issuecomment-1105235227 (self signed certificates) | ||||
|     std::string url("wss://echo.websocket.org"); | ||||
|     webSocket.setUrl(url); | ||||
|  | ||||
| @@ -107,7 +106,6 @@ If your company or project is using this library, feel free to open an issue or | ||||
| - [Teleport](http://teleportconnect.com/), Teleport is your own personal remote robot avatar | ||||
| - [Abaddon](https://github.com/uowuo/abaddon), An alternative Discord client made with C++/gtkmm  | ||||
| - [NovaCoin](https://github.com/novacoin-project/novacoin), a hybrid scrypt PoW + PoS based cryptocurrency. | ||||
| - [Candy](https://github.com/lanthora/candy), A WebSocket and TUN based VPN for Linux  | ||||
|  | ||||
| ## Alternative libraries | ||||
|  | ||||
|   | ||||
| @@ -2,18 +2,6 @@ | ||||
|  | ||||
| All changes to this project will be documented in this file. | ||||
|  | ||||
| ## [11.4.4] - 2023-06-05 | ||||
|  | ||||
| ## [11.4.3] - 2022-05-13 | ||||
|  | ||||
| Set shorter thread names | ||||
| BoringSSL fix with SNI | ||||
| Websocket computed header is valid Base64 | ||||
|  | ||||
| ## [11.4.1] - 2022-04-23 | ||||
|  | ||||
| vckpg + cmake fix, to handle zlib as a dependency better | ||||
|  | ||||
| ## [11.4.0] - 2022-01-05 | ||||
|  | ||||
| (Windows) Use wsa select event, which should lead to a much better behavior on Windows in general, and also when sending large payloads (#342) | ||||
|   | ||||
| @@ -54,7 +54,7 @@ To use the installed package within a cmake project, use the following: | ||||
|  # include headers | ||||
|  include_directories(${IXWEBSOCKET_INCLUDE_DIR}) | ||||
|  # ... | ||||
|  target_link_libraries(${PROJECT_NAME} ... ${IXWEBSOCKET_LIBRARY}) # Cmake will automatically fail the generation if the lib was not found, i.e is set to NOTFOUND | ||||
|  target_link_libraries(${PROJECT_NAME} ... ${IXWEBSOCKET_LIBRARY}) # Cmake will automatically fail the generation if the lib was not found, i.e is set to NOTFOUNS | ||||
|  | ||||
| ``` | ||||
|  | ||||
|   | ||||
| @@ -301,9 +301,7 @@ This api was actually changed to take a weak_ptr<WebSocket> as the first argumen | ||||
|  | ||||
| // Run a server on localhost at a given port. | ||||
| // Bound host name, max connections and listen backlog can also be passed in as parameters. | ||||
| int port = 8008; | ||||
| std::string host("127.0.0.1"); // If you need this server to be accessible on a different machine, use "0.0.0.0" | ||||
| ix::WebSocketServer server(port, host); | ||||
| ix::WebSocketServer server(port); | ||||
|  | ||||
| server.setOnConnectionCallback( | ||||
|     [&server](std::weak_ptr<WebSocket> webSocket, | ||||
| @@ -386,9 +384,7 @@ The webSocket reference is guaranteed to be always valid ; by design the callbac | ||||
|  | ||||
| // Run a server on localhost at a given port. | ||||
| // Bound host name, max connections and listen backlog can also be passed in as parameters. | ||||
| int port = 8008; | ||||
| std::string host("127.0.0.1"); // If you need this server to be accessible on a different machine, use "0.0.0.0" | ||||
| ix::WebSocketServer server(port, host); | ||||
| ix::WebSocketServer server(port); | ||||
|  | ||||
| server.setOnClientMessageCallback([](std::shared_ptr<ix::ConnectionState> connectionState, ix::WebSocket & webSocket, const ix::WebSocketMessagePtr & msg) { | ||||
|     // The ConnectionState object contains information about the connection, | ||||
| @@ -628,5 +624,3 @@ For a client, specifying `caFile` can be used if connecting to a server that use | ||||
| For a server, specifying `caFile` implies that: | ||||
| 1. You require clients to present a certificate | ||||
| 1. It must be signed by one of the trusted roots in the file | ||||
|  | ||||
| By default, a destination's hostname is always validated against the certificate that it presents. To accept certificates with any hostname, set `ix::SocketTLSOptions::disable_hostname_validation` to `true`. | ||||
|   | ||||
| @@ -1,9 +0,0 @@ | ||||
| @PACKAGE_INIT@ | ||||
|  | ||||
| include(CMakeFindDependencyMacro) | ||||
|  | ||||
| if (@USE_ZLIB@) | ||||
|   find_dependency(ZLIB) | ||||
| endif() | ||||
|  | ||||
| include("${CMAKE_CURRENT_LIST_DIR}/ixwebsocket-targets.cmake") | ||||
| @@ -1,11 +0,0 @@ | ||||
| prefix=@prefix@ | ||||
| exec_prefix=${prefix} | ||||
| libdir=${exec_prefix}/lib | ||||
| includedir=${prefix}/include | ||||
|  | ||||
| Name: ixwebsocket | ||||
| Description: websocket and http client and server library, with TLS support and very few dependencies | ||||
| Version: @CMAKE_PROJECT_VERSION@ | ||||
| Libs: -L${libdir} -lixwebsocket | ||||
| Cflags: -I${includedir} | ||||
| Requires: @requires@ | ||||
| @@ -1,125 +0,0 @@ | ||||
| #ifndef _MACARON_BASE64_H_ | ||||
| #define _MACARON_BASE64_H_ | ||||
|  | ||||
| /** | ||||
|  * The MIT License (MIT) | ||||
|  * Copyright (c) 2016 tomykaira | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining | ||||
|  * a copy of this software and associated documentation files (the | ||||
|  * "Software"), to deal in the Software without restriction, including | ||||
|  * without limitation the rights to use, copy, modify, merge, publish, | ||||
|  * distribute, sublicense, and/or sell copies of the Software, and to | ||||
|  * permit persons to whom the Software is furnished to do so, subject to | ||||
|  * the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be | ||||
|  * included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||
|  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||
|  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||
|  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||||
|  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||||
|  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||||
|  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #include <cstdint> | ||||
| #include <string> | ||||
|  | ||||
| namespace macaron { | ||||
|  | ||||
| class Base64 { | ||||
|  public: | ||||
|  | ||||
|   static std::string Encode(const std::string data) { | ||||
|     static constexpr char sEncodingTable[] = { | ||||
|       'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', | ||||
|       'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', | ||||
|       'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', | ||||
|       'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', | ||||
|       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', | ||||
|       'o', 'p', 'q', 'r', 's', 't', 'u', 'v', | ||||
|       'w', 'x', 'y', 'z', '0', '1', '2', '3', | ||||
|       '4', '5', '6', '7', '8', '9', '+', '/' | ||||
|     }; | ||||
|  | ||||
|     size_t in_len = data.size(); | ||||
|     size_t out_len = 4 * ((in_len + 2) / 3); | ||||
|     std::string ret(out_len, '\0'); | ||||
|     size_t i; | ||||
|     char *p = const_cast<char*>(ret.c_str()); | ||||
|  | ||||
|     for (i = 0; i < in_len - 2; i += 3) { | ||||
|       *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; | ||||
|       *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; | ||||
|       *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | ((int) (data[i + 2] & 0xC0) >> 6)]; | ||||
|       *p++ = sEncodingTable[data[i + 2] & 0x3F]; | ||||
|     } | ||||
|     if (i < in_len) { | ||||
|       *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; | ||||
|       if (i == (in_len - 1)) { | ||||
|         *p++ = sEncodingTable[((data[i] & 0x3) << 4)]; | ||||
|         *p++ = '='; | ||||
|       } | ||||
|       else { | ||||
|         *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; | ||||
|         *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)]; | ||||
|       } | ||||
|       *p++ = '='; | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
|   } | ||||
|  | ||||
|   static std::string Decode(const std::string& input, std::string& out) { | ||||
|     static constexpr unsigned char kDecodingTable[] = { | ||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, | ||||
|       52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, | ||||
|       64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, | ||||
|       15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, | ||||
|       64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, | ||||
|       41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, | ||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, | ||||
|       64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 | ||||
|     }; | ||||
|  | ||||
|     size_t in_len = input.size(); | ||||
|     if (in_len % 4 != 0) return "Input data size is not a multiple of 4"; | ||||
|  | ||||
|     size_t out_len = in_len / 4 * 3; | ||||
|     if (input[in_len - 1] == '=') out_len--; | ||||
|     if (input[in_len - 2] == '=') out_len--; | ||||
|  | ||||
|     out.resize(out_len); | ||||
|  | ||||
|     for (size_t i = 0, j = 0; i < in_len;) { | ||||
|       uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; | ||||
|       uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; | ||||
|       uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; | ||||
|       uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])]; | ||||
|  | ||||
|       uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6); | ||||
|  | ||||
|       if (j < out_len) out[j++] = (triple >> 2 * 8) & 0xFF; | ||||
|       if (j < out_len) out[j++] = (triple >> 1 * 8) & 0xFF; | ||||
|       if (j < out_len) out[j++] = (triple >> 0 * 8) & 0xFF; | ||||
|     } | ||||
|  | ||||
|     return ""; | ||||
|   } | ||||
|  | ||||
| }; | ||||
|  | ||||
| } | ||||
|  | ||||
| #endif /* _MACARON_BASE64_H_ */ | ||||
| @@ -6,7 +6,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <chrono> | ||||
| #include <cstdint> | ||||
| #include <stdint.h> | ||||
| #include <string> | ||||
|  | ||||
| namespace ix | ||||
|   | ||||
| @@ -7,9 +7,9 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <atomic> | ||||
| #include <cstdint> | ||||
| #include <functional> | ||||
| #include <memory> | ||||
| #include <stdint.h> | ||||
| #include <string> | ||||
|  | ||||
| namespace ix | ||||
|   | ||||
| @@ -23,7 +23,6 @@ | ||||
| #include <chrono> | ||||
| #include <string.h> | ||||
| #include <thread> | ||||
| #include <utility> | ||||
|  | ||||
| // mingw build quirks | ||||
| #if defined(_WIN32) && defined(__GNUC__) | ||||
| @@ -45,7 +44,7 @@ namespace ix | ||||
|         ; | ||||
|     } | ||||
|  | ||||
|     DNSLookup::AddrInfoPtr DNSLookup::getAddrInfo(const std::string& hostname, | ||||
|     struct addrinfo* DNSLookup::getAddrInfo(const std::string& hostname, | ||||
|                                             int port, | ||||
|                                             std::string& errMsg) | ||||
|     { | ||||
| @@ -64,10 +63,10 @@ namespace ix | ||||
|             errMsg = gai_strerror(getaddrinfo_result); | ||||
|             res = nullptr; | ||||
|         } | ||||
|         return AddrInfoPtr{ res, freeaddrinfo }; | ||||
|         return res; | ||||
|     } | ||||
|  | ||||
|     DNSLookup::AddrInfoPtr DNSLookup::resolve(std::string& errMsg, | ||||
|     struct addrinfo* DNSLookup::resolve(std::string& errMsg, | ||||
|                                         const CancellationRequest& isCancellationRequested, | ||||
|                                         bool cancellable) | ||||
|     { | ||||
| @@ -75,7 +74,12 @@ namespace ix | ||||
|                            : resolveUnCancellable(errMsg, isCancellationRequested); | ||||
|     } | ||||
|  | ||||
|     DNSLookup::AddrInfoPtr DNSLookup::resolveUnCancellable( | ||||
|     void DNSLookup::release(struct addrinfo* addr) | ||||
|     { | ||||
|         freeaddrinfo(addr); | ||||
|     } | ||||
|  | ||||
|     struct addrinfo* DNSLookup::resolveUnCancellable( | ||||
|         std::string& errMsg, const CancellationRequest& isCancellationRequested) | ||||
|     { | ||||
|         errMsg = "no error"; | ||||
| @@ -90,7 +94,7 @@ namespace ix | ||||
|         return getAddrInfo(_hostname, _port, errMsg); | ||||
|     } | ||||
|  | ||||
|     DNSLookup::AddrInfoPtr DNSLookup::resolveCancellable( | ||||
|     struct addrinfo* DNSLookup::resolveCancellable( | ||||
|         std::string& errMsg, const CancellationRequest& isCancellationRequested) | ||||
|     { | ||||
|         errMsg = "no error"; | ||||
| @@ -153,7 +157,7 @@ namespace ix | ||||
|         // gone, so we use temporary variables (res) or we pass in by copy everything that | ||||
|         // getAddrInfo needs to work. | ||||
|         std::string errMsg; | ||||
|         auto res = getAddrInfo(hostname, port, errMsg); | ||||
|         struct addrinfo* res = getAddrInfo(hostname, port, errMsg); | ||||
|  | ||||
|         if (auto lock = self.lock()) | ||||
|         { | ||||
| @@ -177,13 +181,13 @@ namespace ix | ||||
|         return _errMsg; | ||||
|     } | ||||
|  | ||||
|     void DNSLookup::setRes(DNSLookup::AddrInfoPtr addr) | ||||
|     void DNSLookup::setRes(struct addrinfo* addr) | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(_resMutex); | ||||
|         _res = std::move(addr); | ||||
|         _res = addr; | ||||
|     } | ||||
|  | ||||
|     DNSLookup::AddrInfoPtr DNSLookup::getRes() | ||||
|     struct addrinfo* DNSLookup::getRes() | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(_resMutex); | ||||
|         return _res; | ||||
|   | ||||
| @@ -12,7 +12,6 @@ | ||||
|  | ||||
| #include "IXCancellationRequest.h" | ||||
| #include <atomic> | ||||
| #include <cstdint> | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| #include <set> | ||||
| @@ -25,21 +24,22 @@ namespace ix | ||||
|     class DNSLookup : public std::enable_shared_from_this<DNSLookup> | ||||
|     { | ||||
|     public: | ||||
|         using AddrInfoPtr = std::shared_ptr<addrinfo>; | ||||
|         DNSLookup(const std::string& hostname, int port, int64_t wait = DNSLookup::kDefaultWait); | ||||
|         ~DNSLookup() = default; | ||||
|  | ||||
|         AddrInfoPtr resolve(std::string& errMsg, | ||||
|         struct addrinfo* resolve(std::string& errMsg, | ||||
|                                  const CancellationRequest& isCancellationRequested, | ||||
|                                  bool cancellable = true); | ||||
|  | ||||
|         void release(struct addrinfo* addr); | ||||
|  | ||||
|     private: | ||||
|         AddrInfoPtr resolveCancellable(std::string& errMsg, | ||||
|         struct addrinfo* resolveCancellable(std::string& errMsg, | ||||
|                                             const CancellationRequest& isCancellationRequested); | ||||
|         AddrInfoPtr resolveUnCancellable(std::string& errMsg, | ||||
|         struct addrinfo* resolveUnCancellable(std::string& errMsg, | ||||
|                                               const CancellationRequest& isCancellationRequested); | ||||
|  | ||||
|         AddrInfoPtr getAddrInfo(const std::string& hostname, | ||||
|         static struct addrinfo* getAddrInfo(const std::string& hostname, | ||||
|                                             int port, | ||||
|                                             std::string& errMsg); | ||||
|  | ||||
| @@ -48,15 +48,15 @@ namespace ix | ||||
|         void setErrMsg(const std::string& errMsg); | ||||
|         const std::string& getErrMsg(); | ||||
|  | ||||
|         void setRes(AddrInfoPtr addr); | ||||
|         AddrInfoPtr getRes(); | ||||
|         void setRes(struct addrinfo* addr); | ||||
|         struct addrinfo* getRes(); | ||||
|  | ||||
|         std::string _hostname; | ||||
|         int _port; | ||||
|         int64_t _wait; | ||||
|         const static int64_t kDefaultWait; | ||||
|  | ||||
|         AddrInfoPtr _res; | ||||
|         struct addrinfo* _res; | ||||
|         std::mutex _resMutex; | ||||
|  | ||||
|         std::string _errMsg; | ||||
|   | ||||
| @@ -9,7 +9,6 @@ | ||||
| #include "IXProgressCallback.h" | ||||
| #include "IXWebSocketHttpHeaders.h" | ||||
| #include <atomic> | ||||
| #include <cstdint> | ||||
| #include <tuple> | ||||
| #include <unordered_map> | ||||
|  | ||||
|   | ||||
| @@ -12,7 +12,6 @@ | ||||
| #include "IXUserAgent.h" | ||||
| #include "IXWebSocketHttpHeaders.h" | ||||
| #include <assert.h> | ||||
| #include <cstdint> | ||||
| #include <cstring> | ||||
| #include <iomanip> | ||||
| #include <random> | ||||
| @@ -140,9 +139,8 @@ namespace ix | ||||
|  | ||||
|         std::string protocol, host, path, query; | ||||
|         int port; | ||||
|         bool isProtocolDefaultPort; | ||||
|  | ||||
|         if (!UrlParser::parse(url, protocol, host, path, query, port, isProtocolDefaultPort)) | ||||
|         if (!UrlParser::parse(url, protocol, host, path, query, port)) | ||||
|         { | ||||
|             std::stringstream ss; | ||||
|             ss << "Cannot parse url: " << url; | ||||
| @@ -175,12 +173,7 @@ namespace ix | ||||
|         // Build request string | ||||
|         std::stringstream ss; | ||||
|         ss << verb << " " << path << " HTTP/1.1\r\n"; | ||||
|         ss << "Host: " << host; | ||||
|         if (!isProtocolDefaultPort) | ||||
|         { | ||||
|             ss << ":" << port; | ||||
|         } | ||||
|         ss << "\r\n"; | ||||
|         ss << "Host: " << host << "\r\n"; | ||||
|  | ||||
| #ifdef IXWEBSOCKET_USE_ZLIB | ||||
|         if (args->compress && !args->onChunkCallback) | ||||
| @@ -209,12 +202,6 @@ namespace ix | ||||
|             ss << "User-Agent: " << userAgent() << "\r\n"; | ||||
|         } | ||||
|  | ||||
|         // Set an origin header if missing | ||||
|         if (args->extraHeaders.find("Origin") == args->extraHeaders.end()) | ||||
|         { | ||||
|             ss << "Origin: " << protocol << "://" << host << ":" << port << "\r\n"; | ||||
|         } | ||||
|  | ||||
|         if (verb == kPost || verb == kPut || verb == kPatch || _forceBody) | ||||
|         { | ||||
|             // Set request compression header | ||||
|   | ||||
| @@ -10,7 +10,6 @@ | ||||
| #include "IXNetSystem.h" | ||||
| #include "IXSocketConnect.h" | ||||
| #include "IXUserAgent.h" | ||||
| #include <cstdint> | ||||
| #include <cstring> | ||||
| #include <fstream> | ||||
| #include <sstream> | ||||
| @@ -41,29 +40,6 @@ namespace | ||||
|         auto vec = res.second; | ||||
|         return std::make_pair(res.first, std::string(vec.begin(), vec.end())); | ||||
|     } | ||||
|  | ||||
|     std::string response_head_file(const std::string& file_name){ | ||||
|  | ||||
|         if (std::string::npos != file_name.find(".html") || std::string::npos != file_name.find(".htm")) | ||||
|             return "text/html"; | ||||
|         else if (std::string::npos != file_name.find(".css")) | ||||
|             return "text/css"; | ||||
|         else if (std::string::npos != file_name.find(".js") || std::string::npos != file_name.find(".mjs")) | ||||
|             return "application/x-javascript"; | ||||
|         else if (std::string::npos != file_name.find(".ico")) | ||||
|             return "image/x-icon"; | ||||
|         else if (std::string::npos != file_name.find(".png")) | ||||
|             return "image/png"; | ||||
|         else if (std::string::npos != file_name.find(".jpg") || std::string::npos != file_name.find(".jpeg")) | ||||
|             return "image/jpeg"; | ||||
|         else if (std::string::npos != file_name.find(".gif")) | ||||
|             return "image/gif"; | ||||
|         else if (std::string::npos != file_name.find(".svg")) | ||||
|             return "image/svg+xml"; | ||||
|         else | ||||
|             return "application/octet-stream"; | ||||
|     } | ||||
|  | ||||
| } // namespace | ||||
|  | ||||
| namespace ix | ||||
| @@ -75,14 +51,28 @@ namespace ix | ||||
|                            int backlog, | ||||
|                            size_t maxConnections, | ||||
|                            int addressFamily, | ||||
|                            int timeoutSecs, | ||||
|                            int handshakeTimeoutSecs) | ||||
|         : WebSocketServer(port, host, backlog, maxConnections, handshakeTimeoutSecs, addressFamily) | ||||
|                            int timeoutSecs) | ||||
|         : SocketServer(port, host, backlog, maxConnections, addressFamily) | ||||
|         , _connectedClientsCount(0) | ||||
|         , _timeoutSecs(timeoutSecs) | ||||
|     { | ||||
|         setDefaultConnectionCallback(); | ||||
|     } | ||||
|  | ||||
|     HttpServer::~HttpServer() | ||||
|     { | ||||
|         stop(); | ||||
|     } | ||||
|  | ||||
|     void HttpServer::stop() | ||||
|     { | ||||
|         stopAcceptingConnections(); | ||||
|  | ||||
|         // FIXME: cancelling / closing active clients ... | ||||
|  | ||||
|         SocketServer::stop(); | ||||
|     } | ||||
|  | ||||
|     void HttpServer::setOnConnectionCallback(const OnConnectionCallback& callback) | ||||
|     { | ||||
|         _onConnectionCallback = callback; | ||||
| @@ -91,35 +81,34 @@ namespace ix | ||||
|     void HttpServer::handleConnection(std::unique_ptr<Socket> socket, | ||||
|                                       std::shared_ptr<ConnectionState> connectionState) | ||||
|     { | ||||
|         _connectedClientsCount++; | ||||
|  | ||||
|         auto ret = Http::parseRequest(socket, _timeoutSecs); | ||||
|         // FIXME: handle errors in parseRequest | ||||
|  | ||||
|         if (std::get<0>(ret)) | ||||
|         { | ||||
|             auto request = std::get<2>(ret); | ||||
|             std::shared_ptr<ix::HttpResponse> response; | ||||
|             if (request->headers["Upgrade"] == "websocket") | ||||
|             { | ||||
|                 WebSocketServer::handleUpgrade(std::move(socket), connectionState, request); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 auto response = _onConnectionCallback(request, connectionState); | ||||
|             auto response = _onConnectionCallback(std::get<2>(ret), connectionState); | ||||
|             if (!Http::sendResponse(response, socket)) | ||||
|             { | ||||
|                 logError("Cannot send response"); | ||||
|             } | ||||
|         } | ||||
|         } | ||||
|         connectionState->setTerminated(); | ||||
|  | ||||
|         _connectedClientsCount--; | ||||
|     } | ||||
|  | ||||
|     size_t HttpServer::getConnectedClientsCount() | ||||
|     { | ||||
|         return _connectedClientsCount; | ||||
|     } | ||||
|  | ||||
|     void HttpServer::setDefaultConnectionCallback() | ||||
|     { | ||||
|         setOnConnectionCallback( | ||||
|             [this](HttpRequestPtr request, | ||||
|                    std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr | ||||
|             { | ||||
|                    std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr { | ||||
|                 std::string uri(request->uri); | ||||
|                 if (uri.empty() || uri == "/") | ||||
|                 { | ||||
| @@ -128,7 +117,6 @@ namespace ix | ||||
|  | ||||
|                 WebSocketHttpHeaders headers; | ||||
|                 headers["Server"] = userAgent(); | ||||
|                 headers["Content-Type"] = response_head_file(uri); | ||||
|  | ||||
|                 std::string path("." + uri); | ||||
|                 auto res = readAsString(path); | ||||
| @@ -177,9 +165,9 @@ namespace ix | ||||
|         // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections | ||||
|         // | ||||
|         setOnConnectionCallback( | ||||
|             [this, redirectUrl](HttpRequestPtr request, | ||||
|                                 std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr | ||||
|             { | ||||
|             [this, | ||||
|              redirectUrl](HttpRequestPtr request, | ||||
|                           std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr { | ||||
|                 WebSocketHttpHeaders headers; | ||||
|                 headers["Server"] = userAgent(); | ||||
|  | ||||
| @@ -210,8 +198,7 @@ namespace ix | ||||
|     { | ||||
|         setOnConnectionCallback( | ||||
|             [this](HttpRequestPtr request, | ||||
|                    std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr | ||||
|             { | ||||
|                    std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr { | ||||
|                 WebSocketHttpHeaders headers; | ||||
|                 headers["Server"] = userAgent(); | ||||
|  | ||||
|   | ||||
| @@ -7,8 +7,8 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "IXHttp.h" | ||||
| #include "IXSocketServer.h" | ||||
| #include "IXWebSocket.h" | ||||
| #include "IXWebSocketServer.h" | ||||
| #include <functional> | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| @@ -19,7 +19,7 @@ | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     class HttpServer final : public WebSocketServer | ||||
|     class HttpServer final : public SocketServer | ||||
|     { | ||||
|     public: | ||||
|         using OnConnectionCallback = | ||||
| @@ -30,8 +30,9 @@ namespace ix | ||||
|                    int backlog = SocketServer::kDefaultTcpBacklog, | ||||
|                    size_t maxConnections = SocketServer::kDefaultMaxConnections, | ||||
|                    int addressFamily = SocketServer::kDefaultAddressFamily, | ||||
|                    int timeoutSecs = HttpServer::kDefaultTimeoutSecs, | ||||
|                    int handshakeTimeoutSecs = WebSocketServer::kDefaultHandShakeTimeoutSecs); | ||||
|                    int timeoutSecs = HttpServer::kDefaultTimeoutSecs); | ||||
|         virtual ~HttpServer(); | ||||
|         virtual void stop() final; | ||||
|  | ||||
|         void setOnConnectionCallback(const OnConnectionCallback& callback); | ||||
|  | ||||
| @@ -40,10 +41,10 @@ namespace ix | ||||
|         void makeDebugServer(); | ||||
|  | ||||
|         int getTimeoutSecs(); | ||||
|  | ||||
|     private: | ||||
|         // Member variables | ||||
|         OnConnectionCallback _onConnectionCallback; | ||||
|         std::atomic<int> _connectedClientsCount; | ||||
|  | ||||
|         const static int kDefaultTimeoutSecs; | ||||
|         int _timeoutSecs; | ||||
| @@ -51,6 +52,7 @@ namespace ix | ||||
|         // Methods | ||||
|         virtual void handleConnection(std::unique_ptr<Socket>, | ||||
|                                       std::shared_ptr<ConnectionState> connectionState) final; | ||||
|         virtual size_t getConnectedClientsCount() final; | ||||
|  | ||||
|         void setDefaultConnectionCallback(); | ||||
|     }; | ||||
|   | ||||
| @@ -6,12 +6,6 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <cstdint> | ||||
|  | ||||
| #ifdef __FreeBSD__ | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
|  | ||||
| #ifdef _WIN32 | ||||
|  | ||||
| #ifndef WIN32_LEAN_AND_MEAN | ||||
|   | ||||
| @@ -6,8 +6,8 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <cstdint> | ||||
| #include <memory> | ||||
| #include <stdint.h> | ||||
| #include <string> | ||||
|  | ||||
| namespace ix | ||||
|   | ||||
| @@ -5,8 +5,8 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "IXSelectInterrupt.h" | ||||
| #include <cstdint> | ||||
| #include <mutex> | ||||
| #include <stdint.h> | ||||
| #include <string> | ||||
| #include <deque> | ||||
| #ifdef _WIN32 | ||||
|   | ||||
| @@ -7,7 +7,6 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "IXSelectInterrupt.h" | ||||
| #include <cstdint> | ||||
| #include <mutex> | ||||
| #include <stdint.h> | ||||
| #include <string> | ||||
|   | ||||
| @@ -14,6 +14,7 @@ | ||||
| #include <array> | ||||
| #include <assert.h> | ||||
| #include <fcntl.h> | ||||
| #include <stdint.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|   | ||||
| @@ -7,7 +7,6 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <atomic> | ||||
| #include <cstdint> | ||||
| #include <functional> | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
|   | ||||
| @@ -205,8 +205,6 @@ namespace ix | ||||
|                 _sslContext, SocketAppleSSL::readFromSocket, SocketAppleSSL::writeToSocket); | ||||
|             SSLSetConnection(_sslContext, (SSLConnectionRef)(long) _sockfd); | ||||
|             SSLSetProtocolVersionMin(_sslContext, kTLSProtocol12); | ||||
|  | ||||
|             if (!_tlsOptions.disable_hostname_validation) | ||||
|             SSLSetPeerDomainName(_sslContext, host.c_str(), host.size()); | ||||
|  | ||||
|             if (_tlsOptions.isPeerVerifyDisabled()) | ||||
|   | ||||
| @@ -102,7 +102,7 @@ namespace ix | ||||
|         // First do DNS resolution | ||||
|         // | ||||
|         auto dnsLookup = std::make_shared<DNSLookup>(hostname, port); | ||||
|         auto res = dnsLookup->resolve(errMsg, isCancellationRequested); | ||||
|         struct addrinfo* res = dnsLookup->resolve(errMsg, isCancellationRequested); | ||||
|         if (res == nullptr) | ||||
|         { | ||||
|             return -1; | ||||
| @@ -112,7 +112,7 @@ namespace ix | ||||
|  | ||||
|         // iterate through the records to find a working peer | ||||
|         struct addrinfo* address; | ||||
|         for (address = res.get(); address != nullptr; address = address->ai_next) | ||||
|         for (address = res; address != nullptr; address = address->ai_next) | ||||
|         { | ||||
|             // | ||||
|             // Second try to connect to the remote host | ||||
| @@ -124,6 +124,7 @@ namespace ix | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         freeaddrinfo(res); | ||||
|         return sockfd; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -14,7 +14,6 @@ | ||||
| #include "IXNetSystem.h" | ||||
| #include "IXSocket.h" | ||||
| #include "IXSocketConnect.h" | ||||
| #include <cstdint> | ||||
| #include <string.h> | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| @@ -49,7 +48,7 @@ namespace ix | ||||
|         mbedtls_pk_init(&_pkey); | ||||
|     } | ||||
|  | ||||
|     bool SocketMbedTLS::loadSystemCertificates(std::string& /* errorMsg */) | ||||
|     bool SocketMbedTLS::loadSystemCertificates(std::string& errorMsg) | ||||
|     { | ||||
| #ifdef _WIN32 | ||||
|         DWORD flags = CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG | | ||||
| @@ -196,14 +195,11 @@ namespace ix | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if (!_tlsOptions.disable_hostname_validation) | ||||
|         { | ||||
|         if (!host.empty() && mbedtls_ssl_set_hostname(&_ssl, host.c_str()) != 0) | ||||
|         { | ||||
|             errMsg = "SNI setup failed"; | ||||
|             return false; | ||||
|         } | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|   | ||||
| @@ -301,11 +301,7 @@ namespace ix | ||||
|     } | ||||
|  | ||||
|     bool SocketOpenSSL::openSSLCheckServerCert(SSL* ssl, | ||||
| #if OPENSSL_VERSION_NUMBER < 0x10100000L | ||||
|                                                const std::string& hostname, | ||||
| #else | ||||
|                                                const std::string& /* hostname */, | ||||
| #endif | ||||
|                                                std::string& errMsg) | ||||
|     { | ||||
|         X509* server_cert = SSL_get_peer_certificate(ssl); | ||||
| @@ -394,11 +390,6 @@ namespace ix | ||||
|             int connect_result = SSL_connect(_ssl_connection); | ||||
|             if (connect_result == 1) | ||||
|             { | ||||
|                 if (_tlsOptions.disable_hostname_validation) | ||||
|                 { | ||||
|                     return true; | ||||
|                 } | ||||
|  | ||||
|                 return openSSLCheckServerCert(_ssl_connection, host, errMsg); | ||||
|             } | ||||
|             int reason = SSL_get_error(_ssl_connection, connect_result); | ||||
| @@ -763,11 +754,8 @@ namespace ix | ||||
|             // (The docs say that this should work from 1.0.2, and is the default from | ||||
|             // 1.1.0, but it does not. To be on the safe side, the manual test | ||||
|             // below is enabled for all versions prior to 1.1.0.) | ||||
|             if (!_tlsOptions.disable_hostname_validation) | ||||
|             { | ||||
|             X509_VERIFY_PARAM* param = SSL_get0_param(_ssl_connection); | ||||
|                 X509_VERIFY_PARAM_set1_host(param, host.c_str(), host.size()); | ||||
|             } | ||||
|             X509_VERIFY_PARAM_set1_host(param, host.c_str(), 0); | ||||
| #endif | ||||
|             handshakeSuccessful = openSSLClientHandshake(host, errMsg, isCancellationRequested); | ||||
|         } | ||||
|   | ||||
| @@ -219,10 +219,6 @@ namespace ix | ||||
|         if (_gcThread.joinable()) | ||||
|         { | ||||
|             _stopGc = true; | ||||
|             { | ||||
|                 std::lock_guard<std::mutex> lock{ _conditionVariableMutexGC }; | ||||
|                 _canContinueGC = true; | ||||
|             } | ||||
|             _conditionVariableGC.notify_one(); | ||||
|             _gcThread.join(); | ||||
|             _stopGc = false; | ||||
| @@ -272,10 +268,7 @@ namespace ix | ||||
|         // Set the socket to non blocking mode, so that accept calls are not blocking | ||||
|         SocketConnect::configure(_serverFd); | ||||
|  | ||||
|         // Use a cryptic name to stay within the 16 bytes limit thread name limitation | ||||
|         // $ echo Srv:gc:64000 | wc -c | ||||
|         // 13 | ||||
|         setThreadName("Srv:ac:" + std::to_string(_port)); | ||||
|         setThreadName("SocketServer::accept"); | ||||
|  | ||||
|         for (;;) | ||||
|         { | ||||
| @@ -432,10 +425,7 @@ namespace ix | ||||
|  | ||||
|     void SocketServer::runGC() | ||||
|     { | ||||
|         // Use a cryptic name to stay within the 16 bytes limit thread name limitation | ||||
|         // $ echo Srv:gc:64000 | wc -c | ||||
|         // 13 | ||||
|         setThreadName("Srv:gc:" + std::to_string(_port)); | ||||
|         setThreadName("SocketServer::GC"); | ||||
|  | ||||
|         for (;;) | ||||
|         { | ||||
| @@ -455,10 +445,7 @@ namespace ix | ||||
|             if (!_stopGc) | ||||
|             { | ||||
|                 std::unique_lock<std::mutex> lock(_conditionVariableMutexGC); | ||||
|                 if(!_canContinueGC) { | ||||
|                     _conditionVariableGC.wait(lock, [this]{ return _canContinueGC; }); | ||||
|                 } | ||||
|                 _canContinueGC = false; | ||||
|                 _conditionVariableGC.wait(lock); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -472,10 +459,6 @@ namespace ix | ||||
|     { | ||||
|         // a connection got terminated, we can run the connection thread GC, | ||||
|         // so wake up the thread responsible for that | ||||
|         { | ||||
|             std::lock_guard<std::mutex> lock{ _conditionVariableMutexGC }; | ||||
|             _canContinueGC = true; | ||||
|         } | ||||
|         _conditionVariableGC.notify_one(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -126,6 +126,5 @@ namespace ix | ||||
|         // as a connection | ||||
|         std::condition_variable _conditionVariableGC; | ||||
|         std::mutex _conditionVariableMutexGC; | ||||
|         bool _canContinueGC{ false }; | ||||
|     }; | ||||
| } // namespace ix | ||||
|   | ||||
| @@ -33,9 +33,6 @@ namespace ix | ||||
|         // whether tls is enabled, used for server code | ||||
|         bool tls = false; | ||||
|  | ||||
|         // whether to skip validating the peer's hostname against the certificate presented | ||||
|         bool disable_hostname_validation = false; | ||||
|  | ||||
|         bool hasCertAndKey() const; | ||||
|  | ||||
|         bool isUsingSystemDefaults() const; | ||||
|   | ||||
| @@ -333,19 +333,6 @@ namespace | ||||
|  | ||||
|         return Result; | ||||
|     } | ||||
|  | ||||
|     int getProtocolPort(const std::string& protocol) | ||||
|     { | ||||
|         if (protocol == "ws" || protocol == "http") | ||||
|         { | ||||
|             return 80; | ||||
|         } | ||||
|         else if (protocol == "wss" || protocol == "https") | ||||
|         { | ||||
|             return 443; | ||||
|         } | ||||
|         return -1; | ||||
|     } | ||||
| } // namespace | ||||
|  | ||||
| namespace ix | ||||
| @@ -356,18 +343,6 @@ namespace ix | ||||
|                           std::string& path, | ||||
|                           std::string& query, | ||||
|                           int& port) | ||||
|     { | ||||
|         bool isProtocolDefaultPort; | ||||
|         return parse(url, protocol, host, path, query, port, isProtocolDefaultPort); | ||||
|     } | ||||
|  | ||||
|     bool UrlParser::parse(const std::string& url, | ||||
|                               std::string& protocol, | ||||
|                               std::string& host, | ||||
|                               std::string& path, | ||||
|                               std::string& query, | ||||
|                               int& port, | ||||
|                               bool& isProtocolDefaultPort) | ||||
|     { | ||||
|         clParseURL res = clParseURL::ParseURL(url); | ||||
|  | ||||
| @@ -381,12 +356,23 @@ namespace ix | ||||
|         path = res.m_Path; | ||||
|         query = res.m_Query; | ||||
|  | ||||
|         const auto protocolPort = getProtocolPort(protocol); | ||||
|         if (!res.GetPort(&port)) | ||||
|         { | ||||
|             port = protocolPort; | ||||
|             if (protocol == "ws" || protocol == "http") | ||||
|             { | ||||
|                 port = 80; | ||||
|             } | ||||
|             else if (protocol == "wss" || protocol == "https") | ||||
|             { | ||||
|                 port = 443; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 // Invalid protocol. Should be caught by regex check | ||||
|                 // but this missing branch trigger cpplint linter. | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         isProtocolDefaultPort = port == protocolPort; | ||||
|  | ||||
|         if (path.empty()) | ||||
|         { | ||||
|   | ||||
| @@ -19,13 +19,5 @@ namespace ix | ||||
|                           std::string& path, | ||||
|                           std::string& query, | ||||
|                           int& port); | ||||
|  | ||||
|         static bool parse(const std::string& url, | ||||
|                           std::string& protocol, | ||||
|                           std::string& host, | ||||
|                           std::string& path, | ||||
|                           std::string& query, | ||||
|                           int& port, | ||||
|                           bool& isProtocolDefaultPort); | ||||
|     }; | ||||
| } // namespace ix | ||||
|   | ||||
| @@ -16,7 +16,6 @@ | ||||
|  | ||||
| #include "IXUuid.h" | ||||
|  | ||||
| #include <cstdint> | ||||
| #include <iomanip> | ||||
| #include <random> | ||||
| #include <sstream> | ||||
|   | ||||
| @@ -13,7 +13,6 @@ | ||||
| #include "IXWebSocketHandshake.h" | ||||
| #include <cassert> | ||||
| #include <cmath> | ||||
| #include <cstdint> | ||||
|  | ||||
|  | ||||
| namespace | ||||
| @@ -40,11 +39,9 @@ namespace ix | ||||
|         , _handshakeTimeoutSecs(kDefaultHandShakeTimeoutSecs) | ||||
|         , _enablePong(kDefaultEnablePong) | ||||
|         , _pingIntervalSecs(kDefaultPingIntervalSecs) | ||||
|         , _pingType(SendMessageKind::Ping) | ||||
|     { | ||||
|         _ws.setOnCloseCallback( | ||||
|             [this](uint16_t code, const std::string& reason, size_t wireSize, bool remote) | ||||
|             { | ||||
|             [this](uint16_t code, const std::string& reason, size_t wireSize, bool remote) { | ||||
|                 _onMessageCallback( | ||||
|                     ix::make_unique<WebSocketMessage>(WebSocketMessageType::Close, | ||||
|                                                       emptyMsg, | ||||
| @@ -103,17 +100,6 @@ namespace ix | ||||
|         return _perMessageDeflateOptions; | ||||
|     } | ||||
|  | ||||
|     void WebSocket::setPingMessage(const std::string& sendMessage, SendMessageKind pingType) | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(_configMutex); | ||||
|         _pingMessage = sendMessage; | ||||
|         _ws.setPingMessage(_pingMessage, pingType); | ||||
|     } | ||||
|     const std::string WebSocket::getPingMessage() const | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(_configMutex); | ||||
|         return _pingMessage; | ||||
|     } | ||||
|     void WebSocket::setPingInterval(int pingIntervalSecs) | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(_configMutex); | ||||
| @@ -246,7 +232,7 @@ namespace ix | ||||
|         if (_pingIntervalSecs > 0) | ||||
|         { | ||||
|             // Send a heart beat right away | ||||
|             _ws.sendHeartBeat(_pingType); | ||||
|             _ws.sendHeartBeat(); | ||||
|         } | ||||
|  | ||||
|         return status; | ||||
| @@ -254,8 +240,7 @@ namespace ix | ||||
|  | ||||
|     WebSocketInitResult WebSocket::connectToSocket(std::unique_ptr<Socket> socket, | ||||
|                                                    int timeoutSecs, | ||||
|                                                    bool enablePerMessageDeflate, | ||||
|                                                    HttpRequestPtr request) | ||||
|                                                    bool enablePerMessageDeflate) | ||||
|     { | ||||
|         { | ||||
|             std::lock_guard<std::mutex> lock(_configMutex); | ||||
| @@ -264,7 +249,7 @@ namespace ix | ||||
|         } | ||||
|  | ||||
|         WebSocketInitResult status = | ||||
|             _ws.connectToSocket(std::move(socket), timeoutSecs, enablePerMessageDeflate, request); | ||||
|             _ws.connectToSocket(std::move(socket), timeoutSecs, enablePerMessageDeflate); | ||||
|         if (!status.success) | ||||
|         { | ||||
|             return status; | ||||
| @@ -281,7 +266,7 @@ namespace ix | ||||
|         if (_pingIntervalSecs > 0) | ||||
|         { | ||||
|             // Send a heart beat right away | ||||
|             _ws.sendHeartBeat(_pingType); | ||||
|             _ws.sendHeartBeat(); | ||||
|         } | ||||
|  | ||||
|         return status; | ||||
| @@ -399,8 +384,7 @@ namespace ix | ||||
|                 [this](const std::string& msg, | ||||
|                        size_t wireSize, | ||||
|                        bool decompressionError, | ||||
|                        WebSocketTransport::MessageKind messageKind) | ||||
|                 { | ||||
|                        WebSocketTransport::MessageKind messageKind) { | ||||
|                     WebSocketMessageType webSocketMessageType{WebSocketMessageType::Error}; | ||||
|                     switch (messageKind) | ||||
|                     { | ||||
| @@ -519,13 +503,13 @@ namespace ix | ||||
|         return sendMessage(text, SendMessageKind::Text, onProgressCallback); | ||||
|     } | ||||
|  | ||||
|     WebSocketSendInfo WebSocket::ping(const std::string& text, SendMessageKind pingType) | ||||
|     WebSocketSendInfo WebSocket::ping(const std::string& text) | ||||
|     { | ||||
|         // Standard limit ping message size | ||||
|         constexpr size_t pingMaxPayloadSize = 125; | ||||
|         if (text.size() > pingMaxPayloadSize) return WebSocketSendInfo(false); | ||||
|  | ||||
|         return sendMessage(text, pingType); | ||||
|         return sendMessage(text, SendMessageKind::Ping); | ||||
|     } | ||||
|  | ||||
|     WebSocketSendInfo WebSocket::sendMessage(const IXWebSocketSendData& message, | ||||
|   | ||||
| @@ -16,12 +16,11 @@ | ||||
| #include "IXWebSocketHttpHeaders.h" | ||||
| #include "IXWebSocketMessage.h" | ||||
| #include "IXWebSocketPerMessageDeflateOptions.h" | ||||
| #include "IXWebSocketSendData.h" | ||||
| #include "IXWebSocketSendInfo.h" | ||||
| #include "IXWebSocketSendData.h" | ||||
| #include "IXWebSocketTransport.h" | ||||
| #include <atomic> | ||||
| #include <condition_variable> | ||||
| #include <cstdint> | ||||
| #include <mutex> | ||||
| #include <string> | ||||
| #include <thread> | ||||
| @@ -54,8 +53,6 @@ namespace ix | ||||
|         void setPerMessageDeflateOptions( | ||||
|             const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions); | ||||
|         void setTLSOptions(const SocketTLSOptions& socketTLSOptions); | ||||
|         void setPingMessage(const std::string& sendMessage, | ||||
|                             SendMessageKind pingType = SendMessageKind::Ping); | ||||
|         void setPingInterval(int pingIntervalSecs); | ||||
|         void enablePong(); | ||||
|         void disablePong(); | ||||
| @@ -91,7 +88,7 @@ namespace ix | ||||
|                                        const OnProgressCallback& onProgressCallback = nullptr); | ||||
|         WebSocketSendInfo sendText(const std::string& text, | ||||
|                                    const OnProgressCallback& onProgressCallback = nullptr); | ||||
|         WebSocketSendInfo ping(const std::string& text,SendMessageKind pingType = SendMessageKind::Ping); | ||||
|         WebSocketSendInfo ping(const std::string& text); | ||||
|  | ||||
|         void close(uint16_t code = WebSocketCloseConstants::kNormalClosureCode, | ||||
|                    const std::string& reason = WebSocketCloseConstants::kNormalClosureMessage); | ||||
| @@ -106,7 +103,6 @@ namespace ix | ||||
|  | ||||
|         const std::string getUrl() const; | ||||
|         const WebSocketPerMessageDeflateOptions getPerMessageDeflateOptions() const; | ||||
|         const std::string getPingMessage() const; | ||||
|         int getPingInterval() const; | ||||
|         size_t bufferedAmount() const; | ||||
|  | ||||
| @@ -132,8 +128,7 @@ namespace ix | ||||
|         // Server | ||||
|         WebSocketInitResult connectToSocket(std::unique_ptr<Socket>, | ||||
|                                             int timeoutSecs, | ||||
|                                             bool enablePerMessageDeflate, | ||||
|                                             HttpRequestPtr request = nullptr); | ||||
|                                             bool enablePerMessageDeflate); | ||||
|  | ||||
|         WebSocketTransport _ws; | ||||
|  | ||||
| @@ -174,8 +169,6 @@ namespace ix | ||||
|         // Optional ping and pong timeout | ||||
|         int _pingIntervalSecs; | ||||
|         int _pingTimeoutSecs; | ||||
|         std::string _pingMessage; | ||||
|         SendMessageKind _pingType; | ||||
|         static const int kDefaultPingIntervalSecs; | ||||
|         static const int kDefaultPingTimeoutSecs; | ||||
|  | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
|  | ||||
| #include "IXWebSocketHandshake.h" | ||||
|  | ||||
| #include "IXBase64.h" | ||||
| #include "IXHttp.h" | ||||
| #include "IXSocketConnect.h" | ||||
| #include "IXStrCaseCompare.h" | ||||
| @@ -18,6 +17,7 @@ | ||||
| #include <random> | ||||
| #include <sstream> | ||||
|  | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     WebSocketHandshake::WebSocketHandshake( | ||||
| @@ -87,7 +87,6 @@ namespace ix | ||||
|     WebSocketInitResult WebSocketHandshake::clientHandshake( | ||||
|         const std::string& url, | ||||
|         const WebSocketHttpHeaders& extraHeaders, | ||||
|         const std::string& protocol, | ||||
|         const std::string& host, | ||||
|         const std::string& path, | ||||
|         int port, | ||||
| @@ -107,10 +106,15 @@ namespace ix | ||||
|             return WebSocketInitResult(false, 0, ss.str()); | ||||
|         } | ||||
|  | ||||
|         // Generate a random 16 bytes string and base64 encode it. | ||||
|         // | ||||
|         // Generate a random 24 bytes string which looks like it is base64 encoded | ||||
|         // y3JJHMbDL1EzLkh9GBhXDw== | ||||
|         // 0cb3Vd9HkbpVVumoS3Noka== | ||||
|         // | ||||
|         // See https://stackoverflow.com/questions/18265128/what-is-sec-websocket-key-for | ||||
|         std::string secWebSocketKey = macaron::Base64::Encode(genRandomString(16)); | ||||
|         // | ||||
|         std::string secWebSocketKey = genRandomString(22); | ||||
|         secWebSocketKey += "=="; | ||||
|  | ||||
|         std::stringstream ss; | ||||
|         ss << "GET " << path << " HTTP/1.1\r\n"; | ||||
| @@ -126,12 +130,6 @@ namespace ix | ||||
|             ss << "User-Agent: " << userAgent() << "\r\n"; | ||||
|         } | ||||
|  | ||||
|         // Set an origin header if missing | ||||
|         if (extraHeaders.find("Origin") == extraHeaders.end()) | ||||
|         { | ||||
|             ss << "Origin: " << protocol << "://" << host << ":" << port << "\r\n"; | ||||
|         } | ||||
|  | ||||
|         for (auto& it : extraHeaders) | ||||
|         { | ||||
|             ss << it.first << ": " << it.second << "\r\n"; | ||||
| @@ -247,26 +245,13 @@ namespace ix | ||||
|     } | ||||
|  | ||||
|     WebSocketInitResult WebSocketHandshake::serverHandshake(int timeoutSecs, | ||||
|                                                             bool enablePerMessageDeflate, | ||||
|                                                             HttpRequestPtr request) | ||||
|                                                             bool enablePerMessageDeflate) | ||||
|     { | ||||
|         _requestInitCancellation = false; | ||||
|  | ||||
|         auto isCancellationRequested = | ||||
|             makeCancellationRequestWithTimeout(timeoutSecs, _requestInitCancellation); | ||||
|  | ||||
|         std::string method; | ||||
|         std::string uri; | ||||
|         std::string httpVersion; | ||||
|  | ||||
|         if (request) | ||||
|         { | ||||
|             method = request->method; | ||||
|             uri = request->uri; | ||||
|             httpVersion = request->version; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|         // Read first line | ||||
|         auto lineResult = _socket->readLine(isCancellationRequested); | ||||
|         auto lineValid = lineResult.first; | ||||
| @@ -279,10 +264,9 @@ namespace ix | ||||
|  | ||||
|         // Validate request line (GET /foo HTTP/1.1\r\n) | ||||
|         auto requestLine = Http::parseRequestLine(line); | ||||
|             method = std::get<0>(requestLine); | ||||
|             uri = std::get<1>(requestLine); | ||||
|             httpVersion = std::get<2>(requestLine); | ||||
|         } | ||||
|         auto method = std::get<0>(requestLine); | ||||
|         auto uri = std::get<1>(requestLine); | ||||
|         auto httpVersion = std::get<2>(requestLine); | ||||
|  | ||||
|         if (method != "GET") | ||||
|         { | ||||
| @@ -295,23 +279,15 @@ namespace ix | ||||
|                                      "Invalid HTTP version, need HTTP/1.1, got: " + httpVersion); | ||||
|         } | ||||
|  | ||||
|         WebSocketHttpHeaders headers; | ||||
|         if (request) | ||||
|         { | ||||
|             headers = request->headers; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|         // Retrieve and validate HTTP headers | ||||
|         auto result = parseHttpHeaders(_socket, isCancellationRequested); | ||||
|         auto headersValid = result.first; | ||||
|             headers = result.second; | ||||
|         auto headers = result.second; | ||||
|  | ||||
|         if (!headersValid) | ||||
|         { | ||||
|             return sendErrorResponse(400, "Error parsing HTTP headers"); | ||||
|         } | ||||
|         } | ||||
|  | ||||
|         if (headers.find("sec-websocket-key") == headers.end()) | ||||
|         { | ||||
|   | ||||
| @@ -7,7 +7,6 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "IXCancellationRequest.h" | ||||
| #include "IXHttp.h" | ||||
| #include "IXSocket.h" | ||||
| #include "IXWebSocketHttpHeaders.h" | ||||
| #include "IXWebSocketInitResult.h" | ||||
| @@ -31,15 +30,12 @@ namespace ix | ||||
|  | ||||
|         WebSocketInitResult clientHandshake(const std::string& url, | ||||
|                                             const WebSocketHttpHeaders& extraHeaders, | ||||
|                                             const std::string& protocol, | ||||
|                                             const std::string& host, | ||||
|                                             const std::string& path, | ||||
|                                             int port, | ||||
|                                             int timeoutSecs); | ||||
|  | ||||
|         WebSocketInitResult serverHandshake(int timeoutSecs, | ||||
|                                             bool enablePerMessageDeflate, | ||||
|                                             HttpRequestPtr request = nullptr); | ||||
|         WebSocketInitResult serverHandshake(int timeoutSecs, bool enablePerMessageDeflate); | ||||
|  | ||||
|     private: | ||||
|         std::string genRandomString(const int len); | ||||
|   | ||||
| @@ -46,8 +46,6 @@ | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <cstdint> | ||||
|  | ||||
| #include "IXWebSocketPerMessageDeflate.h" | ||||
|  | ||||
| #include "IXUniquePtr.h" | ||||
|   | ||||
| @@ -10,7 +10,6 @@ | ||||
| #include "zlib.h" | ||||
| #endif | ||||
| #include <array> | ||||
| #include <cstdint> | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include "IXWebSocketSendData.h" | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <cstdint> | ||||
| #include <string> | ||||
|  | ||||
| namespace ix | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <cstdint> | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <iterator> | ||||
|   | ||||
| @@ -79,16 +79,7 @@ namespace ix | ||||
|     void WebSocketServer::handleConnection(std::unique_ptr<Socket> socket, | ||||
|                                            std::shared_ptr<ConnectionState> connectionState) | ||||
|     { | ||||
|         handleUpgrade(std::move(socket), connectionState); | ||||
|  | ||||
|         connectionState->setTerminated(); | ||||
|     } | ||||
|  | ||||
|     void WebSocketServer::handleUpgrade(std::unique_ptr<Socket> socket, | ||||
|                                         std::shared_ptr<ConnectionState> connectionState, | ||||
|                                         HttpRequestPtr request) | ||||
|     { | ||||
|         setThreadName("Srv:ws:" + connectionState->getId()); | ||||
|         setThreadName("WebSocketServer::" + connectionState->getId()); | ||||
|  | ||||
|         auto webSocket = std::make_shared<WebSocket>(); | ||||
|         if (_onConnectionCallback) | ||||
| @@ -98,7 +89,7 @@ namespace ix | ||||
|             if (!webSocket->isOnMessageCallbackRegistered()) | ||||
|             { | ||||
|                 logError("WebSocketServer Application developer error: Server callback improperly " | ||||
|                          "registered."); | ||||
|                          "registerered."); | ||||
|                 logError("Missing call to setOnMessageCallback inside setOnConnectionCallback."); | ||||
|                 connectionState->setTerminated(); | ||||
|                 return; | ||||
| @@ -108,8 +99,9 @@ namespace ix | ||||
|         { | ||||
|             WebSocket* webSocketRawPtr = webSocket.get(); | ||||
|             webSocket->setOnMessageCallback( | ||||
|                 [this, webSocketRawPtr, connectionState](const WebSocketMessagePtr& msg) | ||||
|                 { _onClientMessageCallback(connectionState, *webSocketRawPtr, msg); }); | ||||
|                 [this, webSocketRawPtr, connectionState](const WebSocketMessagePtr& msg) { | ||||
|                     _onClientMessageCallback(connectionState, *webSocketRawPtr, msg); | ||||
|                 }); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
| @@ -138,7 +130,7 @@ namespace ix | ||||
|         } | ||||
|  | ||||
|         auto status = webSocket->connectToSocket( | ||||
|             std::move(socket), _handshakeTimeoutSecs, _enablePerMessageDeflate, request); | ||||
|             std::move(socket), _handshakeTimeoutSecs, _enablePerMessageDeflate); | ||||
|         if (status.success) | ||||
|         { | ||||
|             // Process incoming messages and execute callbacks | ||||
| @@ -163,6 +155,8 @@ namespace ix | ||||
|                 logError("Cannot delete client"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         connectionState->setTerminated(); | ||||
|     } | ||||
|  | ||||
|     std::set<std::shared_ptr<WebSocket>> WebSocketServer::getClients() | ||||
| @@ -182,11 +176,9 @@ namespace ix | ||||
|     // | ||||
|     void WebSocketServer::makeBroadcastServer() | ||||
|     { | ||||
|         setOnClientMessageCallback( | ||||
|             [this](std::shared_ptr<ConnectionState> connectionState, | ||||
|         setOnClientMessageCallback([this](std::shared_ptr<ConnectionState> connectionState, | ||||
|                                           WebSocket& webSocket, | ||||
|                    const WebSocketMessagePtr& msg) | ||||
|             { | ||||
|                                           const WebSocketMessagePtr& msg) { | ||||
|             auto remoteIp = connectionState->getRemoteIp(); | ||||
|             if (msg->type == ix::WebSocketMessageType::Message) | ||||
|             { | ||||
|   | ||||
| @@ -55,7 +55,6 @@ namespace ix | ||||
|         int getHandshakeTimeoutSecs(); | ||||
|         bool isPongEnabled(); | ||||
|         bool isPerMessageDeflateEnabled(); | ||||
|  | ||||
|     private: | ||||
|         // Member variables | ||||
|         int _handshakeTimeoutSecs; | ||||
| @@ -74,10 +73,5 @@ namespace ix | ||||
|         virtual void handleConnection(std::unique_ptr<Socket> socket, | ||||
|                                       std::shared_ptr<ConnectionState> connectionState); | ||||
|         virtual size_t getConnectedClientsCount() final; | ||||
|  | ||||
|     protected: | ||||
|         void handleUpgrade(std::unique_ptr<Socket> socket, | ||||
|                            std::shared_ptr<ConnectionState> connectionState, | ||||
|                            HttpRequestPtr request = nullptr); | ||||
|     }; | ||||
| } // namespace ix | ||||
|   | ||||
| @@ -45,6 +45,7 @@ | ||||
| #include <cstdarg> | ||||
| #include <cstdlib> | ||||
| #include <sstream> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <string> | ||||
| #include <thread> | ||||
| @@ -53,6 +54,7 @@ | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     const std::string WebSocketTransport::kPingMessage("ixwebsocket::heartbeat"); | ||||
|     const int WebSocketTransport::kDefaultPingIntervalSecs(-1); | ||||
|     const bool WebSocketTransport::kDefaultEnablePong(true); | ||||
|     const int WebSocketTransport::kClosingMaximumWaitingDelayInMs(300); | ||||
| @@ -72,9 +74,6 @@ namespace ix | ||||
|         , _enablePong(kDefaultEnablePong) | ||||
|         , _pingIntervalSecs(kDefaultPingIntervalSecs) | ||||
|         , _pongReceived(false) | ||||
|         , _setCustomMessage(false) | ||||
|         , _kPingMessage("ixwebsocket::heartbeat") | ||||
|         , _pingType(SendMessageKind::Ping) | ||||
|         , _pingCount(0) | ||||
|         , _lastSendPingTimePoint(std::chrono::steady_clock::now()) | ||||
|     { | ||||
| @@ -140,7 +139,7 @@ namespace ix | ||||
|                                                   _enablePerMessageDeflate); | ||||
|  | ||||
|             result = webSocketHandshake.clientHandshake( | ||||
|                 remoteUrl, headers, protocol, host, path, port, timeoutSecs); | ||||
|                 remoteUrl, headers, host, path, port, timeoutSecs); | ||||
|  | ||||
|             if (result.http_status >= 300 && result.http_status < 400) | ||||
|             { | ||||
| @@ -171,8 +170,7 @@ namespace ix | ||||
|     // Server | ||||
|     WebSocketInitResult WebSocketTransport::connectToSocket(std::unique_ptr<Socket> socket, | ||||
|                                                             int timeoutSecs, | ||||
|                                                             bool enablePerMessageDeflate, | ||||
|                                                             HttpRequestPtr request) | ||||
|                                                             bool enablePerMessageDeflate) | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(_socketMutex); | ||||
|  | ||||
| @@ -189,8 +187,7 @@ namespace ix | ||||
|                                               _perMessageDeflateOptions, | ||||
|                                               _enablePerMessageDeflate); | ||||
|  | ||||
|         auto result = | ||||
|             webSocketHandshake.serverHandshake(timeoutSecs, enablePerMessageDeflate, request); | ||||
|         auto result = webSocketHandshake.serverHandshake(timeoutSecs, enablePerMessageDeflate); | ||||
|         if (result.success) | ||||
|         { | ||||
|             setReadyState(ReadyState::OPEN); | ||||
| @@ -251,52 +248,14 @@ namespace ix | ||||
|         return now - _lastSendPingTimePoint > std::chrono::seconds(_pingIntervalSecs); | ||||
|     } | ||||
|  | ||||
|     void WebSocketTransport::setPingMessage(const std::string& message, SendMessageKind pingType) | ||||
|     { | ||||
|         _setCustomMessage = true; | ||||
|         _kPingMessage = message; | ||||
|         _pingType = pingType; | ||||
|     } | ||||
|  | ||||
|     WebSocketSendInfo WebSocketTransport::sendHeartBeat(SendMessageKind pingMessage) | ||||
|     WebSocketSendInfo WebSocketTransport::sendHeartBeat() | ||||
|     { | ||||
|         _pongReceived = false; | ||||
|         std::stringstream ss; | ||||
|  | ||||
|         ss << _kPingMessage; | ||||
|         if (!_setCustomMessage) | ||||
|         { | ||||
|             ss << "::" << _pingIntervalSecs << "s" | ||||
|         ss << kPingMessage << "::" << _pingIntervalSecs << "s" | ||||
|            << "::" << _pingCount++; | ||||
|         } | ||||
|         if (pingMessage == SendMessageKind::Ping) | ||||
|         { | ||||
|         return sendPing(ss.str()); | ||||
|     } | ||||
|         else if (pingMessage == SendMessageKind::Binary) | ||||
|         { | ||||
|             WebSocketSendInfo info = sendBinary(ss.str(), nullptr); | ||||
|             if (info.success) | ||||
|             { | ||||
|                 std::lock_guard<std::mutex> lck(_lastSendPingTimePointMutex); | ||||
|                 _lastSendPingTimePoint = std::chrono::steady_clock::now(); | ||||
|             } | ||||
|             return info; | ||||
|         } | ||||
|         else if (pingMessage == SendMessageKind::Text) | ||||
|         { | ||||
|             WebSocketSendInfo info = sendText(ss.str(), nullptr); | ||||
|             if (info.success) | ||||
|             { | ||||
|                 std::lock_guard<std::mutex> lck(_lastSendPingTimePointMutex); | ||||
|                 _lastSendPingTimePoint = std::chrono::steady_clock::now(); | ||||
|             } | ||||
|             return info; | ||||
|         } | ||||
|  | ||||
|         // unknow type ping message | ||||
|         return {}; | ||||
|     } | ||||
|  | ||||
|     bool WebSocketTransport::closingDelayExceeded() | ||||
|     { | ||||
| @@ -311,9 +270,7 @@ namespace ix | ||||
|         { | ||||
|             if (pingIntervalExceeded()) | ||||
|             { | ||||
|                 // If it is not a 'ping' message of ping type, there is no need to judge whether | ||||
|                 // pong will receive it | ||||
|                 if (_pingType == SendMessageKind::Ping && !_pongReceived) | ||||
|                 if (!_pongReceived) | ||||
|                 { | ||||
|                     // ping response (PONG) exceeds the maximum delay, close the connection | ||||
|                     close(WebSocketCloseConstants::kInternalErrorCode, | ||||
| @@ -321,7 +278,7 @@ namespace ix | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     sendHeartBeat(_pingType); | ||||
|                     sendHeartBeat(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -700,7 +657,6 @@ namespace ix | ||||
|                 if (_readyState != ReadyState::CLOSING) | ||||
|                 { | ||||
|                     // send back the CLOSE frame | ||||
|                     setReadyState(ReadyState::CLOSING); | ||||
|                     sendCloseFrame(code, reason); | ||||
|  | ||||
|                     wakeUpFromPoll(SelectInterrupt::kCloseRequest); | ||||
| @@ -1073,10 +1029,7 @@ namespace ix | ||||
|             else if (ret <= 0) | ||||
|             { | ||||
|                 closeSocket(); | ||||
|                 if (_readyState != ReadyState::CLOSING) | ||||
|                 { | ||||
|                 setReadyState(ReadyState::CLOSED); | ||||
|                 } | ||||
|                 return false; | ||||
|             } | ||||
|             else | ||||
|   | ||||
| @@ -18,10 +18,9 @@ | ||||
| #include "IXWebSocketHttpHeaders.h" | ||||
| #include "IXWebSocketPerMessageDeflate.h" | ||||
| #include "IXWebSocketPerMessageDeflateOptions.h" | ||||
| #include "IXWebSocketSendData.h" | ||||
| #include "IXWebSocketSendInfo.h" | ||||
| #include "IXWebSocketSendData.h" | ||||
| #include <atomic> | ||||
| #include <cstdint> | ||||
| #include <functional> | ||||
| #include <list> | ||||
| #include <memory> | ||||
| @@ -87,8 +86,7 @@ namespace ix | ||||
|         // Server | ||||
|         WebSocketInitResult connectToSocket(std::unique_ptr<Socket> socket, | ||||
|                                             int timeoutSecs, | ||||
|                                             bool enablePerMessageDeflate, | ||||
|                                             HttpRequestPtr request = nullptr); | ||||
|                                             bool enablePerMessageDeflate); | ||||
|  | ||||
|         PollResult poll(); | ||||
|         WebSocketSendInfo sendBinary(const IXWebSocketSendData& message, | ||||
| @@ -110,12 +108,8 @@ namespace ix | ||||
|         void dispatch(PollResult pollResult, const OnMessageCallback& onMessageCallback); | ||||
|         size_t bufferedAmount() const; | ||||
|  | ||||
|         // set ping heartbeat message | ||||
|         void setPingMessage(const std::string& message, SendMessageKind pingType); | ||||
|  | ||||
|         // internal | ||||
|         // send any type of ping packet, not only 'ping' type | ||||
|         WebSocketSendInfo sendHeartBeat(SendMessageKind pingType); | ||||
|         WebSocketSendInfo sendHeartBeat(); | ||||
|  | ||||
|     private: | ||||
|         std::string _url; | ||||
| @@ -220,10 +214,7 @@ namespace ix | ||||
|         std::atomic<bool> _pongReceived; | ||||
|  | ||||
|         static const int kDefaultPingIntervalSecs; | ||||
|  | ||||
|         bool _setCustomMessage; | ||||
|         std::string _kPingMessage; | ||||
|         SendMessageKind _pingType; | ||||
|         static const std::string kPingMessage; | ||||
|         std::atomic<uint64_t> _pingCount; | ||||
|  | ||||
|         // We record when ping are being sent so that we can know when to send the next one | ||||
|   | ||||
| @@ -6,4 +6,4 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #define IX_WEBSOCKET_VERSION "11.4.4" | ||||
| #define IX_WEBSOCKET_VERSION "11.4.0" | ||||
|   | ||||
| @@ -13,24 +13,16 @@ all: brew | ||||
|  | ||||
| install: brew | ||||
|  | ||||
| -DCMAKE_INSTALL_PREFIX=/opt/homebrew | ||||
|  | ||||
| # Use -DCMAKE_INSTALL_PREFIX= to install into another location | ||||
| # on osx it is good practice to make /usr/local user writable | ||||
| # sudo chown -R `whoami`/staff /usr/local | ||||
| # | ||||
| # Those days (since Apple Silicon mac shipped), on macOS homebrew installs in /opt/homebrew, and /usr/local is readonly | ||||
| # | ||||
| # Release, Debug, MinSizeRel, RelWithDebInfo are the build types | ||||
| # | ||||
| # Default rule does not use python as that requires first time users to have Python3 installed | ||||
| # | ||||
| brew: | ||||
| ifeq ($(shell uname),Darwin) | ||||
| 	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_INSTALL_PREFIX=/opt/homebrew -DCMAKE_UNITY_BUILD=OFF -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; ninja install) | ||||
| else | ||||
| 	mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_UNITY_BUILD=OFF -DCMAKE_INSTALL_MESSAGE=LAZY -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; ninja install) | ||||
| endif | ||||
|  | ||||
| # Docker default target. We've had problems with OpenSSL and TLS 1.3 (on the | ||||
| # server side ?) and I can't work-around it easily, so we're using mbedtls on | ||||
|   | ||||
| @@ -1,20 +0,0 @@ | ||||
| -----BEGIN CERTIFICATE----- | ||||
| MIIDNDCCAhwCFCl+O/rR8flqYKKvD0iwkucFwMaLMA0GCSqGSIb3DQEBCwUAMEEx | ||||
| FDASBgNVBAoMC21hY2hpbmV6b25lMRQwEgYDVQQKDAtJWFdlYlNvY2tldDETMBEG | ||||
| A1UEAwwKdHJ1c3RlZC1jYTAgFw0yMjA4MjMyMDM2MjVaGA80MjgxMDYwMTIwMzYy | ||||
| NVowajELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMREwDwYDVQQHDAhCZXJrZWxl | ||||
| eTEbMBkGA1UECgwSRHVtbXkgT3JnYW5pemF0aW9uMR4wHAYDVQQDDBVub3QuYS52 | ||||
| YWxpZC5ob3N0Lm5hbWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2 | ||||
| 9N806IjCvA82zfk9CPNwaEHOygNDJSXaZ38YDSI4C+Wf2imnMxrLQKaoccHUi+9L | ||||
| 4rQN/hSCg+uTULQUZ0iyssGDaIh4IcAeoEcNlXYHTrgP+aAaby3q5zeZ80K3+6e4 | ||||
| rqcuBPV2lLszJu3XXwEKbDSxW3De0gc2N8m9DN8Lx7i70DRf0F4m6RIMFF/kHXwa | ||||
| zZLeG7rZb4xL684lmmQsWtk5Z600CvrBtUE7fQ7bhy0QhSt66kdTSL8IKQrbWcGj | ||||
| q0tggFlOqeyZSi73gqUiAIuGO8/tRgmp4HygNyC24jpOB5nObOPPJTUEf5Mk1Bum | ||||
| kD5a+yL6YbVdhiaK17wbAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAKsLXGLfO1IZ | ||||
| LbofGc7/TCQwRayR3RdG4864PBy97KfJWyizg7Wm4X4yPFRG+6q3X5NKW32Ew9lI | ||||
| jXulXCTjWOiSxiG4Pk20uczkOhWVHFdnS9gZvykPC/ElxBKPalT6MMstZWxpElsk | ||||
| rCDKXj4LkD0po8bZrjlgSZQQQk6XMRkoRai2GWLJqIjaNCSF8nqb1wM/1OE1tAwi | ||||
| polO1eFMA24yypvlXcNrNXjqcQ7LaoQFQltmi/RV+uTk7EK2F2jgYVzJ/pe2ET0i | ||||
| RIMbGZTlAiemDGL9SpMsxftG6fSmP6QqDqYExmmPlZMLprb2da/2kelWFA+VkvdG | ||||
| zFrnIcyfMY4= | ||||
| -----END CERTIFICATE----- | ||||
| @@ -1,27 +0,0 @@ | ||||
| -----BEGIN RSA PRIVATE KEY----- | ||||
| MIIEpAIBAAKCAQEAtvTfNOiIwrwPNs35PQjzcGhBzsoDQyUl2md/GA0iOAvln9op | ||||
| pzMay0CmqHHB1IvvS+K0Df4UgoPrk1C0FGdIsrLBg2iIeCHAHqBHDZV2B064D/mg | ||||
| Gm8t6uc3mfNCt/unuK6nLgT1dpS7Mybt118BCmw0sVtw3tIHNjfJvQzfC8e4u9A0 | ||||
| X9BeJukSDBRf5B18Gs2S3hu62W+MS+vOJZpkLFrZOWetNAr6wbVBO30O24ctEIUr | ||||
| eupHU0i/CCkK21nBo6tLYIBZTqnsmUou94KlIgCLhjvP7UYJqeB8oDcgtuI6TgeZ | ||||
| zmzjzyU1BH+TJNQbppA+Wvsi+mG1XYYmite8GwIDAQABAoIBAGRzAXG9EglI01mV | ||||
| sPfvyCi5NRhiFXRyGtxU4pTD8TuwXHxtfV0NU/KwJlBpVLBrvBCAAbeE/qHB6D9T | ||||
| metx4ZorRs/tPrAmZ6LpANnWa50LfUdYGK0qyZ0lIYPm6YS2KJnfWm6LznEyq60j | ||||
| /IW45YthaXTO7aOI0OjVrG+dd4CxU1g1NtCQ9bdDMDjfXFVnoOifXIl8W22eRMoZ | ||||
| LzCz+0sI0R0LenXCPT566de21F0NDkIK7NaQ1l5BMX4PA+RsN3cZlzyruA1woPKI | ||||
| aBR2LQGNrBfDVGMATtUm89RpWAftb8FmXqYUsM7zAzTO6dViitiB7OFlw7Ax15YH | ||||
| MTj5zGECgYEA35ocEEMfyahBN70bjyiqOHlzKwFjDl9DsUf8xqHsNhYAL+GrOK9A | ||||
| 8lN5ByzcnbV3TJtU4WYbPgQJld8gXFx4h3eS+SkA/ASkAdtgHfdMImZ1v7k3TIPf | ||||
| DXOCsHzELsQY6OgiI572Nwzx/Tl+0dFwaOfLjU9iEmmqL667j1Y4NiMCgYEA0Xch | ||||
| 9K/vwZ1I9gM3ySvG40R2TRriC9Bf8jwrEWeRsWNvBcqtMMrgwAMsMCKDugSZR7n6 | ||||
| o3WZV6mpvYVLFx0b93v07i7EpFP27kMw3gLNBKX62snR9JbqwAMK7tktgLds5pKM | ||||
| DvLHuAQ9XMMXMLX7WlSyhmtFeU7IDulTSHHqdakCgYEAywITCpy2xpKRK7bwx4gH | ||||
| C6EQc/IdahYJ0nHmSL0IRY6x+sbrelp7H8ezcVVEs5bmylGYvc/DWgm2XjCnI9P8 | ||||
| xhlFAhw9PZJFCT6QRISaxfy6WSgi0cBEieTeubd9MmxtpT/khuyy5AZHyj0iLAL4 | ||||
| CPayMwjopIj0r7f3p8qC3HsCgYBmq2kmYVI4aZrIkv02CtIatYTy+DlSJxnQRvOp | ||||
| PUWpWB6kDRrk7pxJIYT4NwKwG+7xvFQA6PR3hn7fmUUcGDWMEeMVGDFkho9ja+W4 | ||||
| /FB3dc/Gi+PwakS4RwWF20e1brLfNXeXICMKrHFTVYC5bIm+VgOHZW8RLa9bt7wN | ||||
| p2CPuQKBgQCjW+rCODmMzEues/I143mYMDdZ1IschtWGiXBNrpkHm/DcZSutbacm | ||||
| 5C7Kwv44pfA90NHDTjuaIgRgfeUTawkrl8uPXEuj80mW72agf5oS8lJzD+2jibCj | ||||
| Q4K52G+0LaTxHLZxufil28Rgja01c0mTcuLbhKtCgHl5EHP19wOKEg== | ||||
| -----END RSA PRIVATE KEY----- | ||||
| @@ -16,7 +16,7 @@ set (TEST_TARGET_NAMES | ||||
|   IXWebSocketServerTest | ||||
|   IXWebSocketTestConnectionDisconnection | ||||
|   IXUrlParserTest | ||||
|   # IXHttpClientTest ## FIXME httpbin.org does not seem normal | ||||
|   IXHttpClientTest | ||||
|   IXUnityBuildsTest | ||||
|   IXHttpTest | ||||
|   IXDNSLookupTest | ||||
| @@ -24,13 +24,14 @@ set (TEST_TARGET_NAMES | ||||
|   # IXWebSocketBroadcastTest ## FIXME was depending on cobra / take a broadcast server from ws | ||||
|   IXStrCaseCompareTest | ||||
|   IXExponentialBackoffTest | ||||
|   IXWebSocketCloseTest | ||||
| ) | ||||
|  | ||||
| # Some unittest don't work on windows yet | ||||
| # Windows without TLS does not have hmac yet | ||||
| if (UNIX) | ||||
|   list(APPEND TEST_TARGET_NAMES | ||||
|     IXWebSocketCloseTest | ||||
|  | ||||
|     # Fail on Windows in CI probably because the pathing is wrong and | ||||
|     # some resource files cannot be found | ||||
|     IXHttpServerTest | ||||
|   | ||||
| @@ -19,9 +19,13 @@ TEST_CASE("dns", "[net]") | ||||
|         auto dnsLookup = std::make_shared<DNSLookup>("www.google.com", 80); | ||||
|  | ||||
|         std::string errMsg; | ||||
|         auto res = dnsLookup->resolve(errMsg, [] { return false; }); | ||||
|         struct addrinfo* res; | ||||
|  | ||||
|         res = dnsLookup->resolve(errMsg, [] { return false; }); | ||||
|         std::cerr << "Error message: " << errMsg << std::endl; | ||||
|         REQUIRE(res != nullptr); | ||||
|  | ||||
|         dnsLookup->release(res); | ||||
|     } | ||||
|  | ||||
|     SECTION("Test resolving a non-existing hostname") | ||||
| @@ -29,7 +33,7 @@ TEST_CASE("dns", "[net]") | ||||
|         auto dnsLookup = std::make_shared<DNSLookup>("wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww", 80); | ||||
|  | ||||
|         std::string errMsg; | ||||
|         auto res = dnsLookup->resolve(errMsg, [] { return false; }); | ||||
|         struct addrinfo* res = dnsLookup->resolve(errMsg, [] { return false; }); | ||||
|         std::cerr << "Error message: " << errMsg << std::endl; | ||||
|         REQUIRE(res == nullptr); | ||||
|     } | ||||
| @@ -40,7 +44,7 @@ TEST_CASE("dns", "[net]") | ||||
|  | ||||
|         std::string errMsg; | ||||
|         // The callback returning true means we are requesting cancellation | ||||
|         auto res = dnsLookup->resolve(errMsg, [] { return true; }); | ||||
|         struct addrinfo* res = dnsLookup->resolve(errMsg, [] { return true; }); | ||||
|         std::cerr << "Error message: " << errMsg << std::endl; | ||||
|         REQUIRE(res == nullptr); | ||||
|     } | ||||
|   | ||||
| @@ -7,9 +7,7 @@ | ||||
| #include "catch.hpp" | ||||
| #include <cstdint> | ||||
| #include <iostream> | ||||
| #include <ixwebsocket/IXGetFreePort.h> | ||||
| #include <ixwebsocket/IXHttpClient.h> | ||||
| #include <ixwebsocket/IXHttpServer.h> | ||||
|  | ||||
| using namespace ix; | ||||
|  | ||||
| @@ -97,52 +95,6 @@ TEST_CASE("http_client", "[http]") | ||||
|     } | ||||
| #endif | ||||
|  | ||||
| #if defined(IXWEBSOCKET_USE_TLS) && !defined(IXWEBSOCKET_USE_SECURE_TRANSPORT) | ||||
|     SECTION("Disable hostname validation") | ||||
|     { | ||||
|         static auto test_cert_with_wrong_name = [](bool validate_hostname) | ||||
|         { | ||||
|             int port = getFreePort(); | ||||
|             ix::HttpServer server(port, "127.0.0.1"); | ||||
|  | ||||
|             SocketTLSOptions tlsOptionsServer; | ||||
|             tlsOptionsServer.tls = true; | ||||
|             tlsOptionsServer.caFile = "NONE"; | ||||
|             tlsOptionsServer.certFile = "./.certs/wrong-name-server-crt.pem"; | ||||
|             tlsOptionsServer.keyFile = "./.certs/wrong-name-server-key.pem"; | ||||
|             server.setTLSOptions(tlsOptionsServer); | ||||
|  | ||||
|             auto res = server.listen(); | ||||
|             REQUIRE(res.first); | ||||
|             server.start(); | ||||
|  | ||||
|             HttpClient httpClient; | ||||
|             SocketTLSOptions tlsOptionsClient; | ||||
|             tlsOptionsClient.caFile = "./.certs/trusted-ca-crt.pem"; | ||||
|             tlsOptionsClient.disable_hostname_validation = validate_hostname; | ||||
|             httpClient.setTLSOptions(tlsOptionsClient); | ||||
|  | ||||
|             std::string url("https://localhost:" + std::to_string(port)); | ||||
|             auto args = httpClient.createRequest(url); | ||||
|             args->connectTimeout = 10; | ||||
|             args->transferTimeout = 10; | ||||
|  | ||||
|             auto response = httpClient.get(url, args); | ||||
|  | ||||
|             std::cerr << "Status: " << response->statusCode << std::endl; | ||||
|             std::cerr << "Error code: " << (int) response->errorCode << std::endl; | ||||
|             std::cerr << "Error message: " << response->errorMsg << std::endl; | ||||
|  | ||||
|             server.stop(); | ||||
|             return std::make_tuple(response->errorCode, response->statusCode); | ||||
|         }; | ||||
|  | ||||
|         REQUIRE(test_cert_with_wrong_name(false) == | ||||
|                 std::make_tuple(HttpErrorCode::CannotConnect, 0)); | ||||
|         REQUIRE(test_cert_with_wrong_name(true) == std::make_tuple(HttpErrorCode::Ok, 404)); | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     SECTION("Async API, one call") | ||||
|     { | ||||
|         bool async = true; | ||||
|   | ||||
							
								
								
									
										31
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								ws/ws.cpp
									
									
									
									
									
								
							| @@ -77,6 +77,24 @@ namespace | ||||
|         return std::make_pair(res.first, std::string(vec.begin(), vec.end())); | ||||
|     } | ||||
|  | ||||
|     // Assume the file exists | ||||
|     std::string readBytes(const std::string& path) | ||||
|     { | ||||
|         std::vector<uint8_t> memblock; | ||||
|         std::ifstream file(path); | ||||
|  | ||||
|         file.seekg(0, file.end); | ||||
|         std::streamoff size = file.tellg(); | ||||
|         file.seekg(0, file.beg); | ||||
|  | ||||
|         memblock.reserve((size_t) size); | ||||
|         memblock.insert( | ||||
|             memblock.begin(), std::istream_iterator<char>(file), std::istream_iterator<char>()); | ||||
|  | ||||
|         std::string bytes(memblock.begin(), memblock.end()); | ||||
|         return bytes; | ||||
|     } | ||||
|  | ||||
|     std::string truncate(const std::string& str, size_t n) | ||||
|     { | ||||
|         if (str.size() < n) | ||||
| @@ -89,6 +107,12 @@ namespace | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     bool fileExists(const std::string& fileName) | ||||
|     { | ||||
|         std::ifstream infile(fileName); | ||||
|         return infile.good(); | ||||
|     } | ||||
|  | ||||
|     std::string extractFilename(const std::string& path) | ||||
|     { | ||||
|         std::string::size_type idx; | ||||
| @@ -892,8 +916,9 @@ namespace ix | ||||
|         auto dnsLookup = std::make_shared<DNSLookup>(hostname, 80); | ||||
|  | ||||
|         std::string errMsg; | ||||
|         struct addrinfo* res; | ||||
|  | ||||
|         auto res = dnsLookup->resolve(errMsg, [] { return false; }); | ||||
|         res = dnsLookup->resolve(errMsg, [] { return false; }); | ||||
|  | ||||
|         auto addr = res->ai_addr; | ||||
|  | ||||
| @@ -2461,8 +2486,10 @@ int main(int argc, char** argv) | ||||
|     bool verbose = false; | ||||
|     bool save = false; | ||||
|     bool quiet = false; | ||||
|     bool fluentd = false; | ||||
|     bool compress = false; | ||||
|     bool compressRequest = false; | ||||
|     bool stress = false; | ||||
|     bool disableAutomaticReconnection = false; | ||||
|     bool disablePerMessageDeflate = false; | ||||
|     bool greetings = false; | ||||
| @@ -2478,6 +2505,7 @@ int main(int argc, char** argv) | ||||
|     int transferTimeout = 1800; | ||||
|     int maxRedirects = 5; | ||||
|     int delayMs = -1; | ||||
|     int count = 1; | ||||
|     int msgCount = 1000 * 1000; | ||||
|     uint32_t maxWaitBetweenReconnectionRetries = 10 * 1000; // 10 seconds | ||||
|     int pingIntervalSecs = 30; | ||||
| @@ -2501,7 +2529,6 @@ int main(int argc, char** argv) | ||||
|                         "A (comma/space/colon) separated list of ciphers to use for TLS"); | ||||
|         app->add_flag("--tls", tlsOptions.tls, "Enable TLS (server only)"); | ||||
|         app->add_flag("--verify_none", verifyNone, "Disable peer cert verification"); | ||||
|         app->add_flag("--disable-hostname-validation", tlsOptions.disable_hostname_validation, "Disable validation of certificates' hostnames"); | ||||
|     }; | ||||
|  | ||||
|     app.add_flag("--version", version, "Print ws version"); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user