Re: [users@httpd] ProxyPass option mapping=servlet hurts mod_rewrite

2022-02-28 Thread Yann Ylavic
Hi Hendrik,

>
> Is this a bug or do I have to use the "mapping=servlet" option very carefully?

I'd say both..
mod_proxy mapping= acts very early in request processing and kind of
"appropriates" the request URI to mod_proxy, confusing mod_rewrite, so
it's probably a bug because your use case is legitimate and should be
handled.
But you'll also have to be careful because early mapping also means
that the normalization applied to the request URI depends on the
mapping, so the URI as seen by mod_rewrite and/or  sections
depends on the mapping. For instance mapping=servlet/decoded will not
%-decode the URI internally (besides the "unreserved" characters as
defined by the RFC), so you could have to use the %-encoded form of
some characters in a RewriteRule to match special URIs (this is not
the case in your exemple configuration, I'm warning just in case..).

Anyway, could you please try the attached patch and see if it works for you?

Regards;
Yann.
Index: modules/mappers/mod_rewrite.c
===
--- modules/mappers/mod_rewrite.c	(revision 1898463)
+++ modules/mappers/mod_rewrite.c	(working copy)
@@ -4576,7 +4576,7 @@ static int hook_uri2file(request_rec *r)
 unsigned int port;
 int rulestatus;
 void *skipdata;
-const char *oargs;
+char *ofilename, *oargs;
 
 /*
  *  retrieve the config structures
@@ -4629,7 +4629,10 @@ static int hook_uri2file(request_rec *r)
 /*
  *  remember the original query string for later check, since we don't
  *  want to apply URL-escaping when no substitution has changed it.
+ *  also, we'll restore original r->filename if we decline this
+ *  request.
  */
+ofilename = r->filename;
 oargs = r->args;
 
 /*
@@ -4672,13 +4675,14 @@ static int hook_uri2file(request_rec *r)
 apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URI, var);
 
 if (!(saved_rulestatus = apr_table_get(r->notes,"mod_rewrite_rewritten"))) {
-/* if filename was not initially set,
- * we start with the requested URI
+/* if r->filename was not initially set, or if proxy_pre_translate_name()
+ * set its reverse "proxy:" URL, we start with the requested URI
  */
-if (r->filename == NULL) {
+if (r->filename == NULL || r->proxyreq == PROXYREQ_REVERSE) {
 r->filename = apr_pstrdup(r->pool, r->uri);
-rewritelog((r, 2, NULL, "init rewrite engine with requested uri %s",
-r->filename));
+rewritelog((r, 2, NULL, "init rewrite engine with requested uri "
+"%s. Original filename = %s",
+r->filename, ofilename ? ofilename : "n/a"));
 }
 else {
 rewritelog((r, 2, NULL, "init rewrite engine with passed filename "
@@ -4702,6 +4706,7 @@ static int hook_uri2file(request_rec *r)
 if (rulestatus) {
 unsigned skip;
 apr_size_t flen;
+int to_proxyreq;
 
 if (ACTION_STATUS == rulestatus) {
 int n = r->status;
@@ -4711,7 +4716,19 @@ static int hook_uri2file(request_rec *r)
 }
 
 flen = r->filename ? strlen(r->filename) : 0;
-if (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0) {
+to_proxyreq = (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0);
+
+/* If a proxy reverse/pre_trans filename was rewritten to a new uri
+ * this is not a proxy request anymore.
+ */
+if (r->proxyreq == PROXYREQ_REVERSE && !to_proxyreq) {
+if (r->handler && strcmp(r->handler, "proxy-server") == 0) {
+r->handler = NULL;
+}
+r->proxyreq = PROXYREQ_NONE;
+}
+
+if (to_proxyreq) {
 /* it should be go on as an internal proxy request */
 
 /* check if the proxy module is enabled, so
@@ -4735,9 +4752,7 @@ static int hook_uri2file(request_rec *r)
 r->filename = apr_pstrcat(r->pool, r->filename,
   r->path_info, NULL);
 }
-if ((r->args != NULL)
-&& ((r->proxyreq == PROXYREQ_PROXY)
-|| (rulestatus == ACTION_NOESCAPE))) {
+if (r->args && (r->proxyreq || rulestatus == ACTION_NOESCAPE)) {
 /* see proxy_http:proxy_http_canon() */
 r->filename = apr_pstrcat(r->pool, r->filename,
   "?", r->args, NULL);
@@ -4878,7 +4893,9 @@ static int hook_uri2file(request_rec *r)
 }
 }
 else {
-rewritelog((r, 1, NULL, "pass through %s", r->filename));
+rewritelog((r, 1, NULL, "pass through %s (%s)",
+r->filename, ofilename));
+r->filename = ofilename;
 return DECLINED;
 }
 }
@@ -5213,7 +5230,8 @@ static int hook_fixup(request_rec *r)
 }
 }
 else {
-rewritelog((r, 1, dconf->direct

[users@httpd] ProxyPass option mapping=servlet hurts mod_rewrite

2022-02-28 Thread Hendrik Harms
Hi httpd users,

After adding the mapping=servlet option in the ProxyPass configuration, my
RewriteRule no longer works as desired.

Example:

   Hostname:  example.org
   ProxyPass  /alpha  http://server1.localnet:8080/alpha
   ProxyPass  /beta   http://server2.localnet:8080/beta  mapping=servlet
   RewriteRule ^/alpha - [F]
   RewriteRule ^/beta  - [F]

Calling https://example.org/alpha/anypath/ sends back a 403 Forbidden like
desired.
Calling https://example.org/beta/anypath/ sends back the beta content. The
RewriteRule does not catch the request.

I've increased the Logging
   LogLevel proxy:trace3
   LogLevel rewrite:trace3

Calling the alpha url I see this in my error.log:
[proxy:trace2] mod_proxy.c(884): AH03461: attempting to match URI path
'/alpha/anypath/' against prefix '/beta' for proxying
[rewrite:trace2] mod_rewrite.c(480):  init rewrite engine with
requested uri /alpha/anypath/
[rewrite:trace3] mod_rewrite.c(480):  applying pattern '^/alpha' to uri
'/alpha/anypath/'
[rewrite:trace2] mod_rewrite.c(480):  forcing responsecode 403 for
/alpha/anypath/

Calling the beta url I see this in my log:
[proxy:trace2] mod_proxy.c(884): AH03461: attempting to match URI path
'/beta/anypath/' against prefix '/beta' for proxying
[proxy:trace1] mod_proxy.c(986): AH10248: Servlet path '/beta/anypath/'
(/beta/anypath/) matches proxy handler 'proxy:
http://server2.localnet:8080/beta/anypath/'
[rewrite:trace2] mod_rewrite.c(480):  init rewrite engine with passed
filename proxy:http://server2.localnet:8080/beta/anypath/. Original uri =
/beta/anypath/
[rewrite:trace3] mod_rewrite.c(480):  applying pattern '^/alpha' to uri
'proxy:http://server2.localnet:8080/beta/anypath/'
[rewrite:trace3] mod_rewrite.c(480):  applying pattern '^/beta' to uri
'proxy:http://server2.localnet:8080/beta/anypath/'
[rewrite:trace1] mod_rewrite.c(480):  pass through proxy:
http://server2.localnet:8080/beta/anypath/
[proxy_http:trace1] mod_proxy_http.c(98): HTTP: canonicalising URL
http://server2.localnet:8080/beta/anypath/
[proxy:trace2] proxy_util.c(2337): http: found worker
http://server2.localnet:8080/beta for
http://server2.localnet:8080/beta/anypath/

Is this a bug or do I have to use the "mapping=servlet" option very
carefully?

regards,
Hendrik