summaryrefslogtreecommitdiffstats
path: root/modules/mappers
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mappers')
-rw-r--r--modules/mappers/config9.m45
-rw-r--r--modules/mappers/mod_alias.c131
-rw-r--r--modules/mappers/mod_rewrite.c117
-rw-r--r--modules/mappers/mod_rewrite.mak4
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) @<<