From: Ken Coar Date: Sun, 6 May 2001 22:00:02 +0000 (+0000) Subject: Add ability to escape characters in Rewrite* input strings using X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7b8634551133e991e5489c3e9ad036ba7b940f06;p=thirdparty%2Fapache%2Fhttpd.git Add ability to escape characters in Rewrite* input strings using '\' (e.g., "\$" to keep it from having its special meaning), and NoEscape/NE flag to disable filtering the rewritten output through URI encoding. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x@89040 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/CHANGES b/src/CHANGES index b2bc7abf1c2..ab160349bc9 100644 --- a/src/CHANGES +++ b/src/CHANGES @@ -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\'. + Note that [NS] disables *all* normal URI escaping, so incautious + use can give unexpected results. [Ken Coar] + *) Add support for Win32 apxs. Note that cygwin builders must use a cygwin perl to avoid the MSWin32 handling. [William Rowe] @@ -13,8 +21,8 @@ Changes with Apache 1.3.20 for Win32 systems, see http://www.cygwin.com) [Stipe Tolj ] - *) 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 diff --git a/src/modules/standard/mod_rewrite.c b/src/modules/standard/mod_rewrite.c index bc673c7c683..e40a28cd8b5 100644 --- a/src/modules/standard/mod_rewrite.c +++ b/src/modules/standard/mod_rewrite.c @@ -866,6 +866,10 @@ static const char *cmd_rewriterule_setflag(pool *p, rewriterule_entry *cfg, 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 @@ static int hook_uri2file(request_rec *r) const char *ccp; struct stat finfo; unsigned int port; + int rulestatus; int n; int l; @@ -1093,7 +1098,8 @@ static int hook_uri2file(request_rec *r) /* * 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 @@ static int hook_uri2file(request_rec *r) 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 @@ static int hook_fixup(request_rec *r) const char *ccp; char *prefix; int l; + int rulestatus; int n; char *ofilename; @@ -1358,7 +1377,8 @@ static int hook_fixup(request_rec *r) /* * 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 @@ static int hook_fixup(request_rec *r) 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 @@ static int apply_rewrite_list(request_rec *r, array_header *rewriterules, * 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 @@ static int apply_rewrite_list(request_rec *r, array_header *rewriterules, "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 @@ static int apply_rewrite_list(request_rec *r, array_header *rewriterules, 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 @@ static int apply_rewrite_list(request_rec *r, array_header *rewriterules, 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 @@ static void do_expand(request_rec *r, char *input, char *buffer, int nbuf, space = nbuf - 1; /* room for '\0' */ for (;;) { - span = strcspn(inp, "$%"); + span = strcspn(inp, "\\$%"); if (span > space) { span = space; } @@ -2256,8 +2289,14 @@ static void do_expand(request_rec *r, char *input, char *buffer, int nbuf, 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 @@ static void do_expand(request_rec *r, char *input, char *buffer, int nbuf, 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); } diff --git a/src/modules/standard/mod_rewrite.h b/src/modules/standard/mod_rewrite.h index f5804ff41d3..47c55dbdeb8 100644 --- a/src/modules/standard/mod_rewrite.h +++ b/src/modules/standard/mod_rewrite.h @@ -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