From 4b5394837f82c9c3bb8bdd1191520b6cb55debd6 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Wed, 12 May 2021 10:10:36 +0000 Subject: [PATCH] mod_proxy_wstunnel: Add ProxyWebsocketFallbackToProxyHttp. Allows to opt-out the fallback to mod_proxy_http to handle WebSocket upgrade, and let mod_proxy_wstunnel handle the requests as in 2.4.46 and earlier. Update docs. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1889792 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/mod_proxy_wstunnel.xml | 20 ++++++++++ modules/proxy/mod_proxy_wstunnel.c | 53 +++++++++++++++++++++++--- 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/docs/manual/mod/mod_proxy_wstunnel.xml b/docs/manual/mod/mod_proxy_wstunnel.xml index 519523080c0..2c1c2748e67 100644 --- a/docs/manual/mod/mod_proxy_wstunnel.xml +++ b/docs/manual/mod/mod_proxy_wstunnel.xml @@ -71,6 +71,26 @@ in the response Upgrade

mod_proxy + +ProxyWebsocketFallbackToProxyHttp +Instructs this module to let mod_proxy_http handle the request +ProxyWebsocketFallbackToProxyHttp On|Off +ProxyWebsocketFallbackToProxyHttp On +Available in httpd 2.4.48 and later +server config +virtual host + + + +

Since httpd 2.4.47, mod_proxy_http can handle WebSocket + upgrading and tunneling in accordance to RFC 7230, this directive controls + whether mod_proxy_wstunnel should hand over to + mod_proxy_http to this, which is the case by default.

+

Setting to Off lets mod_proxy_wstunnel handle + WebSocket requests as in httpd 2.4.46 and earlier.

+
+
+ ProxyWebsocketAsync Instructs this module to try to create an asynchronous tunnel diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c index caf79e784d0..0037bfc5773 100644 --- a/modules/proxy/mod_proxy_wstunnel.c +++ b/modules/proxy/mod_proxy_wstunnel.c @@ -21,6 +21,8 @@ module AP_MODULE_DECLARE_DATA proxy_wstunnel_module; typedef struct { + unsigned int fallback_to_proxy_http :1, + fallback_to_proxy_http_set :1; int mpm_can_poll; apr_time_t idle_timeout; apr_time_t async_delay; @@ -34,7 +36,7 @@ typedef struct ws_baton_t { const char *scheme; } ws_baton_t; -static int fallback_to_mod_proxy_http; +static int can_fallback_to_proxy_http; static void proxy_wstunnel_callback(void *b); @@ -111,7 +113,10 @@ static void proxy_wstunnel_callback(void *b) static int proxy_wstunnel_check_trans(request_rec *r, const char *url) { - if (fallback_to_mod_proxy_http) { + proxyws_dir_conf *dconf = ap_get_module_config(r->per_dir_config, + &proxy_wstunnel_module); + + if (can_fallback_to_proxy_http && dconf->fallback_to_proxy_http) { ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "check_trans fallback"); return DECLINED; } @@ -140,13 +145,15 @@ static int proxy_wstunnel_check_trans(request_rec *r, const char *url) */ static int proxy_wstunnel_canon(request_rec *r, char *url) { + proxyws_dir_conf *dconf = ap_get_module_config(r->per_dir_config, + &proxy_wstunnel_module); char *host, *path, sport[7]; char *search = NULL; const char *err; char *scheme; apr_port_t port, def_port; - if (fallback_to_mod_proxy_http) { + if (can_fallback_to_proxy_http && dconf->fallback_to_proxy_http) { ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "canon fallback"); return DECLINED; } @@ -328,6 +335,8 @@ static int proxy_wstunnel_handler(request_rec *r, proxy_worker *worker, char *url, const char *proxyname, apr_port_t proxyport) { + proxyws_dir_conf *dconf = ap_get_module_config(r->per_dir_config, + &proxy_wstunnel_module); int status; char server_portstr[32]; proxy_conn_rec *backend = NULL; @@ -338,7 +347,7 @@ static int proxy_wstunnel_handler(request_rec *r, proxy_worker *worker, apr_uri_t *uri; int is_ssl = 0; - if (fallback_to_mod_proxy_http) { + if (can_fallback_to_proxy_http && dconf->fallback_to_proxy_http) { ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "handler fallback"); return DECLINED; } @@ -426,6 +435,7 @@ static void *create_proxyws_dir_config(apr_pool_t *p, char *dummy) proxyws_dir_conf *new = (proxyws_dir_conf *) apr_pcalloc(p, sizeof(proxyws_dir_conf)); + new->fallback_to_proxy_http = 1; new->idle_timeout = -1; /* no timeout */ ap_mpm_query(AP_MPMQ_CAN_POLL, &new->mpm_can_poll); @@ -433,6 +443,23 @@ static void *create_proxyws_dir_config(apr_pool_t *p, char *dummy) return (void *) new; } +static void *merge_proxyws_dir_config(apr_pool_t *p, void *vbase, void *vadd) +{ + proxyws_dir_conf *new = apr_pcalloc(p, sizeof(proxyws_dir_conf)), + *add = vadd, *base = vbase; + + new->fallback_to_proxy_http = (add->fallback_to_proxy_http_set) + ? add->fallback_to_proxy_http + : base->fallback_to_proxy_http; + new->fallback_to_proxy_http_set = (add->fallback_to_proxy_http_set + || base->fallback_to_proxy_http_set); + new->mpm_can_poll = add->mpm_can_poll; + new->idle_timeout = add->idle_timeout; + new->async_delay = add->async_delay; + + return new; +} + static const char * proxyws_set_idle(cmd_parms *cmd, void *conf, const char *val) { proxyws_dir_conf *dconf = conf; @@ -449,10 +476,18 @@ static const char * proxyws_set_asynch_delay(cmd_parms *cmd, void *conf, const c return NULL; } +static const char * proxyws_fallback_to_proxy_http(cmd_parms *cmd, void *conf, int arg) +{ + proxyws_dir_conf *dconf = conf; + dconf->fallback_to_proxy_http = !!arg; + dconf->fallback_to_proxy_http_set = 1; + return NULL; +} + static int proxy_wstunnel_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { - fallback_to_mod_proxy_http = + can_fallback_to_proxy_http = (ap_find_linked_module("mod_proxy_http.c") != NULL); return OK; @@ -460,6 +495,11 @@ static int proxy_wstunnel_post_config(apr_pool_t *pconf, apr_pool_t *plog, static const command_rec ws_proxy_cmds[] = { + AP_INIT_FLAG("ProxyWebsocketFallbackToProxyHttp", + proxyws_fallback_to_proxy_http, NULL, RSRC_CONF|ACCESS_CONF, + "whether to let mod_proxy_http handle the upgrade and tunneling, " + "On by default"), + AP_INIT_TAKE1("ProxyWebsocketIdleTimeout", proxyws_set_idle, NULL, RSRC_CONF|ACCESS_CONF, "timeout for activity in either direction, unlimited by default"), @@ -467,6 +507,7 @@ static const command_rec ws_proxy_cmds[] = AP_INIT_TAKE1("ProxyWebsocketAsyncDelay", proxyws_set_asynch_delay, NULL, RSRC_CONF|ACCESS_CONF, "amount of time to poll before going asynchronous"), + {NULL} }; @@ -482,7 +523,7 @@ static void ws_proxy_hooks(apr_pool_t *p) AP_DECLARE_MODULE(proxy_wstunnel) = { STANDARD20_MODULE_STUFF, create_proxyws_dir_config, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ + merge_proxyws_dir_config, /* merge per-directory config structures */ NULL, /* create per-server config structure */ NULL, /* merge per-server config structures */ ws_proxy_cmds, /* command apr_table_t */ -- 2.47.3