diff options
Diffstat (limited to 'modules/mappers')
-rw-r--r-- | modules/mappers/config9.m4 | 5 | ||||
-rw-r--r-- | modules/mappers/mod_alias.c | 131 | ||||
-rw-r--r-- | modules/mappers/mod_rewrite.c | 117 | ||||
-rw-r--r-- | modules/mappers/mod_rewrite.mak | 4 |
4 files changed, 167 insertions, 90 deletions
diff --git a/modules/mappers/config9.m4 b/modules/mappers/config9.m4 index 55a97ab..7120b72 100644 --- a/modules/mappers/config9.m4 +++ b/modules/mappers/config9.m4 @@ -14,6 +14,11 @@ APACHE_MODULE(userdir, mapping of requests to user-specific directories, , , mos APACHE_MODULE(alias, mapping of requests to different filesystem parts, , , yes) APACHE_MODULE(rewrite, rule based URL manipulation, , , most) +if test "x$enable_rewrite" != "xno"; then + # mod_rewrite needs test_char.h + APR_ADDTO(INCLUDES, [-I\$(top_builddir)/server]) +fi + APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current]) APACHE_MODPATH_FINISH diff --git a/modules/mappers/mod_alias.c b/modules/mappers/mod_alias.c index 5ff937b..35eca74 100644 --- a/modules/mappers/mod_alias.c +++ b/modules/mappers/mod_alias.c @@ -37,6 +37,12 @@ #include "ap_expr.h" +#define ALIAS_FLAG_DEFAULT -1 +#define ALIAS_FLAG_OFF 0 +#define ALIAS_FLAG_ON 1 + +#define ALIAS_PRESERVE_PATH_DEFAULT 0 + typedef struct { const char *real; const char *fake; @@ -55,9 +61,12 @@ typedef struct { unsigned int redirect_set:1; apr_array_header_t *redirects; const ap_expr_info_t *alias; + const char *alias_fake; char *handler; const ap_expr_info_t *redirect; int redirect_status; /* 301, 302, 303, 410, etc */ + int allow_relative; /* skip ap_construct_url() */ + int alias_preserve_path; /* map full path */ } alias_dir_conf; module AP_MODULE_DECLARE_DATA alias_module; @@ -80,6 +89,8 @@ static void *create_alias_dir_config(apr_pool_t *p, char *d) alias_dir_conf *a = (alias_dir_conf *) apr_pcalloc(p, sizeof(alias_dir_conf)); a->redirects = apr_array_make(p, 2, sizeof(alias_entry)); + a->allow_relative = ALIAS_FLAG_DEFAULT; + a->alias_preserve_path = ALIAS_FLAG_DEFAULT; return a; } @@ -105,12 +116,19 @@ static void *merge_alias_dir_config(apr_pool_t *p, void *basev, void *overridesv a->redirects = apr_array_append(p, overrides->redirects, base->redirects); a->alias = (overrides->alias_set == 0) ? base->alias : overrides->alias; + a->alias_fake = (overrides->alias_set == 0) ? base->alias_fake : overrides->alias_fake; a->handler = (overrides->alias_set == 0) ? base->handler : overrides->handler; a->alias_set = overrides->alias_set || base->alias_set; a->redirect = (overrides->redirect_set == 0) ? base->redirect : overrides->redirect; a->redirect_status = (overrides->redirect_set == 0) ? base->redirect_status : overrides->redirect_status; a->redirect_set = overrides->redirect_set || base->redirect_set; + a->allow_relative = (overrides->allow_relative != ALIAS_FLAG_DEFAULT) + ? overrides->allow_relative + : base->allow_relative; + a->alias_preserve_path = (overrides->alias_preserve_path != ALIAS_FLAG_DEFAULT) + ? overrides->alias_preserve_path + : base->alias_preserve_path; return a; } @@ -210,6 +228,7 @@ static const char *add_alias(cmd_parms *cmd, void *dummy, const char *fake, NULL); } + dirconf->alias_fake = cmd->path; dirconf->handler = cmd->info; dirconf->alias_set = 1; @@ -428,6 +447,17 @@ static char *try_alias(request_rec *r) return PREGSUB_ERROR; } + if (dirconf->alias_fake && dirconf->alias_preserve_path == ALIAS_FLAG_ON) { + int l; + + l = alias_matches(r->uri, dirconf->alias_fake); + + if (l > 0) { + ap_set_context_info(r, dirconf->alias_fake, found); + found = apr_pstrcat(r->pool, found, r->uri + l, NULL); + } + } + if (dirconf->handler) { /* Set handler, and leave a note for mod_cgi */ r->handler = dirconf->handler; apr_table_setn(r->notes, "alias-forced-type", r->handler); @@ -591,31 +621,33 @@ static int translate_alias_redir(request_rec *r) if (ret == PREGSUB_ERROR) return HTTP_INTERNAL_SERVER_ERROR; if (ap_is_HTTP_REDIRECT(status)) { - if (ret[0] == '/') { - char *orig_target = ret; - - ret = ap_construct_url(r->pool, ret, r); - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00673) - "incomplete redirection target of '%s' for " - "URI '%s' modified to '%s'", - orig_target, r->uri, ret); - } - if (!ap_is_url(ret)) { - status = HTTP_INTERNAL_SERVER_ERROR; - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00674) - "cannot redirect '%s' to '%s'; " - "target is not a valid absoluteURI or abs_path", - r->uri, ret); - } - else { - /* append requested query only, if the config didn't - * supply its own. - */ - if (r->args && !ap_strchr(ret, '?')) { - ret = apr_pstrcat(r->pool, ret, "?", r->args, NULL); + alias_dir_conf *dirconf = (alias_dir_conf *) + ap_get_module_config(r->per_dir_config, &alias_module); + if (dirconf->allow_relative != ALIAS_FLAG_ON || ret[0] != '/') { + if (ret[0] == '/') { + char *orig_target = ret; + + ret = ap_construct_url(r->pool, ret, r); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00673) + "incomplete redirection target of '%s' for " + "URI '%s' modified to '%s'", + orig_target, r->uri, ret); } - apr_table_setn(r->headers_out, "Location", ret); + if (!ap_is_url(ret)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00674) + "cannot redirect '%s' to '%s'; " + "target is not a valid absoluteURI or abs_path", + r->uri, ret); + return HTTP_INTERNAL_SERVER_ERROR; + } + } + /* append requested query only, if the config didn't + * supply its own. + */ + if (r->args && !ap_strchr(ret, '?')) { + ret = apr_pstrcat(r->pool, ret, "?", r->args, NULL); } + apr_table_setn(r->headers_out, "Location", ret); } return status; } @@ -646,31 +678,31 @@ static int fixup_redir(request_rec *r) if (ret == PREGSUB_ERROR) return HTTP_INTERNAL_SERVER_ERROR; if (ap_is_HTTP_REDIRECT(status)) { - if (ret[0] == '/') { - char *orig_target = ret; - - ret = ap_construct_url(r->pool, ret, r); - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00675) - "incomplete redirection target of '%s' for " - "URI '%s' modified to '%s'", - orig_target, r->uri, ret); - } - if (!ap_is_url(ret)) { - status = HTTP_INTERNAL_SERVER_ERROR; - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00676) - "cannot redirect '%s' to '%s'; " - "target is not a valid absoluteURI or abs_path", - r->uri, ret); - } - else { - /* append requested query only, if the config didn't - * supply its own. - */ - if (r->args && !ap_strchr(ret, '?')) { - ret = apr_pstrcat(r->pool, ret, "?", r->args, NULL); + if (dirconf->allow_relative != ALIAS_FLAG_ON || ret[0] != '/') { + if (ret[0] == '/') { + char *orig_target = ret; + + ret = ap_construct_url(r->pool, ret, r); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00675) + "incomplete redirection target of '%s' for " + "URI '%s' modified to '%s'", + orig_target, r->uri, ret); } - apr_table_setn(r->headers_out, "Location", ret); + if (!ap_is_url(ret)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00676) + "cannot redirect '%s' to '%s'; " + "target is not a valid absoluteURI or abs_path", + r->uri, ret); + return HTTP_INTERNAL_SERVER_ERROR; + } + } + /* append requested query only, if the config didn't + * supply its own. + */ + if (r->args && !ap_strchr(ret, '?')) { + ret = apr_pstrcat(r->pool, ret, "?", r->args, NULL); } + apr_table_setn(r->headers_out, "Location", ret); } return status; } @@ -702,6 +734,13 @@ static const command_rec alias_cmds[] = AP_INIT_TAKE2("RedirectPermanent", add_redirect2, (void *) HTTP_MOVED_PERMANENTLY, OR_FILEINFO, "a document to be redirected, then the destination URL"), + AP_INIT_FLAG("RedirectRelative", ap_set_flag_slot, + (void*)APR_OFFSETOF(alias_dir_conf, allow_relative), OR_FILEINFO, + "Set to ON to allow relative redirect targets to be issued as-is"), + AP_INIT_FLAG("AliasPreservePath", ap_set_flag_slot, + (void*)APR_OFFSETOF(alias_dir_conf, alias_preserve_path), OR_FILEINFO, + "Set to ON to map the full path after the fakename to the realname."), + {NULL} }; diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index 5195cee..bbcc11b 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -106,6 +106,8 @@ #include "mod_rewrite.h" #include "ap_expr.h" +#include "test_char.h" + static ap_dbd_t *(*dbd_acquire)(request_rec*) = NULL; static void (*dbd_prepare)(server_rec*, const char*, const char*) = NULL; static const char* really_last_key = "rewrite_really_last"; @@ -174,6 +176,7 @@ static const char* really_last_key = "rewrite_really_last"; #define RULEFLAG_ESCAPENOPLUS (1<<18) #define RULEFLAG_QSLAST (1<<19) #define RULEFLAG_QSNONE (1<<20) /* programattic only */ +#define RULEFLAG_ESCAPECTLS (1<<21) /* return code of the rewrite rule * the result may be escaped - or not @@ -327,7 +330,8 @@ 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 */ + const char *escapes; /* specific backref escapes */ + const char *noescapes; /* specific backref chars not to escape */ } rewriterule_entry; typedef struct { @@ -427,7 +431,9 @@ static apr_global_mutex_t *rewrite_mapr_lock_acquire = NULL; static const char *rewritemap_mutex_type = "rewrite-map"; /* Optional functions imported from mod_ssl when loaded: */ -static char *escape_backref(apr_pool_t *p, const char *path, const char *escapeme, int noplus); +static char *escape_backref(apr_pool_t *p, const char *path, + const char *escapeme, const char *noescapeme, + int flags); /* * +-------------------------------------------------------+ @@ -654,14 +660,21 @@ static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix, * 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_backref(apr_pool_t *p, const char *path, const char *escapeme, int noplus) { - char *copy = apr_palloc(p, 3 * strlen(path) + 3); +static char *escape_backref(apr_pool_t *p, const char *path, + const char *escapeme, const char *noescapeme, + int flags) +{ + char *copy = apr_palloc(p, 3 * strlen(path) + 1); const unsigned char *s = (const unsigned char *)path; unsigned char *d = (unsigned char *)copy; - unsigned c; + int noplus = (flags & RULEFLAG_ESCAPENOPLUS) != 0; + int ctls = (flags & RULEFLAG_ESCAPECTLS) != 0; + unsigned char c; while ((c = *s)) { - if (!escapeme) { + if (((ctls ? !TEST_CHAR(c, T_VCHAR_OBSTEXT) : !escapeme) + || (escapeme && ap_strchr_c(escapeme, c))) + && (!noescapeme || !ap_strchr_c(noescapeme, c))) { if (apr_isalnum(c) || c == '_') { *d++ = c; } @@ -672,23 +685,8 @@ static char *escape_backref(apr_pool_t *p, const char *path, const char *escapem 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; - } + else { + *d++ = c; } ++s; } @@ -2469,7 +2467,8 @@ 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_backref(pool, tmp, entry->escapes, entry->flags & RULEFLAG_ESCAPENOPLUS); + tmp2 = escape_backref(pool, tmp, entry->escapes, entry->noescapes, + entry->flags); rewritelog((ctx->r, 5, ctx->perdir, "escaping backreference '%s' to '%s'", tmp, tmp2)); @@ -3541,13 +3540,24 @@ 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) { + if (val && *val) { cfg->escapes = val; } } + else if (!strcasecmp(key, "NE")) { + if (val && *val) { + cfg->noescapes = val; + } + else { + return "flag 'BNE' wants a list of characters (i.e. [BNE=...])"; + } + } else if (!strcasecmp(key, "NP") || !strcasecmp(key, "ackrefernoplus")) { cfg->flags |= RULEFLAG_ESCAPENOPLUS; } + else if (!strcasecmp(key, "CTLS")) { + cfg->flags |= RULEFLAG_ESCAPECTLS|RULEFLAG_ESCAPEBACKREF; + } else { ++error; } @@ -3809,7 +3819,6 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf, "'", NULL); } - /* arg3: optional flags field */ newrule->forced_mimetype = NULL; newrule->forced_handler = NULL; newrule->forced_responsecode = HTTP_MOVED_TEMPORARILY; @@ -3818,6 +3827,9 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf, newrule->cookie = NULL; newrule->skip = 0; newrule->maxrounds = REWRITE_MAX_ROUNDS; + newrule->escapes = newrule->noescapes = NULL; + + /* arg3: optional flags field */ if (a3 != NULL) { if ((err = cmd_parseflagfield(cmd->pool, newrule, a3, cmd_rewriterule_setflag)) != NULL) { @@ -3853,7 +3865,16 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf, if (*(a2_end-1) == '?') { /* a literal ? at the end of the unsubstituted rewrite rule */ - newrule->flags |= RULEFLAG_QSNONE; + if (newrule->flags & RULEFLAG_QSAPPEND) { + /* with QSA, splitout_queryargs will safely handle it if RULEFLAG_QSLAST is set */ + newrule->flags |= RULEFLAG_QSLAST; + } + else { + /* avoid getting a query string via inadvertent capture */ + newrule->flags |= RULEFLAG_QSNONE; + /* trailing ? has done its job, but splitout_queryargs will not chop it off */ + *(a2_end-1) = '\0'; + } } else if (newrule->flags & RULEFLAG_QSDISCARD) { if (NULL == ap_strchr(newrule->output, '?')) { @@ -4745,13 +4766,19 @@ static int hook_uri2file(request_rec *r) } if (rulestatus) { - unsigned skip; - apr_size_t flen; - - if (r->args && *(ap_scan_vchar_obstext(r->args))) { + apr_size_t flen = r->filename ? strlen(r->filename) : 0; + unsigned skip_absolute = flen ? is_absolute_uri(r->filename, NULL) : 0; + int to_proxyreq = (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0); + int will_escape = skip_absolute && (rulestatus != ACTION_NOESCAPE); + + if (r->args + && !will_escape + && *(ap_scan_vchar_obstext(r->args))) { /* * We have a raw control character or a ' ' in r->args. * Correct encoding was missed. + * Correct encoding was missed and we're not going to escape + * it before returning. */ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10410) "Rewritten query string contains control " @@ -4766,8 +4793,7 @@ static int hook_uri2file(request_rec *r) return n; } - flen = r->filename ? strlen(r->filename) : 0; - if (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0) { + if (to_proxyreq) { /* it should be go on as an internal proxy request */ /* check if the proxy module is enabled, so @@ -4809,7 +4835,7 @@ static int hook_uri2file(request_rec *r) r->filename)); return OK; } - else if ((skip = is_absolute_uri(r->filename, NULL)) > 0) { + else if (skip_absolute > 0) { int n; /* it was finally rewritten to a remote URL */ @@ -4817,7 +4843,7 @@ static int hook_uri2file(request_rec *r) if (rulestatus != ACTION_NOESCAPE) { rewritelog((r, 1, NULL, "escaping %s for redirect", r->filename)); - r->filename = escape_absolute_uri(r->pool, r->filename, skip); + r->filename = escape_absolute_uri(r->pool, r->filename, skip_absolute); } /* append the QUERY_STRING part */ @@ -5041,9 +5067,17 @@ static int hook_fixup(request_rec *r) */ rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory); if (rulestatus) { - unsigned skip; + unsigned skip_absolute = is_absolute_uri(r->filename, NULL); + int to_proxyreq = 0; + int will_escape = 0; - if (r->args && *(ap_scan_vchar_obstext(r->args))) { + l = strlen(r->filename); + to_proxyreq = l > 6 && strncmp(r->filename, "proxy:", 6) == 0; + will_escape = skip_absolute && (rulestatus != ACTION_NOESCAPE); + + if (r->args + && !will_escape + && *(ap_scan_vchar_obstext(r->args))) { /* * We have a raw control character or a ' ' in r->args. * Correct encoding was missed. @@ -5061,8 +5095,7 @@ static int hook_fixup(request_rec *r) return n; } - l = strlen(r->filename); - if (l > 6 && strncmp(r->filename, "proxy:", 6) == 0) { + if (to_proxyreq) { /* it should go on as an internal proxy request */ /* make sure the QUERY_STRING and @@ -5086,7 +5119,7 @@ static int hook_fixup(request_rec *r) "%s [OK]", r->filename)); return OK; } - else if ((skip = is_absolute_uri(r->filename, NULL)) > 0) { + else if (skip_absolute > 0) { /* it was finally rewritten to a remote URL */ /* because we are in a per-dir context @@ -5095,7 +5128,7 @@ static int hook_fixup(request_rec *r) */ if (dconf->baseurl != NULL) { /* skip 'scheme://' */ - cp = r->filename + skip; + cp = r->filename + skip_absolute; if ((cp = ap_strchr(cp, '/')) != NULL && *(++cp)) { rewritelog((r, 2, dconf->directory, @@ -5140,7 +5173,7 @@ static int hook_fixup(request_rec *r) if (rulestatus != ACTION_NOESCAPE) { rewritelog((r, 1, dconf->directory, "escaping %s for redirect", r->filename)); - r->filename = escape_absolute_uri(r->pool, r->filename, skip); + r->filename = escape_absolute_uri(r->pool, r->filename, skip_absolute); } /* append the QUERY_STRING part */ diff --git a/modules/mappers/mod_rewrite.mak b/modules/mappers/mod_rewrite.mak index 3b08cab..860dd8b 100644 --- a/modules/mappers/mod_rewrite.mak +++ b/modules/mappers/mod_rewrite.mak @@ -62,7 +62,7 @@ CLEAN : if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../database" /I "../ssl" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_rewrite_src" /FD /c +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../database" /I "../ssl" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../server" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_rewrite_src" /FD /c .c{$(INTDIR)}.obj:: $(CPP) @<< @@ -166,7 +166,7 @@ CLEAN : if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../include" /I "../database" /I "../ssl" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_rewrite_src" /FD /EHsc /c +CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../include" /I "../database" /I "../ssl" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../server" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_rewrite_src" /FD /EHsc /c .c{$(INTDIR)}.obj:: $(CPP) @<< |