Compare commits
	
		
			14 Commits
		
	
	
		
			v11.4.3
			...
			feature/te
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					4a2a8e7b36 | ||
| 
						 | 
					f073203ac1 | ||
| 
						 | 
					1866d94550 | ||
| 
						 | 
					9157873f5b | ||
| 
						 | 
					aa2ca19895 | ||
| 
						 | 
					6cc21f3658 | ||
| 
						 | 
					679ce519dd | ||
| 
						 | 
					a5d4911a16 | ||
| 
						 | 
					b0fd119d14 | ||
| 
						 | 
					472cf68c31 | ||
| 
						 | 
					1e46466114 | ||
| 
						 | 
					0b8b5608dc | ||
| 
						 | 
					20a028e2ae | ||
| 
						 | 
					8d7b557be6 | 
							
								
								
									
										19
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,19 +0,0 @@
 | 
				
			|||||||
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'
 | 
					 | 
				
			||||||
@@ -11,6 +11,7 @@ project(ixwebsocket C CXX)
 | 
				
			|||||||
set (CMAKE_CXX_STANDARD 11)
 | 
					set (CMAKE_CXX_STANDARD 11)
 | 
				
			||||||
set (CXX_STANDARD_REQUIRED ON)
 | 
					set (CXX_STANDARD_REQUIRED ON)
 | 
				
			||||||
set (CMAKE_CXX_EXTENSIONS OFF)
 | 
					set (CMAKE_CXX_EXTENSIONS OFF)
 | 
				
			||||||
 | 
					set (CMAKE_EXPORT_COMPILE_COMMANDS yes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
option (BUILD_DEMO OFF)
 | 
					option (BUILD_DEMO OFF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -250,7 +251,7 @@ if (WIN32)
 | 
				
			|||||||
  endif()
 | 
					  endif()
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (UNIX)
 | 
					if (UNIX AND NOT APPLE)
 | 
				
			||||||
  set(THREADS_PREFER_PTHREAD_FLAG TRUE)
 | 
					  set(THREADS_PREFER_PTHREAD_FLAG TRUE)
 | 
				
			||||||
  find_package(Threads)
 | 
					  find_package(Threads)
 | 
				
			||||||
  target_link_libraries(ixwebsocket PRIVATE Threads::Threads)
 | 
					  target_link_libraries(ixwebsocket PRIVATE Threads::Threads)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,7 +54,7 @@ To use the installed package within a cmake project, use the following:
 | 
				
			|||||||
 # include headers
 | 
					 # include headers
 | 
				
			||||||
 include_directories(${IXWEBSOCKET_INCLUDE_DIR})
 | 
					 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 NOTFOUNS
 | 
					 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -301,7 +301,9 @@ This api was actually changed to take a weak_ptr<WebSocket> as the first argumen
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Run a server on localhost at a given port.
 | 
					// Run a server on localhost at a given port.
 | 
				
			||||||
// Bound host name, max connections and listen backlog can also be passed in as parameters.
 | 
					// Bound host name, max connections and listen backlog can also be passed in as parameters.
 | 
				
			||||||
ix::WebSocketServer server(port);
 | 
					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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
server.setOnConnectionCallback(
 | 
					server.setOnConnectionCallback(
 | 
				
			||||||
    [&server](std::weak_ptr<WebSocket> webSocket,
 | 
					    [&server](std::weak_ptr<WebSocket> webSocket,
 | 
				
			||||||
@@ -384,7 +386,9 @@ The webSocket reference is guaranteed to be always valid ; by design the callbac
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Run a server on localhost at a given port.
 | 
					// Run a server on localhost at a given port.
 | 
				
			||||||
// Bound host name, max connections and listen backlog can also be passed in as parameters.
 | 
					// Bound host name, max connections and listen backlog can also be passed in as parameters.
 | 
				
			||||||
ix::WebSocketServer server(port);
 | 
					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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
server.setOnClientMessageCallback([](std::shared_ptr<ix::ConnectionState> connectionState, ix::WebSocket & webSocket, const ix::WebSocketMessagePtr & msg) {
 | 
					server.setOnClientMessageCallback([](std::shared_ptr<ix::ConnectionState> connectionState, ix::WebSocket & webSocket, const ix::WebSocketMessagePtr & msg) {
 | 
				
			||||||
    // The ConnectionState object contains information about the connection,
 | 
					    // The ConnectionState object contains information about the connection,
 | 
				
			||||||
@@ -624,3 +628,5 @@ For a client, specifying `caFile` can be used if connecting to a server that use
 | 
				
			|||||||
For a server, specifying `caFile` implies that:
 | 
					For a server, specifying `caFile` implies that:
 | 
				
			||||||
1. You require clients to present a certificate
 | 
					1. You require clients to present a certificate
 | 
				
			||||||
1. It must be signed by one of the trusted roots in the file
 | 
					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`.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,7 @@
 | 
				
			|||||||
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
					 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace macaron {
 | 
					namespace macaron {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <chrono>
 | 
					#include <chrono>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <cstdint>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,9 +7,9 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <atomic>
 | 
					#include <atomic>
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@
 | 
				
			|||||||
#include <chrono>
 | 
					#include <chrono>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <thread>
 | 
					#include <thread>
 | 
				
			||||||
 | 
					#include <utility>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// mingw build quirks
 | 
					// mingw build quirks
 | 
				
			||||||
#if defined(_WIN32) && defined(__GNUC__)
 | 
					#if defined(_WIN32) && defined(__GNUC__)
 | 
				
			||||||
@@ -44,7 +45,7 @@ namespace ix
 | 
				
			|||||||
        ;
 | 
					        ;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct addrinfo* DNSLookup::getAddrInfo(const std::string& hostname,
 | 
					    DNSLookup::AddrInfoPtr DNSLookup::getAddrInfo(const std::string& hostname,
 | 
				
			||||||
                                            int port,
 | 
					                                            int port,
 | 
				
			||||||
                                            std::string& errMsg)
 | 
					                                            std::string& errMsg)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -63,10 +64,10 @@ namespace ix
 | 
				
			|||||||
            errMsg = gai_strerror(getaddrinfo_result);
 | 
					            errMsg = gai_strerror(getaddrinfo_result);
 | 
				
			||||||
            res = nullptr;
 | 
					            res = nullptr;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return res;
 | 
					        return AddrInfoPtr{ res, freeaddrinfo };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct addrinfo* DNSLookup::resolve(std::string& errMsg,
 | 
					    DNSLookup::AddrInfoPtr DNSLookup::resolve(std::string& errMsg,
 | 
				
			||||||
                                        const CancellationRequest& isCancellationRequested,
 | 
					                                        const CancellationRequest& isCancellationRequested,
 | 
				
			||||||
                                        bool cancellable)
 | 
					                                        bool cancellable)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -74,12 +75,7 @@ namespace ix
 | 
				
			|||||||
                           : resolveUnCancellable(errMsg, isCancellationRequested);
 | 
					                           : resolveUnCancellable(errMsg, isCancellationRequested);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void DNSLookup::release(struct addrinfo* addr)
 | 
					    DNSLookup::AddrInfoPtr DNSLookup::resolveUnCancellable(
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        freeaddrinfo(addr);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    struct addrinfo* DNSLookup::resolveUnCancellable(
 | 
					 | 
				
			||||||
        std::string& errMsg, const CancellationRequest& isCancellationRequested)
 | 
					        std::string& errMsg, const CancellationRequest& isCancellationRequested)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        errMsg = "no error";
 | 
					        errMsg = "no error";
 | 
				
			||||||
@@ -94,7 +90,7 @@ namespace ix
 | 
				
			|||||||
        return getAddrInfo(_hostname, _port, errMsg);
 | 
					        return getAddrInfo(_hostname, _port, errMsg);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct addrinfo* DNSLookup::resolveCancellable(
 | 
					    DNSLookup::AddrInfoPtr DNSLookup::resolveCancellable(
 | 
				
			||||||
        std::string& errMsg, const CancellationRequest& isCancellationRequested)
 | 
					        std::string& errMsg, const CancellationRequest& isCancellationRequested)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        errMsg = "no error";
 | 
					        errMsg = "no error";
 | 
				
			||||||
@@ -157,7 +153,7 @@ namespace ix
 | 
				
			|||||||
        // gone, so we use temporary variables (res) or we pass in by copy everything that
 | 
					        // gone, so we use temporary variables (res) or we pass in by copy everything that
 | 
				
			||||||
        // getAddrInfo needs to work.
 | 
					        // getAddrInfo needs to work.
 | 
				
			||||||
        std::string errMsg;
 | 
					        std::string errMsg;
 | 
				
			||||||
        struct addrinfo* res = getAddrInfo(hostname, port, errMsg);
 | 
					        auto res = getAddrInfo(hostname, port, errMsg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (auto lock = self.lock())
 | 
					        if (auto lock = self.lock())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -181,13 +177,13 @@ namespace ix
 | 
				
			|||||||
        return _errMsg;
 | 
					        return _errMsg;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void DNSLookup::setRes(struct addrinfo* addr)
 | 
					    void DNSLookup::setRes(DNSLookup::AddrInfoPtr addr)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::lock_guard<std::mutex> lock(_resMutex);
 | 
					        std::lock_guard<std::mutex> lock(_resMutex);
 | 
				
			||||||
        _res = addr;
 | 
					        _res = std::move(addr);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct addrinfo* DNSLookup::getRes()
 | 
					    DNSLookup::AddrInfoPtr DNSLookup::getRes()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::lock_guard<std::mutex> lock(_resMutex);
 | 
					        std::lock_guard<std::mutex> lock(_resMutex);
 | 
				
			||||||
        return _res;
 | 
					        return _res;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "IXCancellationRequest.h"
 | 
					#include "IXCancellationRequest.h"
 | 
				
			||||||
#include <atomic>
 | 
					#include <atomic>
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
#include <set>
 | 
					#include <set>
 | 
				
			||||||
@@ -24,22 +25,21 @@ namespace ix
 | 
				
			|||||||
    class DNSLookup : public std::enable_shared_from_this<DNSLookup>
 | 
					    class DNSLookup : public std::enable_shared_from_this<DNSLookup>
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
 | 
					        using AddrInfoPtr = std::shared_ptr<addrinfo>;
 | 
				
			||||||
        DNSLookup(const std::string& hostname, int port, int64_t wait = DNSLookup::kDefaultWait);
 | 
					        DNSLookup(const std::string& hostname, int port, int64_t wait = DNSLookup::kDefaultWait);
 | 
				
			||||||
        ~DNSLookup() = default;
 | 
					        ~DNSLookup() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        struct addrinfo* resolve(std::string& errMsg,
 | 
					        AddrInfoPtr resolve(std::string& errMsg,
 | 
				
			||||||
                                 const CancellationRequest& isCancellationRequested,
 | 
					                                 const CancellationRequest& isCancellationRequested,
 | 
				
			||||||
                                 bool cancellable = true);
 | 
					                                 bool cancellable = true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void release(struct addrinfo* addr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        struct addrinfo* resolveCancellable(std::string& errMsg,
 | 
					        AddrInfoPtr resolveCancellable(std::string& errMsg,
 | 
				
			||||||
                                            const CancellationRequest& isCancellationRequested);
 | 
					                                            const CancellationRequest& isCancellationRequested);
 | 
				
			||||||
        struct addrinfo* resolveUnCancellable(std::string& errMsg,
 | 
					        AddrInfoPtr resolveUnCancellable(std::string& errMsg,
 | 
				
			||||||
                                              const CancellationRequest& isCancellationRequested);
 | 
					                                              const CancellationRequest& isCancellationRequested);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static struct addrinfo* getAddrInfo(const std::string& hostname,
 | 
					        AddrInfoPtr getAddrInfo(const std::string& hostname,
 | 
				
			||||||
                                            int port,
 | 
					                                            int port,
 | 
				
			||||||
                                            std::string& errMsg);
 | 
					                                            std::string& errMsg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -48,15 +48,15 @@ namespace ix
 | 
				
			|||||||
        void setErrMsg(const std::string& errMsg);
 | 
					        void setErrMsg(const std::string& errMsg);
 | 
				
			||||||
        const std::string& getErrMsg();
 | 
					        const std::string& getErrMsg();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void setRes(struct addrinfo* addr);
 | 
					        void setRes(AddrInfoPtr addr);
 | 
				
			||||||
        struct addrinfo* getRes();
 | 
					        AddrInfoPtr getRes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string _hostname;
 | 
					        std::string _hostname;
 | 
				
			||||||
        int _port;
 | 
					        int _port;
 | 
				
			||||||
        int64_t _wait;
 | 
					        int64_t _wait;
 | 
				
			||||||
        const static int64_t kDefaultWait;
 | 
					        const static int64_t kDefaultWait;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        struct addrinfo* _res;
 | 
					        AddrInfoPtr _res;
 | 
				
			||||||
        std::mutex _resMutex;
 | 
					        std::mutex _resMutex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string _errMsg;
 | 
					        std::string _errMsg;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@
 | 
				
			|||||||
#include "IXProgressCallback.h"
 | 
					#include "IXProgressCallback.h"
 | 
				
			||||||
#include "IXWebSocketHttpHeaders.h"
 | 
					#include "IXWebSocketHttpHeaders.h"
 | 
				
			||||||
#include <atomic>
 | 
					#include <atomic>
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <tuple>
 | 
					#include <tuple>
 | 
				
			||||||
#include <unordered_map>
 | 
					#include <unordered_map>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@
 | 
				
			|||||||
#include "IXUserAgent.h"
 | 
					#include "IXUserAgent.h"
 | 
				
			||||||
#include "IXWebSocketHttpHeaders.h"
 | 
					#include "IXWebSocketHttpHeaders.h"
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <cstring>
 | 
					#include <cstring>
 | 
				
			||||||
#include <iomanip>
 | 
					#include <iomanip>
 | 
				
			||||||
#include <random>
 | 
					#include <random>
 | 
				
			||||||
@@ -139,8 +140,9 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        std::string protocol, host, path, query;
 | 
					        std::string protocol, host, path, query;
 | 
				
			||||||
        int port;
 | 
					        int port;
 | 
				
			||||||
 | 
					        bool isProtocolDefaultPort;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!UrlParser::parse(url, protocol, host, path, query, port))
 | 
					        if (!UrlParser::parse(url, protocol, host, path, query, port, isProtocolDefaultPort))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            std::stringstream ss;
 | 
					            std::stringstream ss;
 | 
				
			||||||
            ss << "Cannot parse url: " << url;
 | 
					            ss << "Cannot parse url: " << url;
 | 
				
			||||||
@@ -173,7 +175,12 @@ namespace ix
 | 
				
			|||||||
        // Build request string
 | 
					        // Build request string
 | 
				
			||||||
        std::stringstream ss;
 | 
					        std::stringstream ss;
 | 
				
			||||||
        ss << verb << " " << path << " HTTP/1.1\r\n";
 | 
					        ss << verb << " " << path << " HTTP/1.1\r\n";
 | 
				
			||||||
        ss << "Host: " << host << "\r\n";
 | 
					        ss << "Host: " << host;
 | 
				
			||||||
 | 
					        if (!isProtocolDefaultPort)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ss << ":" << port;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ss << "\r\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef IXWEBSOCKET_USE_ZLIB
 | 
					#ifdef IXWEBSOCKET_USE_ZLIB
 | 
				
			||||||
        if (args->compress && !args->onChunkCallback)
 | 
					        if (args->compress && !args->onChunkCallback)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@
 | 
				
			|||||||
#include "IXNetSystem.h"
 | 
					#include "IXNetSystem.h"
 | 
				
			||||||
#include "IXSocketConnect.h"
 | 
					#include "IXSocketConnect.h"
 | 
				
			||||||
#include "IXUserAgent.h"
 | 
					#include "IXUserAgent.h"
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <cstring>
 | 
					#include <cstring>
 | 
				
			||||||
#include <fstream>
 | 
					#include <fstream>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
@@ -40,6 +41,29 @@ namespace
 | 
				
			|||||||
        auto vec = res.second;
 | 
					        auto vec = res.second;
 | 
				
			||||||
        return std::make_pair(res.first, std::string(vec.begin(), vec.end()));
 | 
					        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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
@@ -51,28 +75,14 @@ namespace ix
 | 
				
			|||||||
                           int backlog,
 | 
					                           int backlog,
 | 
				
			||||||
                           size_t maxConnections,
 | 
					                           size_t maxConnections,
 | 
				
			||||||
                           int addressFamily,
 | 
					                           int addressFamily,
 | 
				
			||||||
                           int timeoutSecs)
 | 
					                           int timeoutSecs,
 | 
				
			||||||
        : SocketServer(port, host, backlog, maxConnections, addressFamily)
 | 
					                           int handshakeTimeoutSecs)
 | 
				
			||||||
        , _connectedClientsCount(0)
 | 
					        : WebSocketServer(port, host, backlog, maxConnections, handshakeTimeoutSecs, addressFamily)
 | 
				
			||||||
        , _timeoutSecs(timeoutSecs)
 | 
					        , _timeoutSecs(timeoutSecs)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        setDefaultConnectionCallback();
 | 
					        setDefaultConnectionCallback();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    HttpServer::~HttpServer()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        stop();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void HttpServer::stop()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        stopAcceptingConnections();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // FIXME: cancelling / closing active clients ...
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        SocketServer::stop();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void HttpServer::setOnConnectionCallback(const OnConnectionCallback& callback)
 | 
					    void HttpServer::setOnConnectionCallback(const OnConnectionCallback& callback)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _onConnectionCallback = callback;
 | 
					        _onConnectionCallback = callback;
 | 
				
			||||||
@@ -81,34 +91,35 @@ namespace ix
 | 
				
			|||||||
    void HttpServer::handleConnection(std::unique_ptr<Socket> socket,
 | 
					    void HttpServer::handleConnection(std::unique_ptr<Socket> socket,
 | 
				
			||||||
                                      std::shared_ptr<ConnectionState> connectionState)
 | 
					                                      std::shared_ptr<ConnectionState> connectionState)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _connectedClientsCount++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        auto ret = Http::parseRequest(socket, _timeoutSecs);
 | 
					        auto ret = Http::parseRequest(socket, _timeoutSecs);
 | 
				
			||||||
        // FIXME: handle errors in parseRequest
 | 
					        // FIXME: handle errors in parseRequest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (std::get<0>(ret))
 | 
					        if (std::get<0>(ret))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            auto response = _onConnectionCallback(std::get<2>(ret), connectionState);
 | 
					            auto request = std::get<2>(ret);
 | 
				
			||||||
            if (!Http::sendResponse(response, socket))
 | 
					            std::shared_ptr<ix::HttpResponse> response;
 | 
				
			||||||
 | 
					            if (request->headers["Upgrade"] == "websocket")
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                logError("Cannot send response");
 | 
					                WebSocketServer::handleUpgrade(std::move(socket), connectionState, request);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                auto response = _onConnectionCallback(request, connectionState);
 | 
				
			||||||
 | 
					                if (!Http::sendResponse(response, socket))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    logError("Cannot send response");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        connectionState->setTerminated();
 | 
					        connectionState->setTerminated();
 | 
				
			||||||
 | 
					 | 
				
			||||||
        _connectedClientsCount--;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    size_t HttpServer::getConnectedClientsCount()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return _connectedClientsCount;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void HttpServer::setDefaultConnectionCallback()
 | 
					    void HttpServer::setDefaultConnectionCallback()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        setOnConnectionCallback(
 | 
					        setOnConnectionCallback(
 | 
				
			||||||
            [this](HttpRequestPtr request,
 | 
					            [this](HttpRequestPtr request,
 | 
				
			||||||
                   std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr {
 | 
					                   std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
                std::string uri(request->uri);
 | 
					                std::string uri(request->uri);
 | 
				
			||||||
                if (uri.empty() || uri == "/")
 | 
					                if (uri.empty() || uri == "/")
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -117,6 +128,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                WebSocketHttpHeaders headers;
 | 
					                WebSocketHttpHeaders headers;
 | 
				
			||||||
                headers["Server"] = userAgent();
 | 
					                headers["Server"] = userAgent();
 | 
				
			||||||
 | 
					                headers["Content-Type"] = response_head_file(uri);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                std::string path("." + uri);
 | 
					                std::string path("." + uri);
 | 
				
			||||||
                auto res = readAsString(path);
 | 
					                auto res = readAsString(path);
 | 
				
			||||||
@@ -165,9 +177,9 @@ namespace ix
 | 
				
			|||||||
        // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections
 | 
					        // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections
 | 
				
			||||||
        //
 | 
					        //
 | 
				
			||||||
        setOnConnectionCallback(
 | 
					        setOnConnectionCallback(
 | 
				
			||||||
            [this,
 | 
					            [this, redirectUrl](HttpRequestPtr request,
 | 
				
			||||||
             redirectUrl](HttpRequestPtr request,
 | 
					                                std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr
 | 
				
			||||||
                          std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr {
 | 
					            {
 | 
				
			||||||
                WebSocketHttpHeaders headers;
 | 
					                WebSocketHttpHeaders headers;
 | 
				
			||||||
                headers["Server"] = userAgent();
 | 
					                headers["Server"] = userAgent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -198,7 +210,8 @@ namespace ix
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        setOnConnectionCallback(
 | 
					        setOnConnectionCallback(
 | 
				
			||||||
            [this](HttpRequestPtr request,
 | 
					            [this](HttpRequestPtr request,
 | 
				
			||||||
                   std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr {
 | 
					                   std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
                WebSocketHttpHeaders headers;
 | 
					                WebSocketHttpHeaders headers;
 | 
				
			||||||
                headers["Server"] = userAgent();
 | 
					                headers["Server"] = userAgent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,8 +7,8 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXHttp.h"
 | 
					#include "IXHttp.h"
 | 
				
			||||||
#include "IXSocketServer.h"
 | 
					 | 
				
			||||||
#include "IXWebSocket.h"
 | 
					#include "IXWebSocket.h"
 | 
				
			||||||
 | 
					#include "IXWebSocketServer.h"
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
@@ -19,7 +19,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    class HttpServer final : public SocketServer
 | 
					    class HttpServer final : public WebSocketServer
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
        using OnConnectionCallback =
 | 
					        using OnConnectionCallback =
 | 
				
			||||||
@@ -30,9 +30,8 @@ namespace ix
 | 
				
			|||||||
                   int backlog = SocketServer::kDefaultTcpBacklog,
 | 
					                   int backlog = SocketServer::kDefaultTcpBacklog,
 | 
				
			||||||
                   size_t maxConnections = SocketServer::kDefaultMaxConnections,
 | 
					                   size_t maxConnections = SocketServer::kDefaultMaxConnections,
 | 
				
			||||||
                   int addressFamily = SocketServer::kDefaultAddressFamily,
 | 
					                   int addressFamily = SocketServer::kDefaultAddressFamily,
 | 
				
			||||||
                   int timeoutSecs = HttpServer::kDefaultTimeoutSecs);
 | 
					                   int timeoutSecs = HttpServer::kDefaultTimeoutSecs,
 | 
				
			||||||
        virtual ~HttpServer();
 | 
					                   int handshakeTimeoutSecs = WebSocketServer::kDefaultHandShakeTimeoutSecs);
 | 
				
			||||||
        virtual void stop() final;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void setOnConnectionCallback(const OnConnectionCallback& callback);
 | 
					        void setOnConnectionCallback(const OnConnectionCallback& callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -41,10 +40,10 @@ namespace ix
 | 
				
			|||||||
        void makeDebugServer();
 | 
					        void makeDebugServer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int getTimeoutSecs();
 | 
					        int getTimeoutSecs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        // Member variables
 | 
					        // Member variables
 | 
				
			||||||
        OnConnectionCallback _onConnectionCallback;
 | 
					        OnConnectionCallback _onConnectionCallback;
 | 
				
			||||||
        std::atomic<int> _connectedClientsCount;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const static int kDefaultTimeoutSecs;
 | 
					        const static int kDefaultTimeoutSecs;
 | 
				
			||||||
        int _timeoutSecs;
 | 
					        int _timeoutSecs;
 | 
				
			||||||
@@ -52,7 +51,6 @@ namespace ix
 | 
				
			|||||||
        // Methods
 | 
					        // Methods
 | 
				
			||||||
        virtual void handleConnection(std::unique_ptr<Socket>,
 | 
					        virtual void handleConnection(std::unique_ptr<Socket>,
 | 
				
			||||||
                                      std::shared_ptr<ConnectionState> connectionState) final;
 | 
					                                      std::shared_ptr<ConnectionState> connectionState) final;
 | 
				
			||||||
        virtual size_t getConnectedClientsCount() final;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void setDefaultConnectionCallback();
 | 
					        void setDefaultConnectionCallback();
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef WIN32_LEAN_AND_MEAN
 | 
					#ifndef WIN32_LEAN_AND_MEAN
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,8 +6,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,8 +5,8 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXSelectInterrupt.h"
 | 
					#include "IXSelectInterrupt.h"
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <deque>
 | 
					#include <deque>
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXSelectInterrupt.h"
 | 
					#include "IXSelectInterrupt.h"
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,6 @@
 | 
				
			|||||||
#include <array>
 | 
					#include <array>
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <atomic>
 | 
					#include <atomic>
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -205,7 +205,9 @@ namespace ix
 | 
				
			|||||||
                _sslContext, SocketAppleSSL::readFromSocket, SocketAppleSSL::writeToSocket);
 | 
					                _sslContext, SocketAppleSSL::readFromSocket, SocketAppleSSL::writeToSocket);
 | 
				
			||||||
            SSLSetConnection(_sslContext, (SSLConnectionRef)(long) _sockfd);
 | 
					            SSLSetConnection(_sslContext, (SSLConnectionRef)(long) _sockfd);
 | 
				
			||||||
            SSLSetProtocolVersionMin(_sslContext, kTLSProtocol12);
 | 
					            SSLSetProtocolVersionMin(_sslContext, kTLSProtocol12);
 | 
				
			||||||
            SSLSetPeerDomainName(_sslContext, host.c_str(), host.size());
 | 
					
 | 
				
			||||||
 | 
					            if (!_tlsOptions.disable_hostname_validation)
 | 
				
			||||||
 | 
					                SSLSetPeerDomainName(_sslContext, host.c_str(), host.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (_tlsOptions.isPeerVerifyDisabled())
 | 
					            if (_tlsOptions.isPeerVerifyDisabled())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -102,7 +102,7 @@ namespace ix
 | 
				
			|||||||
        // First do DNS resolution
 | 
					        // First do DNS resolution
 | 
				
			||||||
        //
 | 
					        //
 | 
				
			||||||
        auto dnsLookup = std::make_shared<DNSLookup>(hostname, port);
 | 
					        auto dnsLookup = std::make_shared<DNSLookup>(hostname, port);
 | 
				
			||||||
        struct addrinfo* res = dnsLookup->resolve(errMsg, isCancellationRequested);
 | 
					        auto res = dnsLookup->resolve(errMsg, isCancellationRequested);
 | 
				
			||||||
        if (res == nullptr)
 | 
					        if (res == nullptr)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return -1;
 | 
					            return -1;
 | 
				
			||||||
@@ -112,7 +112,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // iterate through the records to find a working peer
 | 
					        // iterate through the records to find a working peer
 | 
				
			||||||
        struct addrinfo* address;
 | 
					        struct addrinfo* address;
 | 
				
			||||||
        for (address = res; address != nullptr; address = address->ai_next)
 | 
					        for (address = res.get(); address != nullptr; address = address->ai_next)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            //
 | 
					            //
 | 
				
			||||||
            // Second try to connect to the remote host
 | 
					            // Second try to connect to the remote host
 | 
				
			||||||
@@ -124,7 +124,6 @@ namespace ix
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        freeaddrinfo(res);
 | 
					 | 
				
			||||||
        return sockfd;
 | 
					        return sockfd;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@
 | 
				
			|||||||
#include "IXNetSystem.h"
 | 
					#include "IXNetSystem.h"
 | 
				
			||||||
#include "IXSocket.h"
 | 
					#include "IXSocket.h"
 | 
				
			||||||
#include "IXSocketConnect.h"
 | 
					#include "IXSocketConnect.h"
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
@@ -48,7 +49,7 @@ namespace ix
 | 
				
			|||||||
        mbedtls_pk_init(&_pkey);
 | 
					        mbedtls_pk_init(&_pkey);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool SocketMbedTLS::loadSystemCertificates(std::string& errorMsg)
 | 
					    bool SocketMbedTLS::loadSystemCertificates(std::string& /* errorMsg */)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
        DWORD flags = CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG |
 | 
					        DWORD flags = CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG |
 | 
				
			||||||
@@ -195,10 +196,13 @@ namespace ix
 | 
				
			|||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!host.empty() && mbedtls_ssl_set_hostname(&_ssl, host.c_str()) != 0)
 | 
					        if (!_tlsOptions.disable_hostname_validation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            errMsg = "SNI setup failed";
 | 
					            if (!host.empty() && mbedtls_ssl_set_hostname(&_ssl, host.c_str()) != 0)
 | 
				
			||||||
            return false;
 | 
					            {
 | 
				
			||||||
 | 
					                errMsg = "SNI setup failed";
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -301,7 +301,11 @@ namespace ix
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool SocketOpenSSL::openSSLCheckServerCert(SSL* ssl,
 | 
					    bool SocketOpenSSL::openSSLCheckServerCert(SSL* ssl,
 | 
				
			||||||
 | 
					#if OPENSSL_VERSION_NUMBER < 0x10100000L
 | 
				
			||||||
                                               const std::string& hostname,
 | 
					                                               const std::string& hostname,
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					                                               const std::string& /* hostname */,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
                                               std::string& errMsg)
 | 
					                                               std::string& errMsg)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        X509* server_cert = SSL_get_peer_certificate(ssl);
 | 
					        X509* server_cert = SSL_get_peer_certificate(ssl);
 | 
				
			||||||
@@ -390,6 +394,11 @@ namespace ix
 | 
				
			|||||||
            int connect_result = SSL_connect(_ssl_connection);
 | 
					            int connect_result = SSL_connect(_ssl_connection);
 | 
				
			||||||
            if (connect_result == 1)
 | 
					            if (connect_result == 1)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					                if (_tlsOptions.disable_hostname_validation)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return openSSLCheckServerCert(_ssl_connection, host, errMsg);
 | 
					                return openSSLCheckServerCert(_ssl_connection, host, errMsg);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            int reason = SSL_get_error(_ssl_connection, connect_result);
 | 
					            int reason = SSL_get_error(_ssl_connection, connect_result);
 | 
				
			||||||
@@ -754,8 +763,11 @@ namespace ix
 | 
				
			|||||||
            // (The docs say that this should work from 1.0.2, and is the default from
 | 
					            // (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
 | 
					            // 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.)
 | 
					            // below is enabled for all versions prior to 1.1.0.)
 | 
				
			||||||
            X509_VERIFY_PARAM* param = SSL_get0_param(_ssl_connection);
 | 
					            if (!_tlsOptions.disable_hostname_validation)
 | 
				
			||||||
            X509_VERIFY_PARAM_set1_host(param, host.c_str(), host.size());
 | 
					            {
 | 
				
			||||||
 | 
					                X509_VERIFY_PARAM* param = SSL_get0_param(_ssl_connection);
 | 
				
			||||||
 | 
					                X509_VERIFY_PARAM_set1_host(param, host.c_str(), host.size());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
            handshakeSuccessful = openSSLClientHandshake(host, errMsg, isCancellationRequested);
 | 
					            handshakeSuccessful = openSSLClientHandshake(host, errMsg, isCancellationRequested);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,9 @@ namespace ix
 | 
				
			|||||||
        // whether tls is enabled, used for server code
 | 
					        // whether tls is enabled, used for server code
 | 
				
			||||||
        bool tls = false;
 | 
					        bool tls = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // whether to skip validating the peer's hostname against the certificate presented
 | 
				
			||||||
 | 
					        bool disable_hostname_validation = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool hasCertAndKey() const;
 | 
					        bool hasCertAndKey() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool isUsingSystemDefaults() const;
 | 
					        bool isUsingSystemDefaults() const;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -333,6 +333,19 @@ namespace
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return Result;
 | 
					        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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
@@ -343,6 +356,18 @@ namespace ix
 | 
				
			|||||||
                          std::string& path,
 | 
					                          std::string& path,
 | 
				
			||||||
                          std::string& query,
 | 
					                          std::string& query,
 | 
				
			||||||
                          int& port)
 | 
					                          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);
 | 
					        clParseURL res = clParseURL::ParseURL(url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -356,23 +381,12 @@ namespace ix
 | 
				
			|||||||
        path = res.m_Path;
 | 
					        path = res.m_Path;
 | 
				
			||||||
        query = res.m_Query;
 | 
					        query = res.m_Query;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const auto protocolPort = getProtocolPort(protocol);
 | 
				
			||||||
        if (!res.GetPort(&port))
 | 
					        if (!res.GetPort(&port))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (protocol == "ws" || protocol == "http")
 | 
					            port = protocolPort;
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                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())
 | 
					        if (path.empty())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,5 +19,13 @@ namespace ix
 | 
				
			|||||||
                          std::string& path,
 | 
					                          std::string& path,
 | 
				
			||||||
                          std::string& query,
 | 
					                          std::string& query,
 | 
				
			||||||
                          int& port);
 | 
					                          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
 | 
					} // namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "IXUuid.h"
 | 
					#include "IXUuid.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <iomanip>
 | 
					#include <iomanip>
 | 
				
			||||||
#include <random>
 | 
					#include <random>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@
 | 
				
			|||||||
#include "IXWebSocketHandshake.h"
 | 
					#include "IXWebSocketHandshake.h"
 | 
				
			||||||
#include <cassert>
 | 
					#include <cassert>
 | 
				
			||||||
#include <cmath>
 | 
					#include <cmath>
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace
 | 
					namespace
 | 
				
			||||||
@@ -39,9 +40,11 @@ namespace ix
 | 
				
			|||||||
        , _handshakeTimeoutSecs(kDefaultHandShakeTimeoutSecs)
 | 
					        , _handshakeTimeoutSecs(kDefaultHandShakeTimeoutSecs)
 | 
				
			||||||
        , _enablePong(kDefaultEnablePong)
 | 
					        , _enablePong(kDefaultEnablePong)
 | 
				
			||||||
        , _pingIntervalSecs(kDefaultPingIntervalSecs)
 | 
					        , _pingIntervalSecs(kDefaultPingIntervalSecs)
 | 
				
			||||||
 | 
					        , _pingType(SendMessageKind::Ping)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _ws.setOnCloseCallback(
 | 
					        _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(
 | 
					                _onMessageCallback(
 | 
				
			||||||
                    ix::make_unique<WebSocketMessage>(WebSocketMessageType::Close,
 | 
					                    ix::make_unique<WebSocketMessage>(WebSocketMessageType::Close,
 | 
				
			||||||
                                                      emptyMsg,
 | 
					                                                      emptyMsg,
 | 
				
			||||||
@@ -100,6 +103,17 @@ namespace ix
 | 
				
			|||||||
        return _perMessageDeflateOptions;
 | 
					        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)
 | 
					    void WebSocket::setPingInterval(int pingIntervalSecs)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::lock_guard<std::mutex> lock(_configMutex);
 | 
					        std::lock_guard<std::mutex> lock(_configMutex);
 | 
				
			||||||
@@ -232,7 +246,7 @@ namespace ix
 | 
				
			|||||||
        if (_pingIntervalSecs > 0)
 | 
					        if (_pingIntervalSecs > 0)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Send a heart beat right away
 | 
					            // Send a heart beat right away
 | 
				
			||||||
            _ws.sendHeartBeat();
 | 
					            _ws.sendHeartBeat(_pingType);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return status;
 | 
					        return status;
 | 
				
			||||||
@@ -240,7 +254,8 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    WebSocketInitResult WebSocket::connectToSocket(std::unique_ptr<Socket> socket,
 | 
					    WebSocketInitResult WebSocket::connectToSocket(std::unique_ptr<Socket> socket,
 | 
				
			||||||
                                                   int timeoutSecs,
 | 
					                                                   int timeoutSecs,
 | 
				
			||||||
                                                   bool enablePerMessageDeflate)
 | 
					                                                   bool enablePerMessageDeflate,
 | 
				
			||||||
 | 
					                                                   HttpRequestPtr request)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            std::lock_guard<std::mutex> lock(_configMutex);
 | 
					            std::lock_guard<std::mutex> lock(_configMutex);
 | 
				
			||||||
@@ -249,7 +264,7 @@ namespace ix
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        WebSocketInitResult status =
 | 
					        WebSocketInitResult status =
 | 
				
			||||||
            _ws.connectToSocket(std::move(socket), timeoutSecs, enablePerMessageDeflate);
 | 
					            _ws.connectToSocket(std::move(socket), timeoutSecs, enablePerMessageDeflate, request);
 | 
				
			||||||
        if (!status.success)
 | 
					        if (!status.success)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return status;
 | 
					            return status;
 | 
				
			||||||
@@ -266,7 +281,7 @@ namespace ix
 | 
				
			|||||||
        if (_pingIntervalSecs > 0)
 | 
					        if (_pingIntervalSecs > 0)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Send a heart beat right away
 | 
					            // Send a heart beat right away
 | 
				
			||||||
            _ws.sendHeartBeat();
 | 
					            _ws.sendHeartBeat(_pingType);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return status;
 | 
					        return status;
 | 
				
			||||||
@@ -384,8 +399,9 @@ namespace ix
 | 
				
			|||||||
                [this](const std::string& msg,
 | 
					                [this](const std::string& msg,
 | 
				
			||||||
                       size_t wireSize,
 | 
					                       size_t wireSize,
 | 
				
			||||||
                       bool decompressionError,
 | 
					                       bool decompressionError,
 | 
				
			||||||
                       WebSocketTransport::MessageKind messageKind) {
 | 
					                       WebSocketTransport::MessageKind messageKind)
 | 
				
			||||||
                    WebSocketMessageType webSocketMessageType{WebSocketMessageType::Error};
 | 
					                {
 | 
				
			||||||
 | 
					                    WebSocketMessageType webSocketMessageType {WebSocketMessageType::Error};
 | 
				
			||||||
                    switch (messageKind)
 | 
					                    switch (messageKind)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        case WebSocketTransport::MessageKind::MSG_TEXT:
 | 
					                        case WebSocketTransport::MessageKind::MSG_TEXT:
 | 
				
			||||||
@@ -503,13 +519,13 @@ namespace ix
 | 
				
			|||||||
        return sendMessage(text, SendMessageKind::Text, onProgressCallback);
 | 
					        return sendMessage(text, SendMessageKind::Text, onProgressCallback);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketSendInfo WebSocket::ping(const std::string& text)
 | 
					    WebSocketSendInfo WebSocket::ping(const std::string& text, SendMessageKind pingType)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // Standard limit ping message size
 | 
					        // Standard limit ping message size
 | 
				
			||||||
        constexpr size_t pingMaxPayloadSize = 125;
 | 
					        constexpr size_t pingMaxPayloadSize = 125;
 | 
				
			||||||
        if (text.size() > pingMaxPayloadSize) return WebSocketSendInfo(false);
 | 
					        if (text.size() > pingMaxPayloadSize) return WebSocketSendInfo(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return sendMessage(text, SendMessageKind::Ping);
 | 
					        return sendMessage(text, pingType);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketSendInfo WebSocket::sendMessage(const IXWebSocketSendData& message,
 | 
					    WebSocketSendInfo WebSocket::sendMessage(const IXWebSocketSendData& message,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,11 +16,12 @@
 | 
				
			|||||||
#include "IXWebSocketHttpHeaders.h"
 | 
					#include "IXWebSocketHttpHeaders.h"
 | 
				
			||||||
#include "IXWebSocketMessage.h"
 | 
					#include "IXWebSocketMessage.h"
 | 
				
			||||||
#include "IXWebSocketPerMessageDeflateOptions.h"
 | 
					#include "IXWebSocketPerMessageDeflateOptions.h"
 | 
				
			||||||
#include "IXWebSocketSendInfo.h"
 | 
					 | 
				
			||||||
#include "IXWebSocketSendData.h"
 | 
					#include "IXWebSocketSendData.h"
 | 
				
			||||||
 | 
					#include "IXWebSocketSendInfo.h"
 | 
				
			||||||
#include "IXWebSocketTransport.h"
 | 
					#include "IXWebSocketTransport.h"
 | 
				
			||||||
#include <atomic>
 | 
					#include <atomic>
 | 
				
			||||||
#include <condition_variable>
 | 
					#include <condition_variable>
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <thread>
 | 
					#include <thread>
 | 
				
			||||||
@@ -53,6 +54,8 @@ namespace ix
 | 
				
			|||||||
        void setPerMessageDeflateOptions(
 | 
					        void setPerMessageDeflateOptions(
 | 
				
			||||||
            const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions);
 | 
					            const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions);
 | 
				
			||||||
        void setTLSOptions(const SocketTLSOptions& socketTLSOptions);
 | 
					        void setTLSOptions(const SocketTLSOptions& socketTLSOptions);
 | 
				
			||||||
 | 
					        void setPingMessage(const std::string& sendMessage,
 | 
				
			||||||
 | 
					                            SendMessageKind pingType = SendMessageKind::Ping);
 | 
				
			||||||
        void setPingInterval(int pingIntervalSecs);
 | 
					        void setPingInterval(int pingIntervalSecs);
 | 
				
			||||||
        void enablePong();
 | 
					        void enablePong();
 | 
				
			||||||
        void disablePong();
 | 
					        void disablePong();
 | 
				
			||||||
@@ -88,7 +91,7 @@ namespace ix
 | 
				
			|||||||
                                       const OnProgressCallback& onProgressCallback = nullptr);
 | 
					                                       const OnProgressCallback& onProgressCallback = nullptr);
 | 
				
			||||||
        WebSocketSendInfo sendText(const std::string& text,
 | 
					        WebSocketSendInfo sendText(const std::string& text,
 | 
				
			||||||
                                   const OnProgressCallback& onProgressCallback = nullptr);
 | 
					                                   const OnProgressCallback& onProgressCallback = nullptr);
 | 
				
			||||||
        WebSocketSendInfo ping(const std::string& text);
 | 
					        WebSocketSendInfo ping(const std::string& text,SendMessageKind pingType = SendMessageKind::Ping);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void close(uint16_t code = WebSocketCloseConstants::kNormalClosureCode,
 | 
					        void close(uint16_t code = WebSocketCloseConstants::kNormalClosureCode,
 | 
				
			||||||
                   const std::string& reason = WebSocketCloseConstants::kNormalClosureMessage);
 | 
					                   const std::string& reason = WebSocketCloseConstants::kNormalClosureMessage);
 | 
				
			||||||
@@ -103,6 +106,7 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const std::string getUrl() const;
 | 
					        const std::string getUrl() const;
 | 
				
			||||||
        const WebSocketPerMessageDeflateOptions getPerMessageDeflateOptions() const;
 | 
					        const WebSocketPerMessageDeflateOptions getPerMessageDeflateOptions() const;
 | 
				
			||||||
 | 
					        const std::string getPingMessage() const;
 | 
				
			||||||
        int getPingInterval() const;
 | 
					        int getPingInterval() const;
 | 
				
			||||||
        size_t bufferedAmount() const;
 | 
					        size_t bufferedAmount() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -128,7 +132,8 @@ namespace ix
 | 
				
			|||||||
        // Server
 | 
					        // Server
 | 
				
			||||||
        WebSocketInitResult connectToSocket(std::unique_ptr<Socket>,
 | 
					        WebSocketInitResult connectToSocket(std::unique_ptr<Socket>,
 | 
				
			||||||
                                            int timeoutSecs,
 | 
					                                            int timeoutSecs,
 | 
				
			||||||
                                            bool enablePerMessageDeflate);
 | 
					                                            bool enablePerMessageDeflate,
 | 
				
			||||||
 | 
					                                            HttpRequestPtr request = nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        WebSocketTransport _ws;
 | 
					        WebSocketTransport _ws;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -169,6 +174,8 @@ namespace ix
 | 
				
			|||||||
        // Optional ping and pong timeout
 | 
					        // Optional ping and pong timeout
 | 
				
			||||||
        int _pingIntervalSecs;
 | 
					        int _pingIntervalSecs;
 | 
				
			||||||
        int _pingTimeoutSecs;
 | 
					        int _pingTimeoutSecs;
 | 
				
			||||||
 | 
					        std::string _pingMessage;
 | 
				
			||||||
 | 
					        SendMessageKind _pingType;
 | 
				
			||||||
        static const int kDefaultPingIntervalSecs;
 | 
					        static const int kDefaultPingIntervalSecs;
 | 
				
			||||||
        static const int kDefaultPingTimeoutSecs;
 | 
					        static const int kDefaultPingTimeoutSecs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -240,28 +240,42 @@ namespace ix
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketInitResult WebSocketHandshake::serverHandshake(int timeoutSecs,
 | 
					    WebSocketInitResult WebSocketHandshake::serverHandshake(int timeoutSecs,
 | 
				
			||||||
                                                            bool enablePerMessageDeflate)
 | 
					                                                            bool enablePerMessageDeflate,
 | 
				
			||||||
 | 
					                                                            HttpRequestPtr request)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _requestInitCancellation = false;
 | 
					        _requestInitCancellation = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto isCancellationRequested =
 | 
					        auto isCancellationRequested =
 | 
				
			||||||
            makeCancellationRequestWithTimeout(timeoutSecs, _requestInitCancellation);
 | 
					            makeCancellationRequestWithTimeout(timeoutSecs, _requestInitCancellation);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Read first line
 | 
					        std::string method;
 | 
				
			||||||
        auto lineResult = _socket->readLine(isCancellationRequested);
 | 
					        std::string uri;
 | 
				
			||||||
        auto lineValid = lineResult.first;
 | 
					        std::string httpVersion;
 | 
				
			||||||
        auto line = lineResult.second;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!lineValid)
 | 
					        if (request)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return sendErrorResponse(400, "Error reading HTTP request line");
 | 
					            method = request->method;
 | 
				
			||||||
 | 
					            uri = request->uri;
 | 
				
			||||||
 | 
					            httpVersion = request->version;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // Read first line
 | 
				
			||||||
 | 
					            auto lineResult = _socket->readLine(isCancellationRequested);
 | 
				
			||||||
 | 
					            auto lineValid = lineResult.first;
 | 
				
			||||||
 | 
					            auto line = lineResult.second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Validate request line (GET /foo HTTP/1.1\r\n)
 | 
					            if (!lineValid)
 | 
				
			||||||
        auto requestLine = Http::parseRequestLine(line);
 | 
					            {
 | 
				
			||||||
        auto method = std::get<0>(requestLine);
 | 
					                return sendErrorResponse(400, "Error reading HTTP request line");
 | 
				
			||||||
        auto uri = std::get<1>(requestLine);
 | 
					            }
 | 
				
			||||||
        auto httpVersion = std::get<2>(requestLine);
 | 
					
 | 
				
			||||||
 | 
					            // 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);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (method != "GET")
 | 
					        if (method != "GET")
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -274,14 +288,22 @@ namespace ix
 | 
				
			|||||||
                                     "Invalid HTTP version, need HTTP/1.1, got: " + httpVersion);
 | 
					                                     "Invalid HTTP version, need HTTP/1.1, got: " + httpVersion);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Retrieve and validate HTTP headers
 | 
					        WebSocketHttpHeaders headers;
 | 
				
			||||||
        auto result = parseHttpHeaders(_socket, isCancellationRequested);
 | 
					        if (request)
 | 
				
			||||||
        auto headersValid = result.first;
 | 
					 | 
				
			||||||
        auto headers = result.second;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!headersValid)
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return sendErrorResponse(400, "Error parsing HTTP headers");
 | 
					            headers = request->headers;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // Retrieve and validate HTTP headers
 | 
				
			||||||
 | 
					            auto result = parseHttpHeaders(_socket, isCancellationRequested);
 | 
				
			||||||
 | 
					            auto headersValid = result.first;
 | 
				
			||||||
 | 
					            headers = result.second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!headersValid)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return sendErrorResponse(400, "Error parsing HTTP headers");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (headers.find("sec-websocket-key") == headers.end())
 | 
					        if (headers.find("sec-websocket-key") == headers.end())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXCancellationRequest.h"
 | 
					#include "IXCancellationRequest.h"
 | 
				
			||||||
 | 
					#include "IXHttp.h"
 | 
				
			||||||
#include "IXSocket.h"
 | 
					#include "IXSocket.h"
 | 
				
			||||||
#include "IXWebSocketHttpHeaders.h"
 | 
					#include "IXWebSocketHttpHeaders.h"
 | 
				
			||||||
#include "IXWebSocketInitResult.h"
 | 
					#include "IXWebSocketInitResult.h"
 | 
				
			||||||
@@ -35,7 +36,9 @@ namespace ix
 | 
				
			|||||||
                                            int port,
 | 
					                                            int port,
 | 
				
			||||||
                                            int timeoutSecs);
 | 
					                                            int timeoutSecs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        WebSocketInitResult serverHandshake(int timeoutSecs, bool enablePerMessageDeflate);
 | 
					        WebSocketInitResult serverHandshake(int timeoutSecs,
 | 
				
			||||||
 | 
					                                            bool enablePerMessageDeflate,
 | 
				
			||||||
 | 
					                                            HttpRequestPtr request = nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        std::string genRandomString(const int len);
 | 
					        std::string genRandomString(const int len);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,6 +46,8 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXWebSocketPerMessageDeflate.h"
 | 
					#include "IXWebSocketPerMessageDeflate.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "IXUniquePtr.h"
 | 
					#include "IXUniquePtr.h"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@
 | 
				
			|||||||
#include "zlib.h"
 | 
					#include "zlib.h"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#include <array>
 | 
					#include <array>
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
#include "IXWebSocketSendData.h"
 | 
					#include "IXWebSocketSendData.h"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
#include <iterator>
 | 
					#include <iterator>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,6 +78,15 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void WebSocketServer::handleConnection(std::unique_ptr<Socket> socket,
 | 
					    void WebSocketServer::handleConnection(std::unique_ptr<Socket> socket,
 | 
				
			||||||
                                           std::shared_ptr<ConnectionState> connectionState)
 | 
					                                           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("Srv:ws:" + connectionState->getId());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -89,7 +98,7 @@ namespace ix
 | 
				
			|||||||
            if (!webSocket->isOnMessageCallbackRegistered())
 | 
					            if (!webSocket->isOnMessageCallbackRegistered())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                logError("WebSocketServer Application developer error: Server callback improperly "
 | 
					                logError("WebSocketServer Application developer error: Server callback improperly "
 | 
				
			||||||
                         "registerered.");
 | 
					                         "registered.");
 | 
				
			||||||
                logError("Missing call to setOnMessageCallback inside setOnConnectionCallback.");
 | 
					                logError("Missing call to setOnMessageCallback inside setOnConnectionCallback.");
 | 
				
			||||||
                connectionState->setTerminated();
 | 
					                connectionState->setTerminated();
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
@@ -99,9 +108,8 @@ namespace ix
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            WebSocket* webSocketRawPtr = webSocket.get();
 | 
					            WebSocket* webSocketRawPtr = webSocket.get();
 | 
				
			||||||
            webSocket->setOnMessageCallback(
 | 
					            webSocket->setOnMessageCallback(
 | 
				
			||||||
                [this, webSocketRawPtr, connectionState](const WebSocketMessagePtr& msg) {
 | 
					                [this, webSocketRawPtr, connectionState](const WebSocketMessagePtr& msg)
 | 
				
			||||||
                    _onClientMessageCallback(connectionState, *webSocketRawPtr, msg);
 | 
					                { _onClientMessageCallback(connectionState, *webSocketRawPtr, msg); });
 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -130,7 +138,7 @@ namespace ix
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto status = webSocket->connectToSocket(
 | 
					        auto status = webSocket->connectToSocket(
 | 
				
			||||||
            std::move(socket), _handshakeTimeoutSecs, _enablePerMessageDeflate);
 | 
					            std::move(socket), _handshakeTimeoutSecs, _enablePerMessageDeflate, request);
 | 
				
			||||||
        if (status.success)
 | 
					        if (status.success)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Process incoming messages and execute callbacks
 | 
					            // Process incoming messages and execute callbacks
 | 
				
			||||||
@@ -155,8 +163,6 @@ namespace ix
 | 
				
			|||||||
                logError("Cannot delete client");
 | 
					                logError("Cannot delete client");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        connectionState->setTerminated();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::set<std::shared_ptr<WebSocket>> WebSocketServer::getClients()
 | 
					    std::set<std::shared_ptr<WebSocket>> WebSocketServer::getClients()
 | 
				
			||||||
@@ -176,28 +182,30 @@ namespace ix
 | 
				
			|||||||
    //
 | 
					    //
 | 
				
			||||||
    void WebSocketServer::makeBroadcastServer()
 | 
					    void WebSocketServer::makeBroadcastServer()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        setOnClientMessageCallback([this](std::shared_ptr<ConnectionState> connectionState,
 | 
					        setOnClientMessageCallback(
 | 
				
			||||||
                                          WebSocket& webSocket,
 | 
					            [this](std::shared_ptr<ConnectionState> connectionState,
 | 
				
			||||||
                                          const WebSocketMessagePtr& msg) {
 | 
					                   WebSocket& webSocket,
 | 
				
			||||||
            auto remoteIp = connectionState->getRemoteIp();
 | 
					                   const WebSocketMessagePtr& msg)
 | 
				
			||||||
            if (msg->type == ix::WebSocketMessageType::Message)
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                for (auto&& client : getClients())
 | 
					                auto remoteIp = connectionState->getRemoteIp();
 | 
				
			||||||
 | 
					                if (msg->type == ix::WebSocketMessageType::Message)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    if (client.get() != &webSocket)
 | 
					                    for (auto&& client : getClients())
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        client->send(msg->str, msg->binary);
 | 
					                        if (client.get() != &webSocket)
 | 
				
			||||||
 | 
					 | 
				
			||||||
                        // Make sure the OS send buffer is flushed before moving on
 | 
					 | 
				
			||||||
                        do
 | 
					 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            std::chrono::duration<double, std::milli> duration(500);
 | 
					                            client->send(msg->str, msg->binary);
 | 
				
			||||||
                            std::this_thread::sleep_for(duration);
 | 
					
 | 
				
			||||||
                        } while (client->bufferedAmount() != 0);
 | 
					                            // Make sure the OS send buffer is flushed before moving on
 | 
				
			||||||
 | 
					                            do
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                std::chrono::duration<double, std::milli> duration(500);
 | 
				
			||||||
 | 
					                                std::this_thread::sleep_for(duration);
 | 
				
			||||||
 | 
					                            } while (client->bufferedAmount() != 0);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            });
 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool WebSocketServer::listenAndStart()
 | 
					    bool WebSocketServer::listenAndStart()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,6 +55,7 @@ namespace ix
 | 
				
			|||||||
        int getHandshakeTimeoutSecs();
 | 
					        int getHandshakeTimeoutSecs();
 | 
				
			||||||
        bool isPongEnabled();
 | 
					        bool isPongEnabled();
 | 
				
			||||||
        bool isPerMessageDeflateEnabled();
 | 
					        bool isPerMessageDeflateEnabled();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        // Member variables
 | 
					        // Member variables
 | 
				
			||||||
        int _handshakeTimeoutSecs;
 | 
					        int _handshakeTimeoutSecs;
 | 
				
			||||||
@@ -73,5 +74,10 @@ namespace ix
 | 
				
			|||||||
        virtual void handleConnection(std::unique_ptr<Socket> socket,
 | 
					        virtual void handleConnection(std::unique_ptr<Socket> socket,
 | 
				
			||||||
                                      std::shared_ptr<ConnectionState> connectionState);
 | 
					                                      std::shared_ptr<ConnectionState> connectionState);
 | 
				
			||||||
        virtual size_t getConnectedClientsCount() final;
 | 
					        virtual size_t getConnectedClientsCount() final;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected:
 | 
				
			||||||
 | 
					        void handleUpgrade(std::unique_ptr<Socket> socket,
 | 
				
			||||||
 | 
					                           std::shared_ptr<ConnectionState> connectionState,
 | 
				
			||||||
 | 
					                           HttpRequestPtr request = nullptr);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,6 @@
 | 
				
			|||||||
#include <cstdarg>
 | 
					#include <cstdarg>
 | 
				
			||||||
#include <cstdlib>
 | 
					#include <cstdlib>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <thread>
 | 
					#include <thread>
 | 
				
			||||||
@@ -54,7 +53,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    const std::string WebSocketTransport::kPingMessage("ixwebsocket::heartbeat");
 | 
					 | 
				
			||||||
    const int WebSocketTransport::kDefaultPingIntervalSecs(-1);
 | 
					    const int WebSocketTransport::kDefaultPingIntervalSecs(-1);
 | 
				
			||||||
    const bool WebSocketTransport::kDefaultEnablePong(true);
 | 
					    const bool WebSocketTransport::kDefaultEnablePong(true);
 | 
				
			||||||
    const int WebSocketTransport::kClosingMaximumWaitingDelayInMs(300);
 | 
					    const int WebSocketTransport::kClosingMaximumWaitingDelayInMs(300);
 | 
				
			||||||
@@ -73,6 +71,9 @@ namespace ix
 | 
				
			|||||||
        , _closingTimePoint(std::chrono::steady_clock::now())
 | 
					        , _closingTimePoint(std::chrono::steady_clock::now())
 | 
				
			||||||
        , _enablePong(kDefaultEnablePong)
 | 
					        , _enablePong(kDefaultEnablePong)
 | 
				
			||||||
        , _pingIntervalSecs(kDefaultPingIntervalSecs)
 | 
					        , _pingIntervalSecs(kDefaultPingIntervalSecs)
 | 
				
			||||||
 | 
					        , _setCustomMessage(false)
 | 
				
			||||||
 | 
					        , _kPingMessage("ixwebsocket::heartbeat")
 | 
				
			||||||
 | 
					        , _pingType(SendMessageKind::Ping)
 | 
				
			||||||
        , _pongReceived(false)
 | 
					        , _pongReceived(false)
 | 
				
			||||||
        , _pingCount(0)
 | 
					        , _pingCount(0)
 | 
				
			||||||
        , _lastSendPingTimePoint(std::chrono::steady_clock::now())
 | 
					        , _lastSendPingTimePoint(std::chrono::steady_clock::now())
 | 
				
			||||||
@@ -170,7 +171,8 @@ namespace ix
 | 
				
			|||||||
    // Server
 | 
					    // Server
 | 
				
			||||||
    WebSocketInitResult WebSocketTransport::connectToSocket(std::unique_ptr<Socket> socket,
 | 
					    WebSocketInitResult WebSocketTransport::connectToSocket(std::unique_ptr<Socket> socket,
 | 
				
			||||||
                                                            int timeoutSecs,
 | 
					                                                            int timeoutSecs,
 | 
				
			||||||
                                                            bool enablePerMessageDeflate)
 | 
					                                                            bool enablePerMessageDeflate,
 | 
				
			||||||
 | 
					                                                            HttpRequestPtr request)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::lock_guard<std::mutex> lock(_socketMutex);
 | 
					        std::lock_guard<std::mutex> lock(_socketMutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -187,7 +189,8 @@ namespace ix
 | 
				
			|||||||
                                              _perMessageDeflateOptions,
 | 
					                                              _perMessageDeflateOptions,
 | 
				
			||||||
                                              _enablePerMessageDeflate);
 | 
					                                              _enablePerMessageDeflate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto result = webSocketHandshake.serverHandshake(timeoutSecs, enablePerMessageDeflate);
 | 
					        auto result =
 | 
				
			||||||
 | 
					            webSocketHandshake.serverHandshake(timeoutSecs, enablePerMessageDeflate, request);
 | 
				
			||||||
        if (result.success)
 | 
					        if (result.success)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            setReadyState(ReadyState::OPEN);
 | 
					            setReadyState(ReadyState::OPEN);
 | 
				
			||||||
@@ -248,13 +251,51 @@ namespace ix
 | 
				
			|||||||
        return now - _lastSendPingTimePoint > std::chrono::seconds(_pingIntervalSecs);
 | 
					        return now - _lastSendPingTimePoint > std::chrono::seconds(_pingIntervalSecs);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WebSocketSendInfo WebSocketTransport::sendHeartBeat()
 | 
					    void WebSocketTransport::setPingMessage(const std::string& message, SendMessageKind pingType)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _setCustomMessage = true;
 | 
				
			||||||
 | 
					        _kPingMessage = message;
 | 
				
			||||||
 | 
					        _pingType = pingType;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    WebSocketSendInfo WebSocketTransport::sendHeartBeat(SendMessageKind pingMessage)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _pongReceived = false;
 | 
					        _pongReceived = false;
 | 
				
			||||||
        std::stringstream ss;
 | 
					        std::stringstream ss;
 | 
				
			||||||
        ss << kPingMessage << "::" << _pingIntervalSecs << "s"
 | 
					
 | 
				
			||||||
           << "::" << _pingCount++;
 | 
					        ss << _kPingMessage;
 | 
				
			||||||
        return sendPing(ss.str());
 | 
					        if (!_setCustomMessage)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ss << "::" << _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()
 | 
					    bool WebSocketTransport::closingDelayExceeded()
 | 
				
			||||||
@@ -270,7 +311,9 @@ namespace ix
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            if (pingIntervalExceeded())
 | 
					            if (pingIntervalExceeded())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (!_pongReceived)
 | 
					                // 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)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    // ping response (PONG) exceeds the maximum delay, close the connection
 | 
					                    // ping response (PONG) exceeds the maximum delay, close the connection
 | 
				
			||||||
                    close(WebSocketCloseConstants::kInternalErrorCode,
 | 
					                    close(WebSocketCloseConstants::kInternalErrorCode,
 | 
				
			||||||
@@ -278,7 +321,7 @@ namespace ix
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    sendHeartBeat();
 | 
					                    sendHeartBeat(_pingType);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,15 +18,17 @@
 | 
				
			|||||||
#include "IXWebSocketHttpHeaders.h"
 | 
					#include "IXWebSocketHttpHeaders.h"
 | 
				
			||||||
#include "IXWebSocketPerMessageDeflate.h"
 | 
					#include "IXWebSocketPerMessageDeflate.h"
 | 
				
			||||||
#include "IXWebSocketPerMessageDeflateOptions.h"
 | 
					#include "IXWebSocketPerMessageDeflateOptions.h"
 | 
				
			||||||
#include "IXWebSocketSendInfo.h"
 | 
					 | 
				
			||||||
#include "IXWebSocketSendData.h"
 | 
					#include "IXWebSocketSendData.h"
 | 
				
			||||||
 | 
					#include "IXWebSocketSendInfo.h"
 | 
				
			||||||
#include <atomic>
 | 
					#include <atomic>
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <list>
 | 
					#include <list>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <mutex>
 | 
					#include <mutex>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <deque>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -86,7 +88,8 @@ namespace ix
 | 
				
			|||||||
        // Server
 | 
					        // Server
 | 
				
			||||||
        WebSocketInitResult connectToSocket(std::unique_ptr<Socket> socket,
 | 
					        WebSocketInitResult connectToSocket(std::unique_ptr<Socket> socket,
 | 
				
			||||||
                                            int timeoutSecs,
 | 
					                                            int timeoutSecs,
 | 
				
			||||||
                                            bool enablePerMessageDeflate);
 | 
					                                            bool enablePerMessageDeflate,
 | 
				
			||||||
 | 
					                                            HttpRequestPtr request = nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        PollResult poll();
 | 
					        PollResult poll();
 | 
				
			||||||
        WebSocketSendInfo sendBinary(const IXWebSocketSendData& message,
 | 
					        WebSocketSendInfo sendBinary(const IXWebSocketSendData& message,
 | 
				
			||||||
@@ -108,8 +111,12 @@ namespace ix
 | 
				
			|||||||
        void dispatch(PollResult pollResult, const OnMessageCallback& onMessageCallback);
 | 
					        void dispatch(PollResult pollResult, const OnMessageCallback& onMessageCallback);
 | 
				
			||||||
        size_t bufferedAmount() const;
 | 
					        size_t bufferedAmount() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // set ping heartbeat message
 | 
				
			||||||
 | 
					        void setPingMessage(const std::string& message, SendMessageKind pingType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // internal
 | 
					        // internal
 | 
				
			||||||
        WebSocketSendInfo sendHeartBeat();
 | 
					        // send any type of ping packet, not only 'ping' type
 | 
				
			||||||
 | 
					        WebSocketSendInfo sendHeartBeat(SendMessageKind pingType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        std::string _url;
 | 
					        std::string _url;
 | 
				
			||||||
@@ -150,7 +157,7 @@ namespace ix
 | 
				
			|||||||
        // Contains all messages that were fetched in the last socket read.
 | 
					        // Contains all messages that were fetched in the last socket read.
 | 
				
			||||||
        // This could be a mix of control messages (Close, Ping, etc...) and
 | 
					        // This could be a mix of control messages (Close, Ping, etc...) and
 | 
				
			||||||
        // data messages. That buffer is resized
 | 
					        // data messages. That buffer is resized
 | 
				
			||||||
        std::vector<uint8_t> _rxbuf;
 | 
					        std::deque<uint8_t> _rxbuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Contains all messages that are waiting to be sent
 | 
					        // Contains all messages that are waiting to be sent
 | 
				
			||||||
        std::vector<uint8_t> _txbuf;
 | 
					        std::vector<uint8_t> _txbuf;
 | 
				
			||||||
@@ -214,7 +221,10 @@ namespace ix
 | 
				
			|||||||
        std::atomic<bool> _pongReceived;
 | 
					        std::atomic<bool> _pongReceived;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static const int kDefaultPingIntervalSecs;
 | 
					        static const int kDefaultPingIntervalSecs;
 | 
				
			||||||
        static const std::string kPingMessage;
 | 
					
 | 
				
			||||||
 | 
					        bool _setCustomMessage;
 | 
				
			||||||
 | 
					        std::string _kPingMessage;
 | 
				
			||||||
 | 
					        SendMessageKind _pingType;
 | 
				
			||||||
        std::atomic<uint64_t> _pingCount;
 | 
					        std::atomic<uint64_t> _pingCount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // We record when ping are being sent so that we can know when to send the next one
 | 
					        // We record when ping are being sent so that we can know when to send the next one
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								test/.certs/wrong-name-server-crt.pem
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								test/.certs/wrong-name-server-crt.pem
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					-----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-----
 | 
				
			||||||
							
								
								
									
										27
									
								
								test/.certs/wrong-name-server-key.pem
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								test/.certs/wrong-name-server-key.pem
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					-----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-----
 | 
				
			||||||
@@ -19,13 +19,9 @@ TEST_CASE("dns", "[net]")
 | 
				
			|||||||
        auto dnsLookup = std::make_shared<DNSLookup>("www.google.com", 80);
 | 
					        auto dnsLookup = std::make_shared<DNSLookup>("www.google.com", 80);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string errMsg;
 | 
					        std::string errMsg;
 | 
				
			||||||
        struct addrinfo* res;
 | 
					        auto res = dnsLookup->resolve(errMsg, [] { return false; });
 | 
				
			||||||
 | 
					 | 
				
			||||||
        res = dnsLookup->resolve(errMsg, [] { return false; });
 | 
					 | 
				
			||||||
        std::cerr << "Error message: " << errMsg << std::endl;
 | 
					        std::cerr << "Error message: " << errMsg << std::endl;
 | 
				
			||||||
        REQUIRE(res != nullptr);
 | 
					        REQUIRE(res != nullptr);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        dnsLookup->release(res);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SECTION("Test resolving a non-existing hostname")
 | 
					    SECTION("Test resolving a non-existing hostname")
 | 
				
			||||||
@@ -33,7 +29,7 @@ TEST_CASE("dns", "[net]")
 | 
				
			|||||||
        auto dnsLookup = std::make_shared<DNSLookup>("wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww", 80);
 | 
					        auto dnsLookup = std::make_shared<DNSLookup>("wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww", 80);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string errMsg;
 | 
					        std::string errMsg;
 | 
				
			||||||
        struct addrinfo* res = dnsLookup->resolve(errMsg, [] { return false; });
 | 
					        auto res = dnsLookup->resolve(errMsg, [] { return false; });
 | 
				
			||||||
        std::cerr << "Error message: " << errMsg << std::endl;
 | 
					        std::cerr << "Error message: " << errMsg << std::endl;
 | 
				
			||||||
        REQUIRE(res == nullptr);
 | 
					        REQUIRE(res == nullptr);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -44,7 +40,7 @@ TEST_CASE("dns", "[net]")
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        std::string errMsg;
 | 
					        std::string errMsg;
 | 
				
			||||||
        // The callback returning true means we are requesting cancellation
 | 
					        // The callback returning true means we are requesting cancellation
 | 
				
			||||||
        struct addrinfo* res = dnsLookup->resolve(errMsg, [] { return true; });
 | 
					        auto res = dnsLookup->resolve(errMsg, [] { return true; });
 | 
				
			||||||
        std::cerr << "Error message: " << errMsg << std::endl;
 | 
					        std::cerr << "Error message: " << errMsg << std::endl;
 | 
				
			||||||
        REQUIRE(res == nullptr);
 | 
					        REQUIRE(res == nullptr);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,9 @@
 | 
				
			|||||||
#include "catch.hpp"
 | 
					#include "catch.hpp"
 | 
				
			||||||
#include <cstdint>
 | 
					#include <cstdint>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXGetFreePort.h>
 | 
				
			||||||
#include <ixwebsocket/IXHttpClient.h>
 | 
					#include <ixwebsocket/IXHttpClient.h>
 | 
				
			||||||
 | 
					#include <ixwebsocket/IXHttpServer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace ix;
 | 
					using namespace ix;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -95,6 +97,52 @@ TEST_CASE("http_client", "[http]")
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
#endif
 | 
					#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")
 | 
					    SECTION("Async API, one call")
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        bool async = true;
 | 
					        bool async = true;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										31
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								ws/ws.cpp
									
									
									
									
									
								
							@@ -77,24 +77,6 @@ namespace
 | 
				
			|||||||
        return std::make_pair(res.first, std::string(vec.begin(), vec.end()));
 | 
					        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)
 | 
					    std::string truncate(const std::string& str, size_t n)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (str.size() < n)
 | 
					        if (str.size() < n)
 | 
				
			||||||
@@ -107,12 +89,6 @@ namespace
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool fileExists(const std::string& fileName)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        std::ifstream infile(fileName);
 | 
					 | 
				
			||||||
        return infile.good();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::string extractFilename(const std::string& path)
 | 
					    std::string extractFilename(const std::string& path)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        std::string::size_type idx;
 | 
					        std::string::size_type idx;
 | 
				
			||||||
@@ -916,9 +892,8 @@ namespace ix
 | 
				
			|||||||
        auto dnsLookup = std::make_shared<DNSLookup>(hostname, 80);
 | 
					        auto dnsLookup = std::make_shared<DNSLookup>(hostname, 80);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string errMsg;
 | 
					        std::string errMsg;
 | 
				
			||||||
        struct addrinfo* res;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        res = dnsLookup->resolve(errMsg, [] { return false; });
 | 
					        auto res = dnsLookup->resolve(errMsg, [] { return false; });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto addr = res->ai_addr;
 | 
					        auto addr = res->ai_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2486,10 +2461,8 @@ int main(int argc, char** argv)
 | 
				
			|||||||
    bool verbose = false;
 | 
					    bool verbose = false;
 | 
				
			||||||
    bool save = false;
 | 
					    bool save = false;
 | 
				
			||||||
    bool quiet = false;
 | 
					    bool quiet = false;
 | 
				
			||||||
    bool fluentd = false;
 | 
					 | 
				
			||||||
    bool compress = false;
 | 
					    bool compress = false;
 | 
				
			||||||
    bool compressRequest = false;
 | 
					    bool compressRequest = false;
 | 
				
			||||||
    bool stress = false;
 | 
					 | 
				
			||||||
    bool disableAutomaticReconnection = false;
 | 
					    bool disableAutomaticReconnection = false;
 | 
				
			||||||
    bool disablePerMessageDeflate = false;
 | 
					    bool disablePerMessageDeflate = false;
 | 
				
			||||||
    bool greetings = false;
 | 
					    bool greetings = false;
 | 
				
			||||||
@@ -2505,7 +2478,6 @@ int main(int argc, char** argv)
 | 
				
			|||||||
    int transferTimeout = 1800;
 | 
					    int transferTimeout = 1800;
 | 
				
			||||||
    int maxRedirects = 5;
 | 
					    int maxRedirects = 5;
 | 
				
			||||||
    int delayMs = -1;
 | 
					    int delayMs = -1;
 | 
				
			||||||
    int count = 1;
 | 
					 | 
				
			||||||
    int msgCount = 1000 * 1000;
 | 
					    int msgCount = 1000 * 1000;
 | 
				
			||||||
    uint32_t maxWaitBetweenReconnectionRetries = 10 * 1000; // 10 seconds
 | 
					    uint32_t maxWaitBetweenReconnectionRetries = 10 * 1000; // 10 seconds
 | 
				
			||||||
    int pingIntervalSecs = 30;
 | 
					    int pingIntervalSecs = 30;
 | 
				
			||||||
@@ -2529,6 +2501,7 @@ int main(int argc, char** argv)
 | 
				
			|||||||
                        "A (comma/space/colon) separated list of ciphers to use for TLS");
 | 
					                        "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("--tls", tlsOptions.tls, "Enable TLS (server only)");
 | 
				
			||||||
        app->add_flag("--verify_none", verifyNone, "Disable peer cert verification");
 | 
					        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");
 | 
					    app.add_flag("--version", version, "Print ws version");
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user