httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Rodent of Unusual Size <Ken.C...@Golux.Com>
Subject [PATCH] to fix deficiency in mod_rewrite
Date Fri, 27 Apr 2001 20:49:57 GMT
Okey, here is a patch that seems to address this issue.  It
does two things:

1. Adds the slosh as an escape character; it can be used to turn
   '$1' from 'first backreference' into simply 'dollar-sign 1' with
   '\$1'.  Any character can be escaped, but it really only has
   significance for those with special meanings to mod_rewrite
   (namely '$' and '%').

2. Adds the 'noescape|NE' flag to prevent the application of
   ap_escape_uri() to transformed strings.

With the two used together, result strings can be coded to
include URI escape sequences such as '%24%24'.  Without this
change, that cannot be done; mod_rewrite will *always* treat
'%' as a variable marker, '$' as a backreference marker, and
escape '%' into '%25'.  So '%24%24' will currently *always*
be turned into '%2524%2524'.

mod_rewrite is such a beast that I am proposing this rather than
just committing it; I easily may have missed something.  If/when
it gets committed I will bring it forward to 2.0.

Index: src/CHANGES
===================================================================
RCS file: /home/cvs/apache-1.3/src/CHANGES,v
retrieving revision 1.1675
diff -u -r1.1675 CHANGES
--- src/CHANGES 2001/04/12 17:54:58     1.1675
+++ src/CHANGES 2001/04/27 20:35:33
@@ -1,5 +1,13 @@
 Changes with Apache 1.3.20
 
+  *) Added NOESCAPE (NS) flag to RewriteRule and enabled use of
+     '\' to allow escaping of special characters.  Previously
+     there was no way to embed either '$' or '%' in the output
+     of a RewriteRule; now 'foo\$1' will result in a literal
+     'foo$1' appearing in the result rather than 'foo\<value of $1>'.
+     Note that [NS] disables *all* normal URI escaping, so incautious
+     use can give unexpected results.  [Ken Coar]
+
   *) Changed the initial screen handling for NetWare so that the -s 
      parameter will properly destroy the Apache console screen and switch 
      to the system console screen.  Also removed the call to clrscr() for 
@@ -10,8 +18,8 @@
      for Win32 systems, see http://www.cygwin.com)
      [Stipe Tolj <tolj@wapme-systems.de>]
 
-  *) Changes to 'ab'; fixed int overrun's, added statistics, output in
-     csv/gnuplot format, rudimentary ssl support and various other tweaks
+  *) Changes to 'ab': fixed int overruns, added statistics, output in
+     csv/gnuplot format, rudimentary SSL support and various other tweaks
      to make results more true to what is measured. The upshot of this it
      turns out that 'ab' has often underreported the true performance of
      apache. Often by a order of magnitude :-) See talk/paper of Sander 
Index: src/modules/standard/mod_rewrite.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/modules/standard/mod_rewrite.c,v
retrieving revision 1.170
diff -u -r1.170 mod_rewrite.c
--- src/modules/standard/mod_rewrite.c  2001/02/01 04:12:26     1.170
+++ src/modules/standard/mod_rewrite.c  2001/04/27 20:35:34
@@ -866,6 +866,10 @@
             cfg->forced_responsecode = status;
         }
     }
+    else if (   strcasecmp(key, "noescape") == 0
+        || strcasecmp(key, "NE") == 0       ) {
+        cfg->flags |= RULEFLAG_NOESCAPE;
+    }
     else if (   strcasecmp(key, "last") == 0
              || strcasecmp(key, "L") == 0   ) {
         cfg->flags |= RULEFLAG_LASTRULE;
@@ -1010,6 +1014,7 @@
     const char *ccp;
     struct stat finfo;
     unsigned int port;
+    int rulestatus;
     int n;
     int l;
 
@@ -1093,7 +1098,8 @@
     /*
      *  now apply the rules ...
      */
-    if (apply_rewrite_list(r, conf->rewriterules, NULL)) {
+    rulestatus = apply_rewrite_list(r, conf->rewriterules, NULL);
+    if (rulestatus) {
 
         if (strlen(r->filename) > 6 &&
             strncmp(r->filename, "proxy:", 6) == 0) {
@@ -1143,16 +1149,28 @@
             for ( ; *cp != '/' && *cp != '\0'; cp++)
                 ;
             if (*cp != '\0') {
-                rewritelog(r, 1, "escaping %s for redirect", r->filename);
-                cp2 = ap_escape_uri(r->pool, cp);
+                if (rulestatus != ACTION_NOESCAPE) {
+                    rewritelog(r, 1, "escaping %s for redirect", r->filename);
+                    cp2 = ap_escape_uri(r->pool, cp);
+                }
+                else {
+                    cp2 = ap_pstrdup(r->pool, cp);
+                }
                 *cp = '\0';
                 r->filename = ap_pstrcat(r->pool, r->filename, cp2, NULL);
             }
 
             /* append the QUERY_STRING part */
             if (r->args != NULL) {
+                char *args;
+                if (rulestatus == ACTION_NOESCAPE) {
+                    args = r->args;
+                }
+                else {
+                    args = ap_escape_uri(r->pool, r->args);
+                }
                 r->filename = ap_pstrcat(r->pool, r->filename, "?", 
-                                         ap_escape_uri(r->pool, r->args), NULL);
+                                         args, NULL);
             }
 
             /* determine HTTP redirect response code */
@@ -1305,6 +1323,7 @@
     const char *ccp;
     char *prefix;
     int l;
+    int rulestatus;
     int n;
     char *ofilename;
 
@@ -1358,7 +1377,8 @@
     /*
      *  now apply the rules ...
      */
-    if (apply_rewrite_list(r, dconf->rewriterules, dconf->directory)) {
+    rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory);
+    if (rulestatus) {
 
         if (strlen(r->filename) > 6 &&
             strncmp(r->filename, "proxy:", 6) == 0) {
@@ -1422,17 +1442,29 @@
             for ( ; *cp != '/' && *cp != '\0'; cp++)
                 ;
             if (*cp != '\0') {
-                rewritelog(r, 1, "[per-dir %s] escaping %s for redirect",
-                           dconf->directory, r->filename);
-                cp2 = ap_escape_uri(r->pool, cp);
+                if (rulestatus != ACTION_NOESCAPE) {
+                    rewritelog(r, 1, "[per-dir %s] escaping %s for redirect",
+                               dconf->directory, r->filename);
+                    cp2 = ap_escape_uri(r->pool, cp);
+                }
+                else {
+                    cp2 = ap_pstrdup(r->pool, cp);
+                }
                 *cp = '\0';
                 r->filename = ap_pstrcat(r->pool, r->filename, cp2, NULL);
             }
 
             /* append the QUERY_STRING part */
             if (r->args != NULL) {
+                char *args;
+                if (rulestatus == ACTION_NOESCAPE) {
+                    args = r->args;
+                }
+                else {
+                    args = ap_escape_uri(r->pool, r->args);
+                }
                 r->filename = ap_pstrcat(r->pool, r->filename, "?", 
-                                         ap_escape_uri(r->pool, r->args), NULL);
+                                         args, NULL);
             }
 
             /* determine HTTP redirect response code */
@@ -1622,7 +1654,8 @@
              *  Indicate a change if this was not a match-only rule.
              */
             if (rc != 2) {
-                changed = 1;
+                changed = ((p->flags & RULEFLAG_NOESCAPE)
+                           ? ACTION_NOESCAPE : ACTION_NORMAL);
             }
 
             /*
@@ -1636,7 +1669,7 @@
                            "to next API URI-to-filename handler", r->filename);
                 r->filename = ap_pstrcat(r->pool, "passthrough:",
                                          r->filename, NULL);
-                changed = 1;
+                changed = ACTION_NORMAL;
                 break;
             }
 
@@ -1648,7 +1681,7 @@
                 rewritelog(r, 2, "forcing '%s' to be forbidden", r->filename);
                 r->filename = ap_pstrcat(r->pool, "forbidden:",
                                          r->filename, NULL);
-                changed = 1;
+                changed = ACTION_NORMAL;
                 break;
             }
 
@@ -1659,7 +1692,7 @@
             if (p->flags & RULEFLAG_GONE) {
                 rewritelog(r, 2, "forcing '%s' to be gone", r->filename);
                 r->filename = ap_pstrcat(r->pool, "gone:", r->filename, NULL);
-                changed = 1;
+                changed = ACTION_NORMAL;
                 break;
             }
 
@@ -2245,7 +2278,7 @@
     space = nbuf - 1; /* room for '\0' */
 
     for (;;) {
-       span = strcspn(inp, "$%");
+       span = strcspn(inp, "\\$%");
        if (span > space) {
            span = space;
        }
@@ -2256,8 +2289,14 @@
        if (space == 0 || *inp == '\0') {
            break;
        }
-       /* now we have a '$' or a '%' */
-       if (inp[1] == '{') {
+       /* now we have a '\', '$', or '%' */
+        if (inp[0] == '\\') {
+            if (inp[1] != '\0') {
+                inp++;
+                goto skip;
+            }
+        }
+       else if (inp[1] == '{') {
            char *endp;
            endp = find_closing_bracket(inp+2, '{', '}');
            if (endp == NULL) {
@@ -2288,14 +2327,16 @@
                char xkey[MAX_STRING_LEN];
                char xdflt[MAX_STRING_LEN];
                key = find_char_in_brackets(inp+2, ':', '{', '}');
-               if (key == NULL)
+               if (key == NULL) {
                    goto skip;
+                }
                map  = ap_pstrndup(r->pool, inp+2, key-inp-2);
                dflt = find_char_in_brackets(key+1, '|', '{', '}');
                if (dflt == NULL) {
                    key  = ap_pstrndup(r->pool, key+1, endp-key-1);
                    dflt = "";
-               } else {
+               }
+                else {
                    key  = ap_pstrndup(r->pool, key+1, dflt-key-1);
                    dflt = ap_pstrndup(r->pool, dflt+1, endp-dflt-1);
                }
Index: src/modules/standard/mod_rewrite.h
===================================================================
RCS file: /home/cvs/apache-1.3/src/modules/standard/mod_rewrite.h,v
retrieving revision 1.79
diff -u -r1.79 mod_rewrite.h
--- src/modules/standard/mod_rewrite.h  2001/03/21 03:09:45     1.79
+++ src/modules/standard/mod_rewrite.h  2001/04/27 20:35:34
@@ -209,6 +209,10 @@
 #define RULEFLAG_GONE               1<<10
 #define RULEFLAG_QSAPPEND           1<<11
 #define RULEFLAG_NOCASE             1<<12
+#define RULEFLAG_NOESCAPE           1<<13
+
+#define ACTION_NORMAL               1<<0
+#define ACTION_NOESCAPE             1<<1
 
 #define MAPTYPE_TXT                 1<<0
 #define MAPTYPE_DBM                 1<<1



-- 
#ken    P-)}

Ken Coar                    <http://Golux.Com/coar/>
Apache Software Foundation  <http://www.apache.org/>
"Apache Server for Dummies" <http://Apache-Server.Com/>
"Apache Server Unleashed"   <http://ApacheUnleashed.Com/>

Mime
View raw message