applying the transformation. <em><a
href="../rewrite/flags.html#flag_b">details ...</a></em></td>
</tr>
+ <tr>
+ <td>backrefnoplus|BNP</td>
+ <td>If backreferences are being escaped, spaces should be escaped to
+ %20 instead of +. Useful when the backreference will be used in the
+ path component rather than the query string.<em><a
+ href="../rewrite/flags.html#flag_bnp">details ...</a></em></td>
+ </tr>
+
<tr>
<td>chain|C</td>
<td>Rule is chained to the following rule. If the rule fails,
<p>In 2.4.10 and later, you can limit the escaping to specific characters
in backreferences by listing them: <code>[B=#?;]</code> </p>
+<section id="flag_bnp"><title>BNP|backrefnoplus (don't escape space to +)</title>
+<p>The [BNP] flag instructs <directive
+module="mod_rewrite">RewriteRule</directive> to escape the space character
+in a backreference to %20 rather than '+'. Useful when the backreference
+will be used in the path component rather than the query string.
+
<p><code>mod_rewrite</code> has to unescape URLs before mapping them,
so backreferences are unescaped at the time they are applied.
Using the B flag, non-alphanumeric characters in backreferences
#define RULEFLAG_DISCARDPATHINFO 1<<15
#define RULEFLAG_QSDISCARD 1<<16
#define RULEFLAG_END 1<<17
+#define RULEFLAG_ESCAPENOPLUS 1<<18
/* return code of the rewrite rule
* the result may be escaped - or not
/* 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, const char *escapeme);
+static char *escape_backref(apr_pool_t *p, const char *path, const char *escapeme, int noplus);
/*
* +-------------------------------------------------------+
}
/*
- * 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, const char *escapeme) {
+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;
if (apr_isalnum(c) || c == '_') {
*d++ = c;
}
- else if (c == ' ') {
+ else if (c == ' ' && !noplus) {
*d++ = '+';
}
else {
const char *esc = escapeme;
while (*esc) {
if (c == *esc) {
- d = c2x(c, '%', d);
+ if (c == ' ' && !noplus) {
+ *d++ = '+';
+ }
+ else {
+ d = c2x(c, '%', d);
+ }
break;
}
++esc;
/* escape the backreference */
char *tmp2, *tmp;
tmp = apr_pstrmemdup(pool, bri->source + bri->regmatch[n].rm_so, span);
- tmp2 = escape_uri(pool, tmp, entry->escapes);
+ tmp2 = escape_backref(pool, tmp, entry->escapes, entry->flags & RULEFLAG_ESCAPENOPLUS);
rewritelog((ctx->r, 5, ctx->perdir, "escaping backreference '%s' to '%s'",
tmp, tmp2));
cfg->escapes = val;
}
}
+ else if (!strcasecmp(key, "NP") || !strcasecmp(key, "ackrefernoplus")) {
+ cfg->flags |= RULEFLAG_ESCAPENOPLUS;
+ }
else {
++error;
}