You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by yl...@apache.org on 2021/01/07 13:19:09 UTC

svn commit: r1885239 - in /httpd/httpd/trunk: changes-entries/proxy_wstunnel_to_http.txt docs/log-message-tags/next-number modules/proxy/mod_proxy.h modules/proxy/mod_proxy_http.c modules/proxy/mod_proxy_wstunnel.c modules/proxy/proxy_util.c

Author: ylavic
Date: Thu Jan  7 13:19:08 2021
New Revision: 1885239

URL: http://svn.apache.org/viewvc?rev=1885239&view=rev
Log:
mod_proxy_wstunnel: leave Upgrade requests handling to mod_proxy_http.

Let mod_proxy_http's canon and scheme handlers accept "ws[s]:" schemes so that
mod_proxy_wstunnel can decline requests when mod_proxy_http is loaded.

* modules/proxy/{mod_proxy.h,proxy_util.c} (ap_proxy_worker_can_upgrade):
  Add a "dflt" argument to ap_proxy_worker_can_upgrade() which, if not NULL,
  is matched when no worker upgrade= parameter is configured. This allows to
  handle the default "Upgrade: websocket" case for "ws[s]:" schemes.

* modules/proxy/mod_proxy_http.c (proxy_http_canon, proxy_http_handler):
  Add and use the new get_url_scheme() helper to parse URL schemes handled by
  mod_proxy_http and use it in canon and scheme handlers. This helper now
  accepts ws[s] schemes.

* modules/proxy/mod_proxy_wstunnel.c (proxy_wstunnel_post_config):
  New post_config hook to detect whether mod_proxy_http is loaded and set
  global fallback_to_mod_proxy_http flag in this case.

* modules/proxy/mod_proxy_wstunnel.c (proxy_wstunnel_check_trans,
                                      proxy_wstunnel_canon,
                                      proxy_wstunnel_handler):
  These hooks now early return DECLINED if fallback_to_mod_proxy_http is set.

Added:
    httpd/httpd/trunk/changes-entries/proxy_wstunnel_to_http.txt
Modified:
    httpd/httpd/trunk/docs/log-message-tags/next-number
    httpd/httpd/trunk/modules/proxy/mod_proxy.h
    httpd/httpd/trunk/modules/proxy/mod_proxy_http.c
    httpd/httpd/trunk/modules/proxy/mod_proxy_wstunnel.c
    httpd/httpd/trunk/modules/proxy/proxy_util.c

Added: httpd/httpd/trunk/changes-entries/proxy_wstunnel_to_http.txt
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/changes-entries/proxy_wstunnel_to_http.txt?rev=1885239&view=auto
==============================================================================
--- httpd/httpd/trunk/changes-entries/proxy_wstunnel_to_http.txt (added)
+++ httpd/httpd/trunk/changes-entries/proxy_wstunnel_to_http.txt Thu Jan  7 13:19:08 2021
@@ -0,0 +1,4 @@
+  *) mod_proxy_wstunnel: Leave Upgrade requests handling to mod_proxy_http,
+     allowing for (non-)Upgrade negotiation with the origin server.
+     [Yann Ylavic]
+

Modified: httpd/httpd/trunk/docs/log-message-tags/next-number
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/log-message-tags/next-number?rev=1885239&r1=1885238&r2=1885239&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/log-message-tags/next-number (original)
+++ httpd/httpd/trunk/docs/log-message-tags/next-number Thu Jan  7 13:19:08 2021
@@ -1 +1 @@
-10262
+10263

Modified: httpd/httpd/trunk/modules/proxy/mod_proxy.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy.h?rev=1885239&r1=1885238&r2=1885239&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/mod_proxy.h (original)
+++ httpd/httpd/trunk/modules/proxy/mod_proxy.h Thu Jan  7 13:19:08 2021
@@ -755,11 +755,13 @@ PROXY_DECLARE(char *) ap_proxy_worker_na
  * @param p       memory pool used for displaying worker name
  * @param worker  the worker
  * @param upgrade the Upgrade header to match
+ * @param dflt    default protocol (NULL for none)
  * @return        1 (true) or 0 (false)
  */
 PROXY_DECLARE(int) ap_proxy_worker_can_upgrade(apr_pool_t *p,
                                                const proxy_worker *worker,
-                                               const char *upgrade);
+                                               const char *upgrade,
+                                               const char *dflt);
 
 /**
  * Get the worker from proxy configuration

Modified: httpd/httpd/trunk/modules/proxy/mod_proxy_http.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy_http.c?rev=1885239&r1=1885238&r2=1885239&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/mod_proxy_http.c (original)
+++ httpd/httpd/trunk/modules/proxy/mod_proxy_http.c Thu Jan  7 13:19:08 2021
@@ -28,37 +28,71 @@ static int (*ap_proxy_clear_connection_f
 static apr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n,
                                     request_rec *r, int flags, int *read);
 
+static const char *get_url_scheme(const char **url, int *is_ssl)
+{
+    const char *u = *url;
+
+    switch (u[0]) {
+    case 'h':
+    case 'H':
+        if (strncasecmp(u + 1, "ttp", 3) == 0) {
+            if (u[4] == ':') {
+                *is_ssl = 0;
+                *url = u + 5;
+                return "http";
+            }
+            if (apr_tolower(u[4]) == 's' && u[5] == ':') {
+                *is_ssl = 1;
+                *url = u + 6;
+                return "https";
+            }
+        }
+        break;
+
+    case 'w':
+    case 'W':
+        if (apr_tolower(u[1]) == 's') {
+            if (u[2] == ':') {
+                *is_ssl = 0;
+                *url = u + 3;
+                return "ws";
+            }
+            if (apr_tolower(u[2]) == 's' && u[3] == ':') {
+                *is_ssl = 0;
+                *url = u + 4;
+                return "wss";
+            }
+        }
+        break;
+    }
+
+    *is_ssl = 0;
+    return NULL;
+}
 
 /*
  * Canonicalise http-like URLs.
  *  scheme is the scheme for the URL
  *  url    is the URL starting with the first '/'
- *  def_port is the default port for this scheme.
  */
 static int proxy_http_canon(request_rec *r, char *url)
 {
+    const char *base_url = url;
     char *host, *path, sport[7];
     char *search = NULL;
     const char *err;
     const char *scheme;
     apr_port_t port, def_port;
+    int is_ssl = 0;
 
-    /* ap_port_of_scheme() */
-    if (ap_cstr_casecmpn(url, "http:", 5) == 0) {
-        url += 5;
-        scheme = "http";
-    }
-    else if (ap_cstr_casecmpn(url, "https:", 6) == 0) {
-        url += 6;
-        scheme = "https";
-    }
-    else {
+    scheme = get_url_scheme((const char **)&url, &is_ssl);
+    if (!scheme) {
         return DECLINED;
     }
-    port = def_port = ap_proxy_port_of_scheme(scheme);
+    port = def_port = (is_ssl) ? DEFAULT_HTTPS_PORT : DEFAULT_HTTP_PORT;
 
     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
-                  "HTTP: canonicalising URL %s", url);
+                  "HTTP: canonicalising URL %s", base_url);
 
     /* do syntatic check.
      * We break the URL into host, port, path, search
@@ -66,7 +100,7 @@ static int proxy_http_canon(request_rec
     err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
     if (err) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01083)
-                      "error parsing URL %s: %s", url, err);
+                      "error parsing URL %s: %s", base_url, err);
         return HTTP_BAD_REQUEST;
     }
 
@@ -106,8 +140,9 @@ static int proxy_http_canon(request_rec
     if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */
         host = apr_pstrcat(r->pool, "[", host, "]", NULL);
     }
+
     r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport,
-            "/", path, (search) ? "?" : "", (search) ? search : "", NULL);
+                              "/", path, (search) ? "?" : "", search, NULL);
     return OK;
 }
 
@@ -1568,7 +1603,9 @@ int ap_proxy_http_process_response(proxy
          * may be an HTTP_UPGRADE_REQUIRED response or some other status where
          * Upgrade makes sense to negotiate the protocol by other means.
          */
-        if (upgrade && ap_proxy_worker_can_upgrade(p, worker, upgrade)) {
+        if (upgrade && ap_proxy_worker_can_upgrade(p, worker, upgrade,
+                                                   (*req->proto == 'w')
+                                                   ? "WebSocket" : NULL)) {
             apr_table_setn(r->headers_out, "Connection", "Upgrade");
             apr_table_setn(r->headers_out, "Upgrade", apr_pstrdup(p, upgrade));
         }
@@ -1840,9 +1877,8 @@ static int proxy_http_handler(request_re
                               apr_port_t proxyport)
 {
     int status;
-    char *scheme;
-    const char *proxy_function;
-    const char *u;
+    const char *scheme;
+    const char *u = url;
     proxy_http_req_t *req = NULL;
     proxy_conn_rec *backend = NULL;
     apr_bucket_brigade *input_brigade = NULL;
@@ -1860,41 +1896,31 @@ static int proxy_http_handler(request_re
     apr_pool_t *p = r->pool;
     apr_uri_t *uri;
 
-    /* find the scheme */
-    u = strchr(url, ':');
-    if (u == NULL || u[1] != '/' || u[2] != '/' || u[3] == '\0')
+    scheme = get_url_scheme(&u, &is_ssl);
+    if (!scheme && proxyname && strncasecmp(url, "ftp:", 4) == 0) {
+        u = url + 4;
+        scheme = "ftp";
+        is_ssl = 0;
+    }
+    if (!scheme || u[0] != '/' || u[1] != '/' || u[2] == '\0') {
+        if (!scheme && (u = strchr(url, ':')) && (u - url) > 14) {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10262)
+                          "overlong proxy URL scheme in %s", url);
+            return HTTP_BAD_REQUEST;
+        }
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01113)
+                      "HTTP: declining URL %s", url);
+        return DECLINED; /* only interested in HTTP, WS or FTP via proxy */
+    }
+    if (is_ssl && !ap_proxy_ssl_enable(NULL)) {
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01112)
+                      "HTTP: declining URL %s (mod_ssl not configured?)", url);
         return DECLINED;
-    if ((u - url) > 14)
-        return HTTP_BAD_REQUEST;
-    scheme = apr_pstrmemdup(p, url, u - url);
-    /* scheme is lowercase */
-    ap_str_tolower(scheme);
-    /* is it for us? */
-    if (strcmp(scheme, "https") == 0) {
-        if (!ap_proxy_ssl_enable(NULL)) {
-            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01112)
-                          "HTTPS: declining URL %s (mod_ssl not configured?)",
-                          url);
-            return DECLINED;
-        }
-        is_ssl = 1;
-        proxy_function = "HTTPS";
-    }
-    else if (!(strcmp(scheme, "http") == 0 || (strcmp(scheme, "ftp") == 0 && proxyname))) {
-        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01113) "HTTP: declining URL %s",
-                      url);
-        return DECLINED; /* only interested in HTTP, or FTP via proxy */
-    }
-    else {
-        if (*scheme == 'h')
-            proxy_function = "HTTP";
-        else
-            proxy_function = "FTP";
     }
     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "HTTP: serving URL %s", url);
 
     /* create space for state information */
-    if ((status = ap_proxy_acquire_connection(proxy_function, &backend,
+    if ((status = ap_proxy_acquire_connection(scheme, &backend,
                                               worker, r->server)) != OK) {
         return status;
     }
@@ -1910,7 +1936,7 @@ static int proxy_http_handler(request_re
     req->dconf = dconf;
     req->worker = worker;
     req->backend = backend;
-    req->proto = proxy_function;
+    req->proto = scheme;
     req->bucket_alloc = c->bucket_alloc;
     req->can_go_async = (mpm_can_poll &&
                          dconf->async_delay_set &&
@@ -1921,10 +1947,14 @@ static int proxy_http_handler(request_re
     if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) {
         req->force10 = 1;
     }
-    else if (*worker->s->upgrade) {
-        /* Forward Upgrade header if it matches the configured one(s). */
+    else if (*worker->s->upgrade || *req->proto == 'w') {
+        /* Forward Upgrade header if it matches the configured one(s),
+         * the default being "WebSocket" for ws[s] schemes.
+         */
         const char *upgrade = apr_table_get(r->headers_in, "Upgrade");
-        if (upgrade && ap_proxy_worker_can_upgrade(p, worker, upgrade)) {
+        if (upgrade && ap_proxy_worker_can_upgrade(p, worker, upgrade,
+                                                   (*req->proto == 'w')
+                                                   ? "WebSocket" : NULL)) {
             req->upgrade = upgrade;
         }
     }
@@ -2046,9 +2076,9 @@ static int proxy_http_handler(request_re
         }
 
         /* Step Two: Make the Connection */
-        if (ap_proxy_check_connection(proxy_function, backend, r->server, 1,
+        if (ap_proxy_check_connection(scheme, backend, r->server, 1,
                                       PROXY_CHECK_CONN_EMPTY)
-                && ap_proxy_connect_backend(proxy_function, backend, worker,
+                && ap_proxy_connect_backend(scheme, backend, worker,
                                             r->server)) {
             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01114)
                           "HTTP: failed to make connection to backend: %s",
@@ -2058,8 +2088,7 @@ static int proxy_http_handler(request_re
         }
 
         /* Step Three: Create conn_rec */
-        if ((status = ap_proxy_connection_create_ex(proxy_function,
-                                                    backend, r)) != OK)
+        if ((status = ap_proxy_connection_create_ex(scheme, backend, r)) != OK)
             break;
         req->origin = backend->connection;
 
@@ -2104,8 +2133,7 @@ cleanup:
     if (req->backend) {
         if (status != OK)
             req->backend->close = 1;
-        ap_proxy_release_connection(proxy_function, req->backend,
-                                    r->server);
+        ap_proxy_release_connection(scheme, req->backend, r->server);
     }
     return status;
 }

Modified: httpd/httpd/trunk/modules/proxy/mod_proxy_wstunnel.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy_wstunnel.c?rev=1885239&r1=1885238&r2=1885239&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/mod_proxy_wstunnel.c (original)
+++ httpd/httpd/trunk/modules/proxy/mod_proxy_wstunnel.c Thu Jan  7 13:19:08 2021
@@ -15,6 +15,7 @@
  */
 
 #include "mod_proxy.h"
+#include "http_config.h"
 #include "ap_mpm.h"
 
 module AP_MODULE_DECLARE_DATA proxy_wstunnel_module;
@@ -33,6 +34,8 @@ typedef struct ws_baton_t {
     const char *scheme;
 } ws_baton_t;
 
+static int fallback_to_mod_proxy_http;
+
 static void proxy_wstunnel_callback(void *b);
 
 static int proxy_wstunnel_pump(ws_baton_t *baton, int async)
@@ -108,6 +111,11 @@ static void proxy_wstunnel_callback(void
 
 static int proxy_wstunnel_check_trans(request_rec *r, const char *url)
 {
+    if (fallback_to_mod_proxy_http) {
+        ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "check_trans fallback");
+        return DECLINED;
+    }
+
     if (ap_cstr_casecmpn(url, "ws:", 3) != 0
             && ap_cstr_casecmpn(url, "wss:", 4) != 0) {
         return DECLINED;
@@ -138,6 +146,11 @@ static int proxy_wstunnel_canon(request_
     char *scheme;
     apr_port_t port, def_port;
 
+    if (fallback_to_mod_proxy_http) {
+        ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "canon fallback");
+        return DECLINED;
+    }
+
     /* ap_port_of_scheme() */
     if (ap_cstr_casecmpn(url, "ws:", 3) == 0) {
         url += 3;
@@ -325,6 +338,11 @@ static int proxy_wstunnel_handler(reques
     apr_uri_t *uri;
     int is_ssl = 0;
 
+    if (fallback_to_mod_proxy_http) {
+        ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "handler fallback");
+        return DECLINED;
+    }
+
     if (ap_cstr_casecmpn(url, "wss:", 4) == 0) {
         scheme = "WSS";
         is_ssl = 1;
@@ -333,15 +351,15 @@ static int proxy_wstunnel_handler(reques
         scheme = "WS";
     }
     else {
-        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02450) "declining URL %s", url);
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02450)
+                      "declining URL %s", url);
         return DECLINED;
     }
+    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "serving URL %s", url);
 
     upgrade = apr_table_get(r->headers_in, "Upgrade");
-    if (!upgrade || (*worker->s->upgrade &&
-                     !ap_proxy_worker_can_upgrade(p, worker, upgrade))
-                 || (!*worker->s->upgrade &&
-                     ap_cstr_casecmp(upgrade, "WebSocket") != 0)) {
+    if (!upgrade || !ap_proxy_worker_can_upgrade(p, worker, upgrade,
+                                                 "WebSocket")) {
         const char *worker_upgrade = *worker->s->upgrade ? worker->s->upgrade
                                                          : "WebSocket";
         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02900)
@@ -431,6 +449,24 @@ static const char * proxyws_set_asynch_d
     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 = 0;
+    if (ap_state_query(AP_SQ_MAIN_STATE) != AP_SQ_MS_CREATE_PRE_CONFIG) {
+        apr_size_t i = 0;
+        const module *mod;
+        while ((mod = ap_loaded_modules[i++])) {
+            if (strcmp(mod->name, "mod_proxy_http.c") == 0) {
+                fallback_to_mod_proxy_http = 1;
+                break;
+            }
+        }
+    }
+
+    return OK;
+}
+
 static const command_rec ws_proxy_cmds[] =
 {
     AP_INIT_TAKE1("ProxyWebsocketIdleTimeout", proxyws_set_idle, NULL,
@@ -443,9 +479,10 @@ static const command_rec ws_proxy_cmds[]
     {NULL}
 };
 
-static void ap_proxy_http_register_hook(apr_pool_t *p)
+static void ws_proxy_hooks(apr_pool_t *p)
 {
     static const char * const aszSucc[] = { "mod_proxy_http.c", NULL};
+    ap_hook_post_config(proxy_wstunnel_post_config, NULL, NULL, APR_HOOK_MIDDLE);
     proxy_hook_scheme_handler(proxy_wstunnel_handler, NULL, aszSucc, APR_HOOK_FIRST);
     proxy_hook_check_trans(proxy_wstunnel_check_trans, NULL, aszSucc, APR_HOOK_MIDDLE);
     proxy_hook_canon_handler(proxy_wstunnel_canon, NULL, aszSucc, APR_HOOK_FIRST);
@@ -458,5 +495,5 @@ AP_DECLARE_MODULE(proxy_wstunnel) = {
     NULL,                       /* create per-server config structure */
     NULL,                       /* merge per-server config structures */
     ws_proxy_cmds,              /* command apr_table_t */
-    ap_proxy_http_register_hook /* register hooks */
+    ws_proxy_hooks              /* register hooks */
 };

Modified: httpd/httpd/trunk/modules/proxy/proxy_util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/proxy_util.c?rev=1885239&r1=1885238&r2=1885239&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/proxy_util.c (original)
+++ httpd/httpd/trunk/modules/proxy/proxy_util.c Thu Jan  7 13:19:08 2021
@@ -1656,13 +1656,19 @@ PROXY_DECLARE(char *) ap_proxy_worker_na
 
 PROXY_DECLARE(int) ap_proxy_worker_can_upgrade(apr_pool_t *p,
                                                const proxy_worker *worker,
-                                               const char *upgrade)
+                                               const char *upgrade,
+                                               const char *dflt)
 {
+    /* Find in worker->s->upgrade list (if any) */
     const char *worker_upgrade = worker->s->upgrade;
-    return (*worker_upgrade
-            && (strcmp(worker_upgrade, "*") == 0
+    if (*worker_upgrade) {
+        return (strcmp(worker_upgrade, "*") == 0
                 || ap_cstr_casecmp(worker_upgrade, upgrade) == 0
-                || ap_find_token(p, worker_upgrade, upgrade)));
+                || ap_find_token(p, worker_upgrade, upgrade));
+    }
+
+    /* Compare to the provided default (if any) */
+    return (dflt && ap_cstr_casecmp(dflt, upgrade) == 0);
 }
 
 /*



Re: svn commit: r1885239 - in /httpd/httpd/trunk: changes-entries/proxy_wstunnel_to_http.txt docs/log-message-tags/next-number modules/proxy/mod_proxy.h modules/proxy/mod_proxy_http.c modules/proxy/mod_proxy_wstunnel.c modules/proxy/proxy_util.c

Posted by Yann Ylavic <yl...@gmail.com>.
On Thu, Jan 7, 2021 at 5:10 PM Eric Covener <co...@gmail.com> wrote:
>
> On Thu, Jan 7, 2021 at 11:00 AM Yann Ylavic <yl...@gmail.com> wrote:
> >
> > On Thu, Jan 7, 2021 at 2:19 PM <yl...@apache.org> wrote:
> > >
> > > Author: ylavic
> > > Date: Thu Jan  7 13:19:08 2021
> > > New Revision: 1885239
> > >
> > > URL: http://svn.apache.org/viewvc?rev=1885239&view=rev
> > > Log:
> > > mod_proxy_wstunnel: leave Upgrade requests handling to mod_proxy_http.
> > [snip]
> > > +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 = 0;
> > > +    if (ap_state_query(AP_SQ_MAIN_STATE) != AP_SQ_MS_CREATE_PRE_CONFIG) {
> > > +        apr_size_t i = 0;
> > > +        const module *mod;
> > > +        while ((mod = ap_loaded_modules[i++])) {
> > > +            if (strcmp(mod->name, "mod_proxy_http.c") == 0) {
> > > +                fallback_to_mod_proxy_http = 1;
> > > +                break;
> > > +            }
> > > +        }
> > > +    }
> >
>
> doesn't ap_find_linked_module() do this?

I tried to find it by grep-ing and following "ap_loaded_modules" and
was a bit surprised it didn't exist actually. I should have looked for
the other "ap_top_module" list :)
Changed in r1885244.

>
> > I wonder if, instead of the above loop to check whether mod_proxy_http
> > is loaded, we'd better have an OPTIONAL_FN registered by
> > mod_proxy_http and retrieved here.
>
> > ISTR that we allow for different versions of (proxy) modules to run
> > together, so if a user upgrades to the latest mod_proxy_wstunnel but
> > keeps an older mod_proxy_http the above would not work..
>
> I don't think we should have to tolerate this, not for included
> modules. Is the context maybe for downstream distributions?

I was thinking of them yes, but I suppose that the maintainers also
apply fixes with their whole context, and can figure out here that
both modules need an update (if they ever want to apply this).

>
> > Maybe I should apply the attached patch instead, or is it overkill?
>
> since it's already written and short and conceptually pretty simple I
> think it's good.

OK, just added as is to the backport proposal.

Thanks Eric.

Re: svn commit: r1885239 - in /httpd/httpd/trunk: changes-entries/proxy_wstunnel_to_http.txt docs/log-message-tags/next-number modules/proxy/mod_proxy.h modules/proxy/mod_proxy_http.c modules/proxy/mod_proxy_wstunnel.c modules/proxy/proxy_util.c

Posted by Eric Covener <co...@gmail.com>.
On Thu, Jan 7, 2021 at 11:00 AM Yann Ylavic <yl...@gmail.com> wrote:
>
> On Thu, Jan 7, 2021 at 2:19 PM <yl...@apache.org> wrote:
> >
> > Author: ylavic
> > Date: Thu Jan  7 13:19:08 2021
> > New Revision: 1885239
> >
> > URL: http://svn.apache.org/viewvc?rev=1885239&view=rev
> > Log:
> > mod_proxy_wstunnel: leave Upgrade requests handling to mod_proxy_http.
> [snip]
> > +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 = 0;
> > +    if (ap_state_query(AP_SQ_MAIN_STATE) != AP_SQ_MS_CREATE_PRE_CONFIG) {
> > +        apr_size_t i = 0;
> > +        const module *mod;
> > +        while ((mod = ap_loaded_modules[i++])) {
> > +            if (strcmp(mod->name, "mod_proxy_http.c") == 0) {
> > +                fallback_to_mod_proxy_http = 1;
> > +                break;
> > +            }
> > +        }
> > +    }
>

doesn't ap_find_linked_module() do this?

> I wonder if, instead of the above loop to check whether mod_proxy_http
> is loaded, we'd better have an OPTIONAL_FN registered by
> mod_proxy_http and retrieved here.

> ISTR that we allow for different versions of (proxy) modules to run
> together, so if a user upgrades to the latest mod_proxy_wstunnel but
> keeps an older mod_proxy_http the above would not work..

I don't think we should have to tolerate this, not for included
modules. Is the context maybe for downstream distributions?

> Maybe I should apply the attached patch instead, or is it overkill?

since it's already written and short and conceptually pretty simple I
think it's good.

Re: svn commit: r1885239 - in /httpd/httpd/trunk: changes-entries/proxy_wstunnel_to_http.txt docs/log-message-tags/next-number modules/proxy/mod_proxy.h modules/proxy/mod_proxy_http.c modules/proxy/mod_proxy_wstunnel.c modules/proxy/proxy_util.c

Posted by Yann Ylavic <yl...@gmail.com>.
On Thu, Jan 7, 2021 at 2:19 PM <yl...@apache.org> wrote:
>
> Author: ylavic
> Date: Thu Jan  7 13:19:08 2021
> New Revision: 1885239
>
> URL: http://svn.apache.org/viewvc?rev=1885239&view=rev
> Log:
> mod_proxy_wstunnel: leave Upgrade requests handling to mod_proxy_http.
[snip]
> +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 = 0;
> +    if (ap_state_query(AP_SQ_MAIN_STATE) != AP_SQ_MS_CREATE_PRE_CONFIG) {
> +        apr_size_t i = 0;
> +        const module *mod;
> +        while ((mod = ap_loaded_modules[i++])) {
> +            if (strcmp(mod->name, "mod_proxy_http.c") == 0) {
> +                fallback_to_mod_proxy_http = 1;
> +                break;
> +            }
> +        }
> +    }

I wonder if, instead of the above loop to check whether mod_proxy_http
is loaded, we'd better have an OPTIONAL_FN registered by
mod_proxy_http and retrieved here.
ISTR that we allow for different versions of (proxy) modules to run
together, so if a user upgrades to the latest mod_proxy_wstunnel but
keeps an older mod_proxy_http the above would not work..

Maybe I should apply the attached patch instead, or is it overkill?

Cheers;
Yann.

Re: svn commit: r1885239 - in /httpd/httpd/trunk: changes-entries/proxy_wstunnel_to_http.txt docs/log-message-tags/next-number modules/proxy/mod_proxy.h modules/proxy/mod_proxy_http.c modules/proxy/mod_proxy_wstunnel.c modules/proxy/proxy_util.c

Posted by Ruediger Pluem <rp...@apache.org>.

On 2/2/21 3:05 PM, Yann Ylavic wrote:
> On Tue, Feb 2, 2021 at 11:32 AM Ruediger Pluem <rp...@apache.org> wrote:
>>

> 
> Will you commit the above patch (or should I)?

Done as r1886141.

> Then I could propose it for backport with the other needed
> core_output_filter() change.

+1

> 
> Thanks for the review (again and again :).

Welcome

Regards

Rüdiger


Re: svn commit: r1885239 - in /httpd/httpd/trunk: changes-entries/proxy_wstunnel_to_http.txt docs/log-message-tags/next-number modules/proxy/mod_proxy.h modules/proxy/mod_proxy_http.c modules/proxy/mod_proxy_wstunnel.c modules/proxy/proxy_util.c

Posted by Yann Ylavic <yl...@gmail.com>.
On Tue, Feb 2, 2021 at 11:32 AM Ruediger Pluem <rp...@apache.org> wrote:
>
> On 1/7/21 2:19 PM, ylavic@apache.org wrote:
> > Author: ylavic
> > Date: Thu Jan  7 13:19:08 2021
> > New Revision: 1885239
[]
> >
> > -    /* find the scheme */
> > -    u = strchr(url, ':');
> > -    if (u == NULL || u[1] != '/' || u[2] != '/' || u[3] == '\0')
> > +    scheme = get_url_scheme(&u, &is_ssl);
> > +    if (!scheme && proxyname && strncasecmp(url, "ftp:", 4) == 0) {
> > +        u = url + 4;
> > +        scheme = "ftp";
> > +        is_ssl = 0;
> > +    }
> > +    if (!scheme || u[0] != '/' || u[1] != '/' || u[2] == '\0') {
> > +        if (!scheme && (u = strchr(url, ':')) && (u - url) > 14) {
> > +            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10262)
> > +                          "overlong proxy URL scheme in %s", url);
> > +            return HTTP_BAD_REQUEST;
> > +        }
>
> This breaks forward proxies with the CONNECT method.
> For CONNECT somwhere123456789.com:443 schema is NULL and u[0] is 's' and hence != /.

Yes, sorry about that.

>
> The following patches fixes this:
>
> Index: mod_proxy_http.c
> ===================================================================
> --- mod_proxy_http.c    (revision 1886120)
> +++ mod_proxy_http.c    (working copy)
> @@ -1903,15 +1903,15 @@
>          is_ssl = 0;
>      }
>      if (!scheme || u[0] != '/' || u[1] != '/' || u[2] == '\0') {
> -        if (!scheme && (u = strchr(url, ':')) && (u - url) > 14) {
> -            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10262)
> -                          "overlong proxy URL scheme in %s", url);
> -            return HTTP_BAD_REQUEST;
> -        }
>          ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01113)
>                        "HTTP: declining URL %s", url);
>          return DECLINED; /* only interested in HTTP, WS or FTP via proxy */
>      }
> +    if (!scheme && (u = strchr(url, ':')) && (u - url) > 14) {
> +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10262)
> +                      "overlong proxy URL scheme in %s", url);
> +        return HTTP_BAD_REQUEST;
> +    }
>      if (is_ssl && !ap_proxy_ssl_enable(NULL)) {
>          ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01112)
>                        "HTTP: declining URL %s (mod_ssl not configured?)", url);

+1

>
> Unfortunately this has been already backported in r1885605 and hence 2.4.x is now broken as well.

Will you commit the above patch (or should I)?
Then I could propose it for backport with the other needed
core_output_filter() change.

Thanks for the review (again and again :).

Regards;
Yann.

Re: svn commit: r1885239 - in /httpd/httpd/trunk: changes-entries/proxy_wstunnel_to_http.txt docs/log-message-tags/next-number modules/proxy/mod_proxy.h modules/proxy/mod_proxy_http.c modules/proxy/mod_proxy_wstunnel.c modules/proxy/proxy_util.c

Posted by Ruediger Pluem <rp...@apache.org>.

On 2/2/21 11:32 AM, Ruediger Pluem wrote:
> 
> 
> On 1/7/21 2:19 PM, ylavic@apache.org wrote:
>> Author: ylavic
>> Date: Thu Jan  7 13:19:08 2021
>> New Revision: 1885239

>> Modified: httpd/httpd/trunk/modules/proxy/mod_proxy_http.c
>> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy_http.c?rev=1885239&r1=1885238&r2=1885239&view=diff
>> ==============================================================================
>> --- httpd/httpd/trunk/modules/proxy/mod_proxy_http.c (original)
>> +++ httpd/httpd/trunk/modules/proxy/mod_proxy_http.c Thu Jan  7 13:19:08 2021

>> @@ -1840,9 +1877,8 @@ static int proxy_http_handler(request_re
>>                                apr_port_t proxyport)
>>  {
>>      int status;
>> -    char *scheme;
>> -    const char *proxy_function;
>> -    const char *u;
>> +    const char *scheme;
>> +    const char *u = url;
>>      proxy_http_req_t *req = NULL;
>>      proxy_conn_rec *backend = NULL;
>>      apr_bucket_brigade *input_brigade = NULL;
>> @@ -1860,41 +1896,31 @@ static int proxy_http_handler(request_re
>>      apr_pool_t *p = r->pool;
>>      apr_uri_t *uri;
>>  
>> -    /* find the scheme */
>> -    u = strchr(url, ':');
>> -    if (u == NULL || u[1] != '/' || u[2] != '/' || u[3] == '\0')
>> +    scheme = get_url_scheme(&u, &is_ssl);
>> +    if (!scheme && proxyname && strncasecmp(url, "ftp:", 4) == 0) {
>> +        u = url + 4;
>> +        scheme = "ftp";
>> +        is_ssl = 0;
>> +    }
>> +    if (!scheme || u[0] != '/' || u[1] != '/' || u[2] == '\0') {
>> +        if (!scheme && (u = strchr(url, ':')) && (u - url) > 14) {
>> +            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10262)
>> +                          "overlong proxy URL scheme in %s", url);
>> +            return HTTP_BAD_REQUEST;
>> +        }
> 
> This breaks forward proxies with the CONNECT method.
> For CONNECT somwhere123456789.com:443 schema is NULL and u[0] is 's' and hence != /.
> 
> The following patches fixes this:
> 
> Index: mod_proxy_http.c
> ===================================================================
> --- mod_proxy_http.c	(revision 1886120)
> +++ mod_proxy_http.c	(working copy)
> @@ -1903,15 +1903,15 @@
>          is_ssl = 0;
>      }
>      if (!scheme || u[0] != '/' || u[1] != '/' || u[2] == '\0') {
> -        if (!scheme && (u = strchr(url, ':')) && (u - url) > 14) {
> -            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10262)
> -                          "overlong proxy URL scheme in %s", url);
> -            return HTTP_BAD_REQUEST;
> -        }
>          ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01113)
>                        "HTTP: declining URL %s", url);
>          return DECLINED; /* only interested in HTTP, WS or FTP via proxy */
>      }
> +    if (!scheme && (u = strchr(url, ':')) && (u - url) > 14) {
> +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10262)
> +                      "overlong proxy URL scheme in %s", url);
> +        return HTTP_BAD_REQUEST;
> +    }
>      if (is_ssl && !ap_proxy_ssl_enable(NULL)) {
>          ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01112)
>                        "HTTP: declining URL %s (mod_ssl not configured?)", url);
> 
> Unfortunately this has been already backported in r1885605 and hence 2.4.x is now broken as well.
> 

And it looks like that the test suite has no forward proxy tests at all which caused this to be missed by the test framework.

Regards

Rüdiger


Re: svn commit: r1885239 - in /httpd/httpd/trunk: changes-entries/proxy_wstunnel_to_http.txt docs/log-message-tags/next-number modules/proxy/mod_proxy.h modules/proxy/mod_proxy_http.c modules/proxy/mod_proxy_wstunnel.c modules/proxy/proxy_util.c

Posted by Ruediger Pluem <rp...@apache.org>.

On 1/7/21 2:19 PM, ylavic@apache.org wrote:
> Author: ylavic
> Date: Thu Jan  7 13:19:08 2021
> New Revision: 1885239
> 
> URL: http://svn.apache.org/viewvc?rev=1885239&view=rev
> Log:
> mod_proxy_wstunnel: leave Upgrade requests handling to mod_proxy_http.
> 
> Let mod_proxy_http's canon and scheme handlers accept "ws[s]:" schemes so that
> mod_proxy_wstunnel can decline requests when mod_proxy_http is loaded.
> 
> * modules/proxy/{mod_proxy.h,proxy_util.c} (ap_proxy_worker_can_upgrade):
>   Add a "dflt" argument to ap_proxy_worker_can_upgrade() which, if not NULL,
>   is matched when no worker upgrade= parameter is configured. This allows to
>   handle the default "Upgrade: websocket" case for "ws[s]:" schemes.
> 
> * modules/proxy/mod_proxy_http.c (proxy_http_canon, proxy_http_handler):
>   Add and use the new get_url_scheme() helper to parse URL schemes handled by
>   mod_proxy_http and use it in canon and scheme handlers. This helper now
>   accepts ws[s] schemes.
> 
> * modules/proxy/mod_proxy_wstunnel.c (proxy_wstunnel_post_config):
>   New post_config hook to detect whether mod_proxy_http is loaded and set
>   global fallback_to_mod_proxy_http flag in this case.
> 
> * modules/proxy/mod_proxy_wstunnel.c (proxy_wstunnel_check_trans,
>                                       proxy_wstunnel_canon,
>                                       proxy_wstunnel_handler):
>   These hooks now early return DECLINED if fallback_to_mod_proxy_http is set.
> 
> Added:
>     httpd/httpd/trunk/changes-entries/proxy_wstunnel_to_http.txt
> Modified:
>     httpd/httpd/trunk/docs/log-message-tags/next-number
>     httpd/httpd/trunk/modules/proxy/mod_proxy.h
>     httpd/httpd/trunk/modules/proxy/mod_proxy_http.c
>     httpd/httpd/trunk/modules/proxy/mod_proxy_wstunnel.c
>     httpd/httpd/trunk/modules/proxy/proxy_util.c
> 
> Added: httpd/httpd/trunk/changes-entries/proxy_wstunnel_to_http.txt
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/changes-entries/proxy_wstunnel_to_http.txt?rev=1885239&view=auto
> ==============================================================================
> --- httpd/httpd/trunk/changes-entries/proxy_wstunnel_to_http.txt (added)
> +++ httpd/httpd/trunk/changes-entries/proxy_wstunnel_to_http.txt Thu Jan  7 13:19:08 2021
> @@ -0,0 +1,4 @@
> +  *) mod_proxy_wstunnel: Leave Upgrade requests handling to mod_proxy_http,
> +     allowing for (non-)Upgrade negotiation with the origin server.
> +     [Yann Ylavic]
> +
> 
> Modified: httpd/httpd/trunk/docs/log-message-tags/next-number
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/log-message-tags/next-number?rev=1885239&r1=1885238&r2=1885239&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/docs/log-message-tags/next-number (original)
> +++ httpd/httpd/trunk/docs/log-message-tags/next-number Thu Jan  7 13:19:08 2021
> @@ -1 +1 @@
> -10262
> +10263
> 
> Modified: httpd/httpd/trunk/modules/proxy/mod_proxy.h
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy.h?rev=1885239&r1=1885238&r2=1885239&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/modules/proxy/mod_proxy.h (original)
> +++ httpd/httpd/trunk/modules/proxy/mod_proxy.h Thu Jan  7 13:19:08 2021
> @@ -755,11 +755,13 @@ PROXY_DECLARE(char *) ap_proxy_worker_na
>   * @param p       memory pool used for displaying worker name
>   * @param worker  the worker
>   * @param upgrade the Upgrade header to match
> + * @param dflt    default protocol (NULL for none)
>   * @return        1 (true) or 0 (false)
>   */
>  PROXY_DECLARE(int) ap_proxy_worker_can_upgrade(apr_pool_t *p,
>                                                 const proxy_worker *worker,
> -                                               const char *upgrade);
> +                                               const char *upgrade,
> +                                               const char *dflt);
>  
>  /**
>   * Get the worker from proxy configuration
> 
> Modified: httpd/httpd/trunk/modules/proxy/mod_proxy_http.c
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy_http.c?rev=1885239&r1=1885238&r2=1885239&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/modules/proxy/mod_proxy_http.c (original)
> +++ httpd/httpd/trunk/modules/proxy/mod_proxy_http.c Thu Jan  7 13:19:08 2021
> @@ -28,37 +28,71 @@ static int (*ap_proxy_clear_connection_f
>  static apr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n,
>                                      request_rec *r, int flags, int *read);
>  
> +static const char *get_url_scheme(const char **url, int *is_ssl)
> +{
> +    const char *u = *url;
> +
> +    switch (u[0]) {
> +    case 'h':
> +    case 'H':
> +        if (strncasecmp(u + 1, "ttp", 3) == 0) {
> +            if (u[4] == ':') {
> +                *is_ssl = 0;
> +                *url = u + 5;
> +                return "http";
> +            }
> +            if (apr_tolower(u[4]) == 's' && u[5] == ':') {
> +                *is_ssl = 1;
> +                *url = u + 6;
> +                return "https";
> +            }
> +        }
> +        break;
> +
> +    case 'w':
> +    case 'W':
> +        if (apr_tolower(u[1]) == 's') {
> +            if (u[2] == ':') {
> +                *is_ssl = 0;
> +                *url = u + 3;
> +                return "ws";
> +            }
> +            if (apr_tolower(u[2]) == 's' && u[3] == ':') {
> +                *is_ssl = 0;
> +                *url = u + 4;
> +                return "wss";
> +            }
> +        }
> +        break;
> +    }
> +
> +    *is_ssl = 0;
> +    return NULL;
> +}
>  
>  /*
>   * Canonicalise http-like URLs.
>   *  scheme is the scheme for the URL
>   *  url    is the URL starting with the first '/'
> - *  def_port is the default port for this scheme.
>   */
>  static int proxy_http_canon(request_rec *r, char *url)
>  {
> +    const char *base_url = url;
>      char *host, *path, sport[7];
>      char *search = NULL;
>      const char *err;
>      const char *scheme;
>      apr_port_t port, def_port;
> +    int is_ssl = 0;
>  
> -    /* ap_port_of_scheme() */
> -    if (ap_cstr_casecmpn(url, "http:", 5) == 0) {
> -        url += 5;
> -        scheme = "http";
> -    }
> -    else if (ap_cstr_casecmpn(url, "https:", 6) == 0) {
> -        url += 6;
> -        scheme = "https";
> -    }
> -    else {
> +    scheme = get_url_scheme((const char **)&url, &is_ssl);
> +    if (!scheme) {
>          return DECLINED;
>      }
> -    port = def_port = ap_proxy_port_of_scheme(scheme);
> +    port = def_port = (is_ssl) ? DEFAULT_HTTPS_PORT : DEFAULT_HTTP_PORT;
>  
>      ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
> -                  "HTTP: canonicalising URL %s", url);
> +                  "HTTP: canonicalising URL %s", base_url);
>  
>      /* do syntatic check.
>       * We break the URL into host, port, path, search
> @@ -66,7 +100,7 @@ static int proxy_http_canon(request_rec
>      err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
>      if (err) {
>          ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01083)
> -                      "error parsing URL %s: %s", url, err);
> +                      "error parsing URL %s: %s", base_url, err);
>          return HTTP_BAD_REQUEST;
>      }
>  
> @@ -106,8 +140,9 @@ static int proxy_http_canon(request_rec
>      if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */
>          host = apr_pstrcat(r->pool, "[", host, "]", NULL);
>      }
> +
>      r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport,
> -            "/", path, (search) ? "?" : "", (search) ? search : "", NULL);
> +                              "/", path, (search) ? "?" : "", search, NULL);
>      return OK;
>  }
>  
> @@ -1568,7 +1603,9 @@ int ap_proxy_http_process_response(proxy
>           * may be an HTTP_UPGRADE_REQUIRED response or some other status where
>           * Upgrade makes sense to negotiate the protocol by other means.
>           */
> -        if (upgrade && ap_proxy_worker_can_upgrade(p, worker, upgrade)) {
> +        if (upgrade && ap_proxy_worker_can_upgrade(p, worker, upgrade,
> +                                                   (*req->proto == 'w')
> +                                                   ? "WebSocket" : NULL)) {
>              apr_table_setn(r->headers_out, "Connection", "Upgrade");
>              apr_table_setn(r->headers_out, "Upgrade", apr_pstrdup(p, upgrade));
>          }
> @@ -1840,9 +1877,8 @@ static int proxy_http_handler(request_re
>                                apr_port_t proxyport)
>  {
>      int status;
> -    char *scheme;
> -    const char *proxy_function;
> -    const char *u;
> +    const char *scheme;
> +    const char *u = url;
>      proxy_http_req_t *req = NULL;
>      proxy_conn_rec *backend = NULL;
>      apr_bucket_brigade *input_brigade = NULL;
> @@ -1860,41 +1896,31 @@ static int proxy_http_handler(request_re
>      apr_pool_t *p = r->pool;
>      apr_uri_t *uri;
>  
> -    /* find the scheme */
> -    u = strchr(url, ':');
> -    if (u == NULL || u[1] != '/' || u[2] != '/' || u[3] == '\0')
> +    scheme = get_url_scheme(&u, &is_ssl);
> +    if (!scheme && proxyname && strncasecmp(url, "ftp:", 4) == 0) {
> +        u = url + 4;
> +        scheme = "ftp";
> +        is_ssl = 0;
> +    }
> +    if (!scheme || u[0] != '/' || u[1] != '/' || u[2] == '\0') {
> +        if (!scheme && (u = strchr(url, ':')) && (u - url) > 14) {
> +            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10262)
> +                          "overlong proxy URL scheme in %s", url);
> +            return HTTP_BAD_REQUEST;
> +        }

This breaks forward proxies with the CONNECT method.
For CONNECT somwhere123456789.com:443 schema is NULL and u[0] is 's' and hence != /.

The following patches fixes this:

Index: mod_proxy_http.c
===================================================================
--- mod_proxy_http.c	(revision 1886120)
+++ mod_proxy_http.c	(working copy)
@@ -1903,15 +1903,15 @@
         is_ssl = 0;
     }
     if (!scheme || u[0] != '/' || u[1] != '/' || u[2] == '\0') {
-        if (!scheme && (u = strchr(url, ':')) && (u - url) > 14) {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10262)
-                          "overlong proxy URL scheme in %s", url);
-            return HTTP_BAD_REQUEST;
-        }
         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01113)
                       "HTTP: declining URL %s", url);
         return DECLINED; /* only interested in HTTP, WS or FTP via proxy */
     }
+    if (!scheme && (u = strchr(url, ':')) && (u - url) > 14) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10262)
+                      "overlong proxy URL scheme in %s", url);
+        return HTTP_BAD_REQUEST;
+    }
     if (is_ssl && !ap_proxy_ssl_enable(NULL)) {
         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01112)
                       "HTTP: declining URL %s (mod_ssl not configured?)", url);

Unfortunately this has been already backported in r1885605 and hence 2.4.x is now broken as well.


Regards

Rüdiger