--- httpd-2.2.4/modules/mappers/mod_rewrite.c.orig 2006-09-15 08:19:00.000000000 +0200 +++ httpd-2.2.4/modules/mappers/mod_rewrite.c.orig 2007-05-18 19:25:27.437500000 +0200 @@ -145,6 +145,7 @@ #define RULEFLAG_NOESCAPE 1<<11 #define RULEFLAG_NOSUB 1<<12 #define RULEFLAG_STATUS 1<<13 +#define RULEFLAG_ESCAPEBACKREF 1<<14 /* return code of the rewrite rule * the result may be escaped - or not @@ -376,6 +377,7 @@ /* 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); /* * +-------------------------------------------------------+ @@ -624,6 +626,46 @@ return 0; } +static const char c2x_table[] = "0123456789abcdef"; + +static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix, + unsigned char *where) +{ +#if APR_CHARSET_EBCDIC + what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what); +#endif /*APR_CHARSET_EBCDIC*/ + *where++ = prefix; + *where++ = c2x_table[what >> 4]; + *where++ = c2x_table[what & 0xf]; + return where; +} + +/* + * Escapes a uri 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) { + 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++ = '+'; + } + else { + d = c2x(c, '%', d); + } + ++s; + } + *d = '\0'; + return copy; +} + /* * escape absolute uri, which may or may not be path oriented. * So let's handle them differently. @@ -2083,7 +2125,7 @@ * are interpreted by a later expansion, producing results that * were not intended by the administrator. */ -static char *do_expand(char *input, rewrite_ctx *ctx) +static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) { result_list *result, *current; result_list sresult[SMALL_EXPANSION]; @@ -2195,10 +2237,10 @@ } /* reuse of key variable as result */ - key = lookup_map(ctx->r, map, do_expand(key, ctx)); + key = lookup_map(ctx->r, map, do_expand(key, ctx, entry)); if (!key && dflt && *dflt) { - key = do_expand(dflt, ctx); + key = do_expand(dflt, ctx, entry); } if (key) { @@ -2222,9 +2264,23 @@ if (bri->source && n < AP_MAX_REG_MATCH && bri->regmatch[n].rm_eo > bri->regmatch[n].rm_so) { span = bri->regmatch[n].rm_eo - bri->regmatch[n].rm_so; - - current->len = span; - current->string = bri->source + bri->regmatch[n].rm_so; + if (entry && (entry->flags & RULEFLAG_ESCAPEBACKREF)) { + /* escape the backreference */ + char *tmp2, *tmp; + tmp = apr_palloc(pool, span + 1); + strncpy(tmp, bri->source + bri->regmatch[n].rm_so, span); + tmp[span] = '\0'; + tmp2 = escape_uri(pool, tmp); + rewritelog((ctx->r, 5, ctx->perdir, "escaping backreference '%s' to '%s'", + tmp, tmp2)); + + current->len = span = strlen(tmp2); + current->string = tmp2; + } else { + current->len = span; + current->string = bri->source + bri->regmatch[n].rm_so; + } + outlen += span; } @@ -2284,7 +2340,7 @@ char *name, *val; while (env) { - name = do_expand(env->data, ctx); + name = do_expand(env->data, ctx, NULL); if ((val = ap_strchr(name, ':')) != NULL) { *val++ = '\0'; @@ -2373,7 +2429,7 @@ static void do_expand_cookie(data_item *cookie, rewrite_ctx *ctx) { while (cookie) { - add_cookie(ctx->r, do_expand(cookie->data, ctx)); + add_cookie(ctx->r, do_expand(cookie->data, ctx, NULL)); cookie = cookie->next; } @@ -3153,6 +3209,15 @@ int error = 0; switch (*key++) { + case 'b': + case 'B': + if (!*key || !strcasecmp(key, "ackrefescaping")) { + cfg->flags |= RULEFLAG_ESCAPEBACKREF; + } + else { + ++error; + } + break; case 'c': case 'C': if (!*key || !strcasecmp(key, "hain")) { /* chain */ @@ -3354,7 +3419,6 @@ ++error; } break; - default: ++error; break; @@ -3490,7 +3554,7 @@ */ static int apply_rewrite_cond(rewritecond_entry *p, rewrite_ctx *ctx) { - char *input = do_expand(p->input, ctx); + char *input = do_expand(p->input, ctx, NULL); apr_finfo_t sb; request_rec *rsub, *r = ctx->r; ap_regmatch_t regmatch[AP_MAX_REG_MATCH]; @@ -3613,7 +3677,7 @@ char *expanded; if (p->forced_mimetype) { - expanded = do_expand(p->forced_mimetype, ctx); + expanded = do_expand(p->forced_mimetype, ctx, p); if (*expanded) { ap_str_tolower(expanded); @@ -3627,7 +3691,7 @@ } if (p->forced_handler) { - expanded = do_expand(p->forced_handler, ctx); + expanded = do_expand(p->forced_handler, ctx, p); if (*expanded) { ap_str_tolower(expanded); @@ -3759,7 +3823,7 @@ /* expand the result */ if (!(p->flags & RULEFLAG_NOSUB)) { - newuri = do_expand(p->output, ctx); + newuri = do_expand(p->output, ctx, p); rewritelog((r, 2, ctx->perdir, "rewrite '%s' -> '%s'", ctx->uri, newuri)); }