On Thu, Jun 25, 2020 at 1:27 PM Ruediger Pluem <rpl...@apache.org> wrote:
>
> On 6/25/20 12:13 PM, Yann Ylavic wrote:
> > Index: modules/proxy/mod_proxy.c
> > ===================================================================
> > --- modules/proxy/mod_proxy.c (revision 1879145)
> > +++ modules/proxy/mod_proxy.c (working copy)
>
> > @@ -987,10 +991,10 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_re
> >                        "URI path '%s' matches proxy handler '%s'", r->uri,
> >                        found);
> >
> > -        return OK;
> > +        return servlet ? DONE : OK;
>
> Why setting it to DONE in the servlet case? Wouldn't that cause 
> ap_process_request_internal to be left early?

No, ap_process_request_internal() would just skip r->uri decoding (we
are in pre_trans hook here, since mapping=servlet only happens there).
Anyway, it's an orthogonal change sorry, maybe we still want uri
decoding for directory/location walk in the servlet case, but since
this patch actually modifies r->uri (while other proxy mappings do
not), I thought it could be the final transformation (that's DONE
returned from pre_trans).

The only case where it matters is for encoded control/reserved chars
(unreserved are always decoded during initial normalization). So for
the authz/authn case you mentioned it means that the admin would have
to use/match the encoded form of the path (in <Location>) when the
concerned path contains reserved chars.
Something like <Location "/admin%3Bfoo"> if the final app on Tomcat is
really called "admin;foo" (which I don't recommend!), but it kind of
make sense because with servlet normalization <Location /admin;foo>
would never match..

That's all theoretical and unlikely case, but that's where we are ;)

By the way, I think a more correct patch would be this one (attached),
whether it returns DONE or OK (I kept DONE for now, until we get
further on this lovely encoding discussion :)
The change is that r->uri is rewritten in-place so that
r->parsed_uri.path gets updated too.

Regards;
Yann.
Index: modules/proxy/mod_proxy.c
===================================================================
--- modules/proxy/mod_proxy.c	(revision 1879145)
+++ modules/proxy/mod_proxy.c	(working copy)
@@ -17,6 +17,7 @@
 #include "mod_proxy.h"
 #include "mod_core.h"
 #include "apr_optional.h"
+#include "apr_strings.h"
 #include "scoreboard.h"
 #include "mod_status.h"
 #include "proxy_util.h"
@@ -574,10 +575,11 @@ static int alias_match(const char *uri, const char
  * Inspired by mod_jk's jk_servlet_normalize().
  */
 static int alias_match_servlet(apr_pool_t *p,
-                               const char *uri,
+                               const char **urip,
                                const char *alias)
 {
     char *map;
+    const char *uri = *urip;
     apr_array_header_t *stack;
     int map_pos, uri_pos, alias_pos, first_pos;
     int alias_depth = 0, depth;
@@ -759,6 +761,8 @@ static int alias_match_servlet(apr_pool_t *p,
     if (alias[alias_pos - 1] != '/' && uri[uri_pos - 1] == '/') {
         uri_pos--;
     }
+
+    *urip = map;
     return uri_pos;
 }
 
@@ -872,6 +876,7 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_re
     int mismatch = 0;
     unsigned int nocanon = ent->flags & PROXYPASS_NOCANON;
     const char *use_uri = nocanon ? r->unparsed_uri : r->uri;
+    const char *servlet_uri = NULL;
 
     if (dconf && (dconf->interpolate_env == 1) && (ent->flags & PROXYPASS_INTERPOLATE)) {
         fake = proxy_interpolate(r, ent->fake);
@@ -933,8 +938,9 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_re
     }
     else {
         if ((ent->flags & PROXYPASS_MAP_SERVLET) == PROXYPASS_MAP_SERVLET) {
+            servlet_uri = r->uri;
+            len = alias_match_servlet(r->pool, &servlet_uri, fake);
             nocanon = 0; /* ignored since servlet's normalization applies */
-            len = alias_match_servlet(r->pool, r->uri, fake);
         }
         else {
             len = alias_match(r->uri, fake);
@@ -969,7 +975,7 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_re
          */
         int rc = proxy_run_check_trans(r, found + 6);
         if (rc != OK && rc != DECLINED) {
-            return DONE;
+            return HTTP_CONTINUE;
         }
 
         r->filename = found;
@@ -983,14 +989,27 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_re
             apr_table_setn(r->notes, "proxy-noquery", "1");
         }
 
+        if (servlet_uri) {
+            ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO()
+                          "Servlet path '%s' (%s) matches proxy handler '%s'",
+                          r->uri, servlet_uri, found);
+
+            /* We change r->uri in-place so that r->parsed_uri.path gets
+             * updated too. Normalized servlet_uri is necessarily shorter
+             * than the original r->uri, so strcpy() is fine.
+             */
+            AP_DEBUG_ASSERT(strlen(r->uri) >= strlen(servlet_uri));
+            strcpy(r->uri, servlet_uri);
+            return DONE;
+        }
+
         ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(03464)
                       "URI path '%s' matches proxy handler '%s'", r->uri,
                       found);
-
         return OK;
     }
 
-    return DONE;
+    return HTTP_CONTINUE;
 }
 
 static int proxy_trans(request_rec *r, int pre_trans)
@@ -1042,7 +1061,7 @@ static int proxy_trans(request_rec *r, int pre_tra
         enc = (dconf->alias->flags & PROXYPASS_MAP_ENCODED) != 0;
         if (!(pre_trans ^ enc)) {
             int rv = ap_proxy_trans_match(r, dconf->alias, dconf);
-            if (DONE != rv) {
+            if (rv != HTTP_CONTINUE) {
                 return rv;
             }
         }
@@ -1054,7 +1073,7 @@ static int proxy_trans(request_rec *r, int pre_tra
         enc = (ent->flags & PROXYPASS_MAP_ENCODED) != 0;
         if (!(pre_trans ^ enc)) {
             int rv = ap_proxy_trans_match(r, ent, dconf);
-            if (DONE != rv) {
+            if (rv != HTTP_CONTINUE) {
                 return rv;
             }
         }

Reply via email to