|
@@ -15,6 +15,7 @@
|
|
|
#include "utils.hpp"
|
|
|
|
|
|
#include "tcptransport.hpp"
|
|
|
+#include "httpproxytransport.hpp"
|
|
|
#include "tlstransport.hpp"
|
|
|
#include "verifiedtlstransport.hpp"
|
|
|
#include "wstransport.hpp"
|
|
@@ -47,10 +48,6 @@ void WebSocket::open(const string &url) {
|
|
|
if (state != State::Closed)
|
|
|
throw std::logic_error("WebSocket must be closed before opening");
|
|
|
|
|
|
- if (config.proxyServer) {
|
|
|
- PLOG_WARNING << "Proxy server support for WebSocket is not implemented";
|
|
|
- }
|
|
|
-
|
|
|
// Modified regex from RFC 3986, see https://www.rfc-editor.org/rfc/rfc3986.html#appendix-B
|
|
|
static const char *rs =
|
|
|
R"(^(([^:.@/?#]+):)?(/{0,2}((([^:@]*)(:([^@]*))?)@)?(([^:/?#]*)(:([^/?#]*))?))?([^?#]*)(\?([^#]*))?(#(.*))?)";
|
|
@@ -101,11 +98,20 @@ void WebSocket::open(const string &url) {
|
|
|
if (string query = m[15]; !query.empty())
|
|
|
path += "?" + query;
|
|
|
|
|
|
- mHostname = hostname; // for TLS SNI
|
|
|
+ mHostname = hostname; // for TLS SNI and Proxy
|
|
|
+ mService = service; //For proxy
|
|
|
std::atomic_store(&mWsHandshake, std::make_shared<WsHandshake>(host, path, config.protocols));
|
|
|
|
|
|
changeState(State::Connecting);
|
|
|
- setTcpTransport(std::make_shared<TcpTransport>(hostname, service, nullptr));
|
|
|
+
|
|
|
+ if (config.proxyServer)
|
|
|
+ {
|
|
|
+ setTcpTransport(std::make_shared<TcpTransport>(config.proxyServer->hostname, std::to_string(config.proxyServer->port), nullptr));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ setTcpTransport(std::make_shared<TcpTransport>(hostname, service, nullptr));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void WebSocket::close() {
|
|
@@ -218,7 +224,9 @@ shared_ptr<TcpTransport> WebSocket::setTcpTransport(shared_ptr<TcpTransport> tra
|
|
|
return;
|
|
|
switch (transportState) {
|
|
|
case State::Connected:
|
|
|
- if (mIsSecure)
|
|
|
+ if (config.proxyServer)
|
|
|
+ initProxyTransport();
|
|
|
+ else if (mIsSecure)
|
|
|
initTlsTransport();
|
|
|
else
|
|
|
initWsTransport();
|
|
@@ -250,6 +258,52 @@ shared_ptr<TcpTransport> WebSocket::setTcpTransport(shared_ptr<TcpTransport> tra
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+shared_ptr<HttpProxyTransport> WebSocket::initProxyTransport() {
|
|
|
+ PLOG_VERBOSE << "Starting Tcp Proxy transport";
|
|
|
+ using State = HttpProxyTransport::State;
|
|
|
+ try {
|
|
|
+ if (auto transport = std::atomic_load(&mProxyTransport))
|
|
|
+ return transport;
|
|
|
+
|
|
|
+ auto lower = std::atomic_load(&mTcpTransport);
|
|
|
+ if (!lower)
|
|
|
+ throw std::logic_error("No underlying TCP transport for Proxy transport");
|
|
|
+
|
|
|
+ auto stateChangeCallback = [this, weak_this = weak_from_this()](State transportState) {
|
|
|
+ auto shared_this = weak_this.lock();
|
|
|
+ if (!shared_this)
|
|
|
+ return;
|
|
|
+ switch (transportState) {
|
|
|
+ case State::Connected:
|
|
|
+ if (mIsSecure)
|
|
|
+ initTlsTransport();
|
|
|
+ else
|
|
|
+ initWsTransport();
|
|
|
+ break;
|
|
|
+ case State::Failed:
|
|
|
+ triggerError("Proxy connection failed");
|
|
|
+ remoteClose();
|
|
|
+ break;
|
|
|
+ case State::Disconnected:
|
|
|
+ remoteClose();
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ // Ignore
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ auto transport = std::make_shared<HttpProxyTransport>( lower, mHostname.value(), mService.value(), stateChangeCallback );
|
|
|
+
|
|
|
+ return emplaceTransport(this, &mProxyTransport, std::move(transport));
|
|
|
+
|
|
|
+ } catch (const std::exception &e) {
|
|
|
+ PLOG_ERROR << e.what();
|
|
|
+ remoteClose();
|
|
|
+ throw std::runtime_error("Tcp Proxy transport initialization failed");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
shared_ptr<TlsTransport> WebSocket::initTlsTransport() {
|
|
|
PLOG_VERBOSE << "Starting TLS transport";
|
|
|
using State = TlsTransport::State;
|
|
@@ -257,9 +311,20 @@ shared_ptr<TlsTransport> WebSocket::initTlsTransport() {
|
|
|
if (auto transport = std::atomic_load(&mTlsTransport))
|
|
|
return transport;
|
|
|
|
|
|
- auto lower = std::atomic_load(&mTcpTransport);
|
|
|
- if (!lower)
|
|
|
- throw std::logic_error("No underlying TCP transport for TLS transport");
|
|
|
+ variant<shared_ptr<TcpTransport>, shared_ptr<HttpProxyTransport>> lower;
|
|
|
+ if (config.proxyServer) {
|
|
|
+ auto transport = std::atomic_load(&mProxyTransport);
|
|
|
+ if (!transport)
|
|
|
+ throw std::logic_error("No underlying proxy transport for TLS transport");
|
|
|
+
|
|
|
+ lower = transport;
|
|
|
+ } else {
|
|
|
+ auto transport = std::atomic_load(&mTcpTransport);
|
|
|
+ if (!transport)
|
|
|
+ throw std::logic_error("No underlying TCP transport for TLS transport");
|
|
|
+
|
|
|
+ lower = transport;
|
|
|
+ }
|
|
|
|
|
|
auto stateChangeCallback = [this, weak_this = weak_from_this()](State transportState) {
|
|
|
auto shared_this = weak_this.lock();
|
|
@@ -314,12 +379,19 @@ shared_ptr<WsTransport> WebSocket::initWsTransport() {
|
|
|
if (auto transport = std::atomic_load(&mWsTransport))
|
|
|
return transport;
|
|
|
|
|
|
- variant<shared_ptr<TcpTransport>, shared_ptr<TlsTransport>> lower;
|
|
|
+ variant<shared_ptr<TcpTransport>, shared_ptr<HttpProxyTransport>, shared_ptr<TlsTransport>> lower;
|
|
|
if (mIsSecure) {
|
|
|
auto transport = std::atomic_load(&mTlsTransport);
|
|
|
if (!transport)
|
|
|
throw std::logic_error("No underlying TLS transport for WebSocket transport");
|
|
|
|
|
|
+ lower = transport;
|
|
|
+ }
|
|
|
+ else if (config.proxyServer) {
|
|
|
+ auto transport = std::atomic_load(&mProxyTransport);
|
|
|
+ if (!transport)
|
|
|
+ throw std::logic_error("No underlying proxy transport for WebSocket transport");
|
|
|
+
|
|
|
lower = transport;
|
|
|
} else {
|
|
|
auto transport = std::atomic_load(&mTcpTransport);
|