On Sat, Mar 11, 2023 at 11:10 PM <cove...@apache.org> wrote:
>
> Author: covener
> Date: Sat Mar 11 22:10:09 2023
> New Revision: 1908301
>
> URL: http://svn.apache.org/viewvc?rev=1908301&view=rev
> Log:
> add [BCTLS] alternative to [B] for 2.4.56 problems

Nice, that was the missing bit I think. Would have been great if
[BCTLS] was the default but I guess it's not possible with the
redirect case which %-encodes by default (chicken and egg problem to
avoid double encoding..).

>
> +++ httpd/httpd/trunk/modules/mappers/mod_rewrite.c Sat Mar 11 22:10:09 2023
> @@ -684,14 +685,27 @@ static APR_INLINE unsigned char *c2x(uns
>   * Escapes a backreference in a similar way as php's urlencode does.
>   * Based on ap_os_escape_path in server/util.c
>   */
> -static char *escape_backref(apr_pool_t *p, const char *path, const char 
> *escapeme, int noplus) {
> +static char *escape_backref(apr_pool_t *p, const char *path, const char 
> *escapeme, int flags) {
>      char *copy = apr_palloc(p, 3 * strlen(path) + 3);
>      const unsigned char *s = (const unsigned char *)path;
>      unsigned char *d = (unsigned char *)copy;
>      unsigned c;
> +    int noplus = flags & RULEFLAG_ESCAPENOPLUS;
> +    int ctls = flags & RULEFLAG_ESCAPECTLS;
>
>      while ((c = *s)) {
> -        if (!escapeme) {
> +        if (ctls) {
> +            if (c == ' ' && !noplus) {
> +                *d++ = '+';
> +            }
> +            else if (apr_iscntrl(c)) {

Seems we should encode space here too => (apr_iscntrl(c) || c == ' ') ?

> +                d = c2x(c, '%', d);
> +            }
> +            else {
> +                *d++ = c;
> +            }
> +        }
> +        else if (!escapeme) {
>              if (apr_isalnum(c) || c == '_') {
>                  *d++ = c;
>              }
> @@ -702,9 +716,9 @@ static char *escape_backref(apr_pool_t *
>                  d = c2x(c, '%', d);
>              }
>          }
> -        else {
> +        else {

Maybe we could make [B=] and [BTCLS] not mutually exclusive (encode
both controls and whatever in B=).
I was thinking of a [BNEG] flag too (encode everything but what's in
B=), and never encode alnum or '_', so all in all some further patch
like the attached one. WDYT?

Regards;
Yann.
Index: modules/mappers/mod_rewrite.c
===================================================================
--- modules/mappers/mod_rewrite.c	(revision 1908321)
+++ modules/mappers/mod_rewrite.c	(working copy)
@@ -99,6 +99,8 @@
 #include "util_charset.h"
 #endif
 
+#include "test_char.h"
+
 static ap_dbd_t *(*dbd_acquire)(request_rec*) = NULL;
 static void (*dbd_prepare)(server_rec*, const char*, const char*) = NULL;
 static const char* really_last_key = "rewrite_really_last";
@@ -175,6 +177,7 @@ static const char* really_last_key = "rewrite_real
 #define RULEFLAG_QSLAST             (1<<19)
 #define RULEFLAG_QSNONE             (1<<20) /* programattic only */
 #define RULEFLAG_ESCAPECTLS         (1<<21)
+#define RULEFLAG_ESCAPENEG          (1<<22)
 
 /* return code of the rewrite rule
  * the result may be escaped - or not
@@ -688,51 +691,27 @@ static APR_INLINE unsigned char *c2x(unsigned what
 static char *escape_backref(apr_pool_t *p, const char *path, const char *escapeme, int flags) {
     char *copy = apr_palloc(p, 3 * strlen(path) + 3);
     const unsigned char *s = (const unsigned char *)path;
-    unsigned char *d = (unsigned char *)copy;
-    unsigned c;
-    int noplus = flags & RULEFLAG_ESCAPENOPLUS;
-    int ctls = flags & RULEFLAG_ESCAPECTLS;
+    unsigned char *d = (unsigned char *)copy, c;
+    int noplus = (flags & RULEFLAG_ESCAPENOPLUS) != 0;
+    int ctls = (flags & RULEFLAG_ESCAPECTLS) != 0;
+    int neg = (flags & RULEFLAG_ESCAPENEG) != 0;
 
     while ((c = *s)) {
-        if (ctls) {
-            if (c == ' ' && !noplus) {
-                *d++ = '+';
-            }
-            else if (apr_iscntrl(c)) {
-                d = c2x(c, '%', d);
-            }
-            else {
-                *d++ = c;
-            }
-        }
-        else if (!escapeme) {
+        if (!c
+            || (ctls ? !TEST_CHAR(c, T_VCHAR_OBSTEXT) : !escapeme)
+            || (escapeme && ((ap_strchr_c(escapeme, c) != NULL) ^ neg))) {
             if (apr_isalnum(c) || c == '_') {
                 *d++ = c;
             }
-            else if (c == ' ' && !noplus) {
+            else if (c == ' ' && !noplus) { 
                 *d++ = '+';
             }
-            else {
+            else { 
                 d = c2x(c, '%', d);
             }
         }
         else {
-            const char *esc = escapeme;
-            while (*esc) {
-                if (c == *esc) { 
-                    if (c == ' ' && !noplus) { 
-                        *d++ = '+';
-                    }
-                    else { 
-                        d = c2x(c, '%', d);
-                    }
-                    break;
-                }
-                ++esc;
-            }
-            if (!*esc) { 
-                *d++ = c;
-            }
+            *d++ = c;
         }
         ++s;
     }
@@ -3603,6 +3582,9 @@ static const char *cmd_rewriterule_setflag(apr_poo
                 cfg->escapes = val;
             }
         }
+        else if (!strcasecmp(key, "NEG")) { 
+            cfg->flags |= RULEFLAG_ESCAPENEG;
+        }
         else if (!strcasecmp(key, "NP") || !strcasecmp(key, "ackrefernoplus")) { 
             cfg->flags |= RULEFLAG_ESCAPENOPLUS;
         }

Reply via email to