From 506ab6ce8d804a33a4db2fa7c4c1358e4d172918 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Mon, 5 Jun 2017 12:07:43 +0000 Subject: [PATCH] Merge from trunk: Add upgrade parameter to mod_proxy_wstunnel. That allows to upgrade to jboss-remoting for example or to run an HTTP/1.1 backend that needs to upgrade to WebSocket. See also: https://issues.jboss.org/browse/JBCS-254 https://issues.jboss.org/browse/JBCS-291 whitespace only Submitted By: jfclere Reviewed By: covener, jim, ylavic git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1797650 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 3 +++ STATUS | 7 ------- docs/manual/mod/mod_proxy.xml | 10 ++++++++++ docs/manual/mod/mod_proxy_wstunnel.xml | 5 +++++ modules/proxy/mod_proxy.c | 6 ++++++ modules/proxy/mod_proxy.h | 1 + modules/proxy/mod_proxy_wstunnel.c | 23 ++++++++++++++++------- 7 files changed, 41 insertions(+), 14 deletions(-) diff --git a/CHANGES b/CHANGES index a817ae0f20..301cb7061c 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,9 @@ Changes with Apache 2.4.26 + *) mod_proxy_wstunnel: Add "upgrade" parameter to allow upgrade to other + protocols. [Jean-Frederic Clere] + *) MPMs unix: Place signals handlers and helpers out of DSOs to avoid a possible crash if a signal is caught during (graceful) restart. PR 60487. [Yann Ylavic] diff --git a/STATUS b/STATUS index 8c740c4499..7d9f5ed301 100644 --- a/STATUS +++ b/STATUS @@ -120,13 +120,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - *) proxy_wstunnel: Restore ability to process other Upgrade: protocols which was - blocked in r1674632/r1674661. - trunk patch: http://svn.apache.org/r1792092 - http://svn.apache.org/r1796864 - 2.4.x patch: svn merge -c 1792092,1796864 ^/httpd/httpd/trunk . - +1: covener, jim, ylavic - *) worker, prefork: save some cycles by not copying the listener's pollfds for each pollset operation trunk patch: http://svn.apache.org/r1662437 diff --git a/docs/manual/mod/mod_proxy.xml b/docs/manual/mod/mod_proxy.xml index b0e0b560f8..094f1de113 100644 --- a/docs/manual/mod/mod_proxy.xml +++ b/docs/manual/mod/mod_proxy.xml @@ -1189,6 +1189,16 @@ ProxyPass "/mirror/foo" "http://backend.example.com"

Name of the provider used by mod_proxy_fdpass. See the documentation of this module for more details.

+ secret + - +

Value of secret used by mod_proxy_ajp. + See the documentation of this module for more details.

+ + upgrade + WebSocket +

Protocol accepted in the Upgrade header by mod_proxy_wstunnel. + See the documentation of this module for more details.

+ diff --git a/docs/manual/mod/mod_proxy_wstunnel.xml b/docs/manual/mod/mod_proxy_wstunnel.xml index 907576766d..639131ba2d 100644 --- a/docs/manual/mod/mod_proxy_wstunnel.xml +++ b/docs/manual/mod/mod_proxy_wstunnel.xml @@ -51,6 +51,11 @@ ProxyPass "/wss2/" "wss://echo.websocket.org/"

Load balancing for multiple backends can be achieved using mod_proxy_balancer.

+ +

In fact the module can be used to upgrade to other protocols, you can set the upgrade +parameter in the ProxyPass +directive to allow the module to accept other protocol. +NONE means you bypass the check for the header but still upgrade to WebSocket.

mod_proxy diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 6977835004..f6fb473ed1 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -308,6 +308,12 @@ static const char *set_worker_param(apr_pool_t *p, (int)sizeof(worker->s->flusher)); PROXY_STRNCPY(worker->s->flusher, val); } + else if (!strcasecmp(key, "upgrade")) { + if (PROXY_STRNCPY(worker->s->upgrade, val) != APR_SUCCESS) { + return apr_psprintf(p, "upgrade protocol length must be < %d characters", + (int)sizeof(worker->s->upgrade)); + } + } else { if (set_worker_hc_param_f) { return set_worker_hc_param_f(p, s, worker, key, val, NULL); diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 281a77650c..8a0ad10259 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -442,6 +442,7 @@ typedef struct { int fcount; /* current count of failures */ hcmethod_t method; /* method to use for health check */ apr_interval_time_t interval; + char upgrade[PROXY_WORKER_MAX_SCHEME_SIZE];/* upgrade protocol used by mod_proxy_wstunnel */ } proxy_worker_shared; #define ALIGNED_PROXY_WORKER_SHARED_SIZE (APR_ALIGN_DEFAULT(sizeof(proxy_worker_shared))) diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c index 597cf11862..0130699005 100644 --- a/modules/proxy/mod_proxy_wstunnel.c +++ b/modules/proxy/mod_proxy_wstunnel.c @@ -116,6 +116,7 @@ static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r, apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc); apr_socket_t *client_socket = ap_get_conn_socket(c); int done = 0, replied = 0; + const char *upgrade_method = *worker->s->upgrade ? worker->s->upgrade : "WebSocket"; header_brigade = apr_brigade_create(p, backconn->bucket_alloc); @@ -128,7 +129,11 @@ static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r, return rv; } - buf = apr_pstrdup(p, "Upgrade: WebSocket" CRLF "Connection: Upgrade" CRLF CRLF); + if (ap_cstr_casecmp(upgrade_method, "NONE") == 0) { + buf = apr_pstrdup(p, "Upgrade: WebSocket" CRLF "Connection: Upgrade" CRLF CRLF); + } else { + buf = apr_pstrcat(p, "Upgrade: ", upgrade_method, CRLF "Connection: Upgrade" CRLF CRLF, NULL); + } ap_xlate_proto_to_ascii(buf, strlen(buf)); e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(header_brigade, e); @@ -274,13 +279,13 @@ static int proxy_wstunnel_handler(request_rec *r, proxy_worker *worker, int status; char server_portstr[32]; proxy_conn_rec *backend = NULL; - const char *upgrade; char *scheme; int retry; conn_rec *c = r->connection; apr_pool_t *p = r->pool; apr_uri_t *uri; int is_ssl = 0; + const char *upgrade_method = *worker->s->upgrade ? worker->s->upgrade : "WebSocket"; if (strncasecmp(url, "wss:", 4) == 0) { scheme = "WSS"; @@ -294,11 +299,15 @@ static int proxy_wstunnel_handler(request_rec *r, proxy_worker *worker, return DECLINED; } - upgrade = apr_table_get(r->headers_in, "Upgrade"); - if (!upgrade || strcasecmp(upgrade, "WebSocket") != 0) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02900) - "declining URL %s (not WebSocket)", url); - return DECLINED; + if (ap_cstr_casecmp(upgrade_method, "NONE") != 0) { + const char *upgrade; + upgrade = apr_table_get(r->headers_in, "Upgrade"); + if (!upgrade || ap_cstr_casecmp(upgrade, upgrade_method) != 0) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02900) + "declining URL %s (not %s, Upgrade: header is %s)", + url, upgrade_method, upgrade ? upgrade : "missing"); + return DECLINED; + } } uri = apr_palloc(p, sizeof(*uri)); -- 2.40.0