From 1a821d6abf5458d424bd670e0bd21babcb932058 Mon Sep 17 00:00:00 2001 From: Tobias Madsen - QIAGEN Date: Wed, 17 Aug 2022 08:44:07 +0200 Subject: [PATCH 1/4] Add method for enabling proxying by setting proxy_url --- R/cpp11.R | 4 ++++ R/websocket.R | 7 ++++++- src/client.hpp | 4 ++++ src/cpp11.cpp | 23 +++++++++++------------ src/websocket.cpp | 7 +++++++ 5 files changed, 32 insertions(+), 13 deletions(-) diff --git a/R/cpp11.R b/R/cpp11.R index 6076008..74be7cc 100644 --- a/R/cpp11.R +++ b/R/cpp11.R @@ -12,6 +12,10 @@ wsAddProtocols <- function(wsc_xptr, protocols) { invisible(.Call(`_websocket_wsAddProtocols`, wsc_xptr, protocols)) } +wsAddProxy <- function(wsc_xptr, proxy_url) { + invisible(.Call(`_websocket_wsAddProxy`, wsc_xptr, proxy_url)) +} + wsConnect <- function(wsc_xptr) { invisible(.Call(`_websocket_wsConnect`, wsc_xptr)) } diff --git a/R/websocket.R b/R/websocket.R index fdd95fd..da841ea 100644 --- a/R/websocket.R +++ b/R/websocket.R @@ -151,7 +151,8 @@ WebSocket <- R6Class("WebSocket", accessLogChannels = c("none"), errorLogChannels = NULL, maxMessageSize = 32 * 1024 * 1024, - loop = later::current_loop() + loop = later::current_loop(), + proxy_url = NULL ) { private$callbacks <- new.env(parent = emptyenv()) private$callbacks$open <- Callbacks$new() @@ -175,6 +176,10 @@ WebSocket <- R6Class("WebSocket", }) wsAddProtocols(private$wsObj, protocols) + if (!is.null(proxy_url)) { + wsAddProxy(private$wsObj, proxy_url) + } + private$pendingConnect <- TRUE if (autoConnect) { self$connect() diff --git a/src/client.hpp b/src/client.hpp index 3792ed6..b86c600 100644 --- a/src/client.hpp +++ b/src/client.hpp @@ -49,6 +49,7 @@ class Client { virtual void setup_connection(std::string location, ws_websocketpp::lib::error_code &ec) = 0; virtual void append_header(std::string key, std::string value) = 0; virtual void add_subprotocol(std::string const & request) = 0; + virtual void set_proxy(std::string const & proxy_url) = 0; virtual void connect() = 0; virtual std::string get_subprotocol() const = 0; @@ -137,6 +138,9 @@ class ClientImpl : public Client { void add_subprotocol(std::string const & value) { con->add_subprotocol(value); }; + void set_proxy(std::string const & proxy_url) { + this->con->set_proxy(proxy_url); + } void connect() { client.connect(this->con); }; diff --git a/src/cpp11.cpp b/src/cpp11.cpp index 52f02bd..f55df18 100644 --- a/src/cpp11.cpp +++ b/src/cpp11.cpp @@ -3,6 +3,7 @@ #include "cpp11/declarations.hpp" +#include // websocket.cpp SEXP wsCreate(std::string uri, int loop_id, cpp11::environment robjPublic, cpp11::environment robjPrivate, cpp11::strings accessLogChannels, cpp11::strings errorLogChannels, int maxMessageSize); @@ -28,6 +29,14 @@ extern "C" SEXP _websocket_wsAddProtocols(SEXP wsc_xptr, SEXP protocols) { END_CPP11 } // websocket.cpp +void wsAddProxy(SEXP wsc_xptr, std::string proxy_url); +extern "C" SEXP _websocket_wsAddProxy(SEXP wsc_xptr, SEXP proxy_url) { + BEGIN_CPP11 + wsAddProxy(cpp11::as_cpp>(wsc_xptr), cpp11::as_cpp>(proxy_url)); + return R_NilValue; + END_CPP11 +} +// websocket.cpp void wsConnect(SEXP wsc_xptr); extern "C" SEXP _websocket_wsConnect(SEXP wsc_xptr) { BEGIN_CPP11 @@ -75,19 +84,9 @@ extern "C" SEXP _websocket_wsUpdateLogChannels(SEXP wsc_xptr, SEXP accessOrError } extern "C" { -/* .Call calls */ -extern SEXP _websocket_wsAddProtocols(SEXP, SEXP); -extern SEXP _websocket_wsAppendHeader(SEXP, SEXP, SEXP); -extern SEXP _websocket_wsClose(SEXP, SEXP, SEXP); -extern SEXP _websocket_wsConnect(SEXP); -extern SEXP _websocket_wsCreate(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP _websocket_wsProtocol(SEXP); -extern SEXP _websocket_wsSend(SEXP, SEXP); -extern SEXP _websocket_wsState(SEXP); -extern SEXP _websocket_wsUpdateLogChannels(SEXP, SEXP, SEXP, SEXP); - static const R_CallMethodDef CallEntries[] = { {"_websocket_wsAddProtocols", (DL_FUNC) &_websocket_wsAddProtocols, 2}, + {"_websocket_wsAddProxy", (DL_FUNC) &_websocket_wsAddProxy, 2}, {"_websocket_wsAppendHeader", (DL_FUNC) &_websocket_wsAppendHeader, 3}, {"_websocket_wsClose", (DL_FUNC) &_websocket_wsClose, 3}, {"_websocket_wsConnect", (DL_FUNC) &_websocket_wsConnect, 1}, @@ -100,7 +99,7 @@ static const R_CallMethodDef CallEntries[] = { }; } -extern "C" void R_init_websocket(DllInfo* dll){ +extern "C" attribute_visible void R_init_websocket(DllInfo* dll){ R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); R_forceSymbols(dll, TRUE); diff --git a/src/websocket.cpp b/src/websocket.cpp index 010e3ad..ce9fe0f 100644 --- a/src/websocket.cpp +++ b/src/websocket.cpp @@ -84,6 +84,13 @@ void wsAddProtocols(SEXP wsc_xptr, cpp11::strings protocols) { } } +[[cpp11::register]] +void wsAddProxy(SEXP wsc_xptr, std::string proxy_url) { + ASSERT_MAIN_THREAD() + shared_ptr wsc = xptrGetWsConn(wsc_xptr); + wsc->client->set_proxy(proxy_url); +} + [[cpp11::register]] void wsConnect(SEXP wsc_xptr) { ASSERT_MAIN_THREAD() From ef65b744da4572f93470d4b203ac32e72d992c4a Mon Sep 17 00:00:00 2001 From: Tobias Madsen - QIAGEN Date: Wed, 17 Aug 2022 11:01:23 +0200 Subject: [PATCH 2/4] Add method for enabling basic auth for proxy --- R/cpp11.R | 4 ++++ R/websocket.R | 12 +++++++++--- src/client.hpp | 4 ++++ src/cpp11.cpp | 9 +++++++++ src/websocket.cpp | 7 +++++++ 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/R/cpp11.R b/R/cpp11.R index 74be7cc..3032b58 100644 --- a/R/cpp11.R +++ b/R/cpp11.R @@ -16,6 +16,10 @@ wsAddProxy <- function(wsc_xptr, proxy_url) { invisible(.Call(`_websocket_wsAddProxy`, wsc_xptr, proxy_url)) } +wsAddProxyBasicAuth <- function(wsc_xptr, username, password) { + invisible(.Call(`_websocket_wsAddProxyBasicAuth`, wsc_xptr, username, password)) +} + wsConnect <- function(wsc_xptr) { invisible(.Call(`_websocket_wsConnect`, wsc_xptr)) } diff --git a/R/websocket.R b/R/websocket.R index da841ea..8b51b60 100644 --- a/R/websocket.R +++ b/R/websocket.R @@ -152,7 +152,9 @@ WebSocket <- R6Class("WebSocket", errorLogChannels = NULL, maxMessageSize = 32 * 1024 * 1024, loop = later::current_loop(), - proxy_url = NULL + proxyUrl = NULL, + proxyUsername = NULL, + proxyPassword = NULL ) { private$callbacks <- new.env(parent = emptyenv()) private$callbacks$open <- Callbacks$new() @@ -176,8 +178,12 @@ WebSocket <- R6Class("WebSocket", }) wsAddProtocols(private$wsObj, protocols) - if (!is.null(proxy_url)) { - wsAddProxy(private$wsObj, proxy_url) + if (!is.null(proxyUrl)) { + wsAddProxy(private$wsObj, proxyUrl) + + if(!is.null(proxyUsername)) { + wsAddProxyBasicAuth(private$wsObj, proxyUsername, proxyPassword); + } } private$pendingConnect <- TRUE diff --git a/src/client.hpp b/src/client.hpp index b86c600..1ea9805 100644 --- a/src/client.hpp +++ b/src/client.hpp @@ -50,6 +50,7 @@ class Client { virtual void append_header(std::string key, std::string value) = 0; virtual void add_subprotocol(std::string const & request) = 0; virtual void set_proxy(std::string const & proxy_url) = 0; + virtual void set_proxy_basic_auth(std::string const & username, std::string const & password) = 0; virtual void connect() = 0; virtual std::string get_subprotocol() const = 0; @@ -141,6 +142,9 @@ class ClientImpl : public Client { void set_proxy(std::string const & proxy_url) { this->con->set_proxy(proxy_url); } + void set_proxy_basic_auth(std::string const & username, std::string const & password) { + this->con->set_proxy_basic_auth(username, password); + } void connect() { client.connect(this->con); }; diff --git a/src/cpp11.cpp b/src/cpp11.cpp index f55df18..e982345 100644 --- a/src/cpp11.cpp +++ b/src/cpp11.cpp @@ -37,6 +37,14 @@ extern "C" SEXP _websocket_wsAddProxy(SEXP wsc_xptr, SEXP proxy_url) { END_CPP11 } // websocket.cpp +void wsAddProxyBasicAuth(SEXP wsc_xptr, std::string username, std::string password); +extern "C" SEXP _websocket_wsAddProxyBasicAuth(SEXP wsc_xptr, SEXP username, SEXP password) { + BEGIN_CPP11 + wsAddProxyBasicAuth(cpp11::as_cpp>(wsc_xptr), cpp11::as_cpp>(username), cpp11::as_cpp>(password)); + return R_NilValue; + END_CPP11 +} +// websocket.cpp void wsConnect(SEXP wsc_xptr); extern "C" SEXP _websocket_wsConnect(SEXP wsc_xptr) { BEGIN_CPP11 @@ -87,6 +95,7 @@ extern "C" { static const R_CallMethodDef CallEntries[] = { {"_websocket_wsAddProtocols", (DL_FUNC) &_websocket_wsAddProtocols, 2}, {"_websocket_wsAddProxy", (DL_FUNC) &_websocket_wsAddProxy, 2}, + {"_websocket_wsAddProxyBasicAuth", (DL_FUNC) &_websocket_wsAddProxyBasicAuth, 3}, {"_websocket_wsAppendHeader", (DL_FUNC) &_websocket_wsAppendHeader, 3}, {"_websocket_wsClose", (DL_FUNC) &_websocket_wsClose, 3}, {"_websocket_wsConnect", (DL_FUNC) &_websocket_wsConnect, 1}, diff --git a/src/websocket.cpp b/src/websocket.cpp index ce9fe0f..96a6d70 100644 --- a/src/websocket.cpp +++ b/src/websocket.cpp @@ -91,6 +91,13 @@ void wsAddProxy(SEXP wsc_xptr, std::string proxy_url) { wsc->client->set_proxy(proxy_url); } +[[cpp11::register]] +void wsAddProxyBasicAuth(SEXP wsc_xptr, std::string username, std::string password) { + ASSERT_MAIN_THREAD() + shared_ptr wsc = xptrGetWsConn(wsc_xptr); + wsc->client->set_proxy_basic_auth(username, password); +} + [[cpp11::register]] void wsConnect(SEXP wsc_xptr) { ASSERT_MAIN_THREAD() From d4cab2825b712a8aa4aa58c1ff31940748ecdeb3 Mon Sep 17 00:00:00 2001 From: Tobias Madsen - QIAGEN Date: Fri, 2 Sep 2022 12:41:50 +0200 Subject: [PATCH 3/4] Add documentation of proxy related parameters --- R/websocket.R | 8 +++++++- man/WebSocket.Rd | 8 ++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/R/websocket.R b/R/websocket.R index 8b51b60..4a1b9ee 100644 --- a/R/websocket.R +++ b/R/websocket.R @@ -116,6 +116,11 @@ null_func <- function(...) { } #' @param maxMessageSize The maximum size of a message in bytes. If a message #' larger than this is sent, the connection will fail with the \code{message_too_big} #' protocol error. +#' @param proxyUrl Optional parameter to connect to websocket through proxy, +#' will usually begin with \code{http://} or \code{https://}. +#' @param proxyUsername Optional parameter to specify proxy username +#' @param proxyPassword Optional parameter to specify proxy password, can not be +#' \code{NULL} if \code{proxyUsername} is given. #' #' #' @name WebSocket @@ -181,7 +186,8 @@ WebSocket <- R6Class("WebSocket", if (!is.null(proxyUrl)) { wsAddProxy(private$wsObj, proxyUrl) - if(!is.null(proxyUsername)) { + if (!is.null(proxyUsername)) { + if (is.null(proxyPassword)) wsAddProxyBasicAuth(private$wsObj, proxyUsername, proxyPassword); } } diff --git a/man/WebSocket.Rd b/man/WebSocket.Rd index adcc0f9..3538974 100644 --- a/man/WebSocket.Rd +++ b/man/WebSocket.Rd @@ -53,6 +53,14 @@ must call `ws$connect()` to establish the WebSocket connection.} \item{maxMessageSize}{The maximum size of a message in bytes. If a message larger than this is sent, the connection will fail with the \code{message_too_big} protocol error.} + +\item{proxyUrl}{Optional parameter to connect to websocket through proxy, +will usually begin with \code{http://} or \code{https://}.} + +\item{proxyUsername}{Optional parameter to specify proxy username} + +\item{proxyPassword}{Optional parameter to specify proxy password, can not be +\code{NULL} if \code{proxyUsername} is given.} } \description{ \preformatted{ From 110e72c965f673d5f5a8f074719b2927cecb3714 Mon Sep 17 00:00:00 2001 From: Tobias Madsen - QIAGEN Date: Fri, 2 Sep 2022 13:02:59 +0200 Subject: [PATCH 4/4] Add entry on proxy support in changelog --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 76b1b68..cd3eafb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # websocket (development version) +* Add support for connecting to websocket through a proxy + # websocket 1.4.1 * Add UCRT toolchain support (@jeroen, #82)