diff options
author | Jim Jagielski <jim@apache.org> | 2017-05-30 12:19:58 +0000 |
---|---|---|
committer | Jim Jagielski <jim@apache.org> | 2017-05-30 12:19:58 +0000 |
commit | 1b4533436a3fa72058b1ec6a03dc67d3b0376ca3 (patch) | |
tree | 48565d336e6efb32acdc6d8334a97b707e0750ee /modules/mappers | |
parent | 5979f0ada48e1c3187c937de87b652356050c40c (diff) | |
download | httpd-1b4533436a3fa72058b1ec6a03dc67d3b0376ca3.tar.gz |
Merge r1584417, r1585157 from trunk:
allow users to workaround the over-agressive backreference
escaping by selecting the characters to escape.
add BNP flag to give control to the user on whether a space ' ' in
an escaped backrefernece is decoded to a + (default) or %20. Useful
if your backreference isn't going into the query string.
Submitted by: covener
Reviewed by: jailletc36, covener, ylavic
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1796850 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/mappers')
-rw-r--r-- | modules/mappers/mod_rewrite.c | 50 |
1 files changed, 39 insertions, 11 deletions
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index dcf7988ed0..d54ad8f4a8 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -166,6 +166,7 @@ static const char* really_last_key = "rewrite_really_last"; #define RULEFLAG_DISCARDPATHINFO (1<<15) #define RULEFLAG_QSDISCARD (1<<16) #define RULEFLAG_END (1<<17) +#define RULEFLAG_ESCAPENOPLUS (1<<18) #define RULEFLAG_QSLAST (1<<19) /* return code of the rewrite rule @@ -317,6 +318,7 @@ typedef struct { data_item *cookie; /* added cookies */ int skip; /* number of next rules to skip */ int maxrounds; /* limit on number of loops with N flag */ + char *escapes; /* specific backref escapes */ } rewriterule_entry; typedef struct { @@ -417,7 +419,7 @@ static const char *rewritemap_mutex_type = "rewrite-map"; /* Optional functions imported from mod_ssl when loaded: */ static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *rewrite_ssl_lookup = NULL; static APR_OPTIONAL_FN_TYPE(ssl_is_https) *rewrite_is_https = NULL; -static char *escape_uri(apr_pool_t *p, const char *path); +static char *escape_backref(apr_pool_t *p, const char *path, const char *escapeme, int noplus); /* * +-------------------------------------------------------+ @@ -634,24 +636,44 @@ static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix, } /* - * Escapes a uri in a similar way as php's urlencode does. + * 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_uri(apr_pool_t *p, const char *path) { +static char *escape_backref(apr_pool_t *p, const char *path, const char *escapeme, int noplus) { 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; while ((c = *s)) { - if (apr_isalnum(c) || c == '_') { - *d++ = c; - } - else if (c == ' ') { - *d++ = '+'; + if (!escapeme) { + if (apr_isalnum(c) || c == '_') { + *d++ = c; + } + else if (c == ' ' && !noplus) { + *d++ = '+'; + } + else { + d = c2x(c, '%', d); + } } - 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; + } } ++s; } @@ -2390,7 +2412,7 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) /* escape the backreference */ char *tmp2, *tmp; tmp = apr_pstrmemdup(pool, bri->source + bri->regmatch[n].rm_so, span); - tmp2 = escape_uri(pool, tmp); + tmp2 = escape_backref(pool, tmp, entry->escapes, entry->flags & RULEFLAG_ESCAPENOPLUS); rewritelog((ctx->r, 5, ctx->perdir, "escaping backreference '%s' to '%s'", tmp, tmp2)); @@ -3446,6 +3468,12 @@ static const char *cmd_rewriterule_setflag(apr_pool_t *p, void *_cfg, case 'B': if (!*key || !strcasecmp(key, "ackrefescaping")) { cfg->flags |= RULEFLAG_ESCAPEBACKREF; + if (val && *val) { + cfg->escapes = val; + } + } + else if (!strcasecmp(key, "NP") || !strcasecmp(key, "ackrefernoplus")) { + cfg->flags |= RULEFLAG_ESCAPENOPLUS; } else { ++error; |