summaryrefslogtreecommitdiffstats
path: root/modules/mappers/mod_rewrite.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mappers/mod_rewrite.c')
-rw-r--r--modules/mappers/mod_rewrite.c288
1 files changed, 198 insertions, 90 deletions
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
index 68a33b6..bbcc11b 100644
--- a/modules/mappers/mod_rewrite.c
+++ b/modules/mappers/mod_rewrite.c
@@ -55,6 +55,12 @@
#include "apr_global_mutex.h"
#include "apr_dbm.h"
#include "apr_dbd.h"
+
+#include "apr_version.h"
+#if !APR_VERSION_AT_LEAST(2,0,0)
+#include "apu_version.h"
+#endif
+
#include "mod_dbd.h"
#if APR_HAS_THREADS
@@ -93,14 +99,15 @@
#include "http_core.h"
#include "http_log.h"
#include "http_protocol.h"
+#include "http_ssl.h"
#include "http_vhost.h"
#include "util_mutex.h"
-#include "mod_ssl.h"
-
#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";
@@ -168,6 +175,8 @@ static const char* really_last_key = "rewrite_really_last";
#define RULEFLAG_END (1<<17)
#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
@@ -321,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 {
@@ -421,9 +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 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_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);
/*
* +-------------------------------------------------------+
@@ -524,7 +534,7 @@ static unsigned is_absolute_uri(char *uri, int *supportsqs)
switch (*uri++) {
case 'a':
case 'A':
- if (!strncasecmp(uri, "jp://", 5)) { /* ajp:// */
+ if (!ap_cstr_casecmpn(uri, "jp://", 5)) { /* ajp:// */
*sqs = 1;
return 6;
}
@@ -532,7 +542,7 @@ static unsigned is_absolute_uri(char *uri, int *supportsqs)
case 'b':
case 'B':
- if (!strncasecmp(uri, "alancer://", 10)) { /* balancer:// */
+ if (!ap_cstr_casecmpn(uri, "alancer://", 10)) { /* balancer:// */
*sqs = 1;
return 11;
}
@@ -540,10 +550,10 @@ static unsigned is_absolute_uri(char *uri, int *supportsqs)
case 'f':
case 'F':
- if (!strncasecmp(uri, "tp://", 5)) { /* ftp:// */
+ if (!ap_cstr_casecmpn(uri, "tp://", 5)) { /* ftp:// */
return 6;
}
- if (!strncasecmp(uri, "cgi://", 6)) { /* fcgi:// */
+ if (!ap_cstr_casecmpn(uri, "cgi://", 6)) { /* fcgi:// */
*sqs = 1;
return 7;
}
@@ -551,26 +561,26 @@ static unsigned is_absolute_uri(char *uri, int *supportsqs)
case 'g':
case 'G':
- if (!strncasecmp(uri, "opher://", 8)) { /* gopher:// */
+ if (!ap_cstr_casecmpn(uri, "opher://", 8)) { /* gopher:// */
return 9;
}
break;
case 'h':
case 'H':
- if (!strncasecmp(uri, "ttp://", 6)) { /* http:// */
+ if (!ap_cstr_casecmpn(uri, "ttp://", 6)) { /* http:// */
*sqs = 1;
return 7;
}
- else if (!strncasecmp(uri, "ttps://", 7)) { /* https:// */
+ else if (!ap_cstr_casecmpn(uri, "ttps://", 7)) { /* https:// */
*sqs = 1;
return 8;
}
- else if (!strncasecmp(uri, "2://", 4)) { /* h2:// */
+ else if (!ap_cstr_casecmpn(uri, "2://", 4)) { /* h2:// */
*sqs = 1;
return 5;
}
- else if (!strncasecmp(uri, "2c://", 5)) { /* h2c:// */
+ else if (!ap_cstr_casecmpn(uri, "2c://", 5)) { /* h2c:// */
*sqs = 1;
return 6;
}
@@ -578,14 +588,14 @@ static unsigned is_absolute_uri(char *uri, int *supportsqs)
case 'l':
case 'L':
- if (!strncasecmp(uri, "dap://", 6)) { /* ldap:// */
+ if (!ap_cstr_casecmpn(uri, "dap://", 6)) { /* ldap:// */
return 7;
}
break;
case 'm':
case 'M':
- if (!strncasecmp(uri, "ailto:", 6)) { /* mailto: */
+ if (!ap_cstr_casecmpn(uri, "ailto:", 6)) { /* mailto: */
*sqs = 1;
return 7;
}
@@ -593,17 +603,17 @@ static unsigned is_absolute_uri(char *uri, int *supportsqs)
case 'n':
case 'N':
- if (!strncasecmp(uri, "ews:", 4)) { /* news: */
+ if (!ap_cstr_casecmpn(uri, "ews:", 4)) { /* news: */
return 5;
}
- else if (!strncasecmp(uri, "ntp://", 6)) { /* nntp:// */
+ else if (!ap_cstr_casecmpn(uri, "ntp://", 6)) { /* nntp:// */
return 7;
}
break;
case 's':
case 'S':
- if (!strncasecmp(uri, "cgi://", 6)) { /* scgi:// */
+ if (!ap_cstr_casecmpn(uri, "cgi://", 6)) { /* scgi:// */
*sqs = 1;
return 7;
}
@@ -611,15 +621,22 @@ static unsigned is_absolute_uri(char *uri, int *supportsqs)
case 'w':
case 'W':
- if (!strncasecmp(uri, "s://", 4)) { /* ws:// */
+ if (!ap_cstr_casecmpn(uri, "s://", 4)) { /* ws:// */
*sqs = 1;
return 5;
}
- else if (!strncasecmp(uri, "ss://", 5)) { /* wss:// */
+ else if (!ap_cstr_casecmpn(uri, "ss://", 5)) { /* wss:// */
*sqs = 1;
return 6;
}
break;
+
+ case 'u':
+ case 'U':
+ if (!ap_cstr_casecmpn(uri, "nix:", 4)) { /* unix: */
+ *sqs = 1;
+ return (uri[4] == '/' && uri[5] == '/') ? 7 : 5;
+ }
}
return 0;
@@ -643,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;
}
@@ -661,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;
}
@@ -723,7 +732,7 @@ static char *escape_absolute_uri(apr_pool_t *p, char *uri, unsigned scheme)
* [dn ["?" [attributes] ["?" [scope]
* ["?" [filter] ["?" extensions]]]]]]
*/
- if (!strncasecmp(uri, "ldap", 4)) {
+ if (!ap_cstr_casecmpn(uri, "ldap", 4)) {
char *token[5];
int c = 0;
@@ -759,27 +768,35 @@ static char *escape_absolute_uri(apr_pool_t *p, char *uri, unsigned scheme)
* split out a QUERY_STRING part from
* the current URI string
*/
-static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard,
- int qslast)
+static void splitout_queryargs(request_rec *r, int flags)
{
char *q;
- int split;
+ int split, skip;
+ int qsappend = flags & RULEFLAG_QSAPPEND;
+ int qsdiscard = flags & RULEFLAG_QSDISCARD;
+ int qslast = flags & RULEFLAG_QSLAST;
+
+ if (flags & RULEFLAG_QSNONE) {
+ rewritelog((r, 2, NULL, "discarding query string, no parse from substitution"));
+ r->args = NULL;
+ return;
+ }
/* don't touch, unless it's a scheme for which a query string makes sense.
* See RFC 1738 and RFC 2368.
*/
- if (is_absolute_uri(r->filename, &split)
+ if ((skip = is_absolute_uri(r->filename, &split))
&& !split) {
r->args = NULL; /* forget the query that's still flying around */
return;
}
- if ( qsdiscard ) {
+ if (qsdiscard) {
r->args = NULL; /* Discard query string */
rewritelog((r, 2, NULL, "discarding query string"));
}
- q = qslast ? ap_strrchr(r->filename, '?') : ap_strchr(r->filename, '?');
+ q = qslast ? ap_strrchr(r->filename + skip, '?') : ap_strchr(r->filename + skip, '?');
if (q != NULL) {
char *olduri;
@@ -788,7 +805,7 @@ static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard,
olduri = apr_pstrdup(r->pool, r->filename);
*q++ = '\0';
if (qsappend) {
- if (*q) {
+ if (*q) {
r->args = apr_pstrcat(r->pool, q, "&" , r->args, NULL);
}
}
@@ -796,9 +813,9 @@ static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard,
r->args = apr_pstrdup(r->pool, q);
}
- if (r->args) {
+ if (r->args) {
len = strlen(r->args);
-
+
if (!len) {
r->args = NULL;
}
@@ -810,8 +827,6 @@ static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard,
rewritelog((r, 3, NULL, "split uri=%s -> uri=%s, args=%s", olduri,
r->filename, r->args ? r->args : "<none>"));
}
-
- return;
}
/*
@@ -825,7 +840,7 @@ static void reduce_uri(request_rec *r)
cp = (char *)ap_http_scheme(r);
l = strlen(cp);
if ( strlen(r->filename) > l+3
- && strncasecmp(r->filename, cp, l) == 0
+ && ap_cstr_casecmpn(r->filename, cp, l) == 0
&& r->filename[l] == ':'
&& r->filename[l+1] == '/'
&& r->filename[l+2] == '/' ) {
@@ -1029,6 +1044,7 @@ static void set_cache_value(const char *name, apr_time_t t, char *key,
#endif
return;
}
+ apr_pool_tag(p, "rewrite_cachedmap");
map = apr_palloc(cachep->pool, sizeof(cachedmap));
map->pool = p;
@@ -1106,6 +1122,7 @@ static int init_cache(apr_pool_t *p)
cachep = NULL; /* turns off cache */
return 0;
}
+ apr_pool_tag(cachep->pool, "rewrite_cachep");
cachep->maps = apr_hash_make(cachep->pool);
#if APR_HAS_THREADS
@@ -1353,12 +1370,31 @@ static char *lookup_map_txtfile(request_rec *r, const char *file, char *key)
static char *lookup_map_dbmfile(request_rec *r, const char *file,
const char *dbmtype, char *key)
{
+#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7)
+ const apr_dbm_driver_t *driver;
+ const apu_err_t *err;
+#endif
apr_dbm_t *dbmfp = NULL;
apr_datum_t dbmkey;
apr_datum_t dbmval;
char *value;
apr_status_t rv;
+#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7)
+ if ((rv = apr_dbm_get_driver(&driver, dbmtype, &err,
+ r->pool)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(10287)
+ "mod_rewrite: can't load DBM library '%s': %s",
+ err->reason, err->msg);
+ return NULL;
+ }
+ if ((rv = apr_dbm_open2(&dbmfp, driver, file, APR_DBM_READONLY,
+ APR_OS_DEFAULT, r->pool)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00656)
+ "mod_rewrite: can't open DBM RewriteMap %s", file);
+ return NULL;
+ }
+#else
if ((rv = apr_dbm_open_ex(&dbmfp, dbmtype, file, APR_DBM_READONLY,
APR_OS_DEFAULT, r->pool)) != APR_SUCCESS)
{
@@ -1366,6 +1402,7 @@ static char *lookup_map_dbmfile(request_rec *r, const char *file,
"mod_rewrite: can't open DBM RewriteMap %s", file);
return NULL;
}
+#endif
dbmkey.dptr = key;
dbmkey.dsize = strlen(key);
@@ -1864,8 +1901,8 @@ static char *lookup_variable(char *var, rewrite_ctx *ctx)
result = getenv(var);
}
}
- else if (var[4] && !strncasecmp(var, "SSL", 3) && rewrite_ssl_lookup) {
- result = rewrite_ssl_lookup(r->pool, r->server, r->connection, r,
+ else if (var[4] && !strncasecmp(var, "SSL", 3)) {
+ result = ap_ssl_var_lookup(r->pool, r->server, r->connection, r,
var + 4);
}
}
@@ -1963,7 +2000,7 @@ static char *lookup_variable(char *var, rewrite_ctx *ctx)
case 5:
if (!strcmp(var, "HTTPS")) {
- int flag = rewrite_is_https && rewrite_is_https(r->connection);
+ int flag = ap_ssl_conn_is_ssl(r->connection);
return apr_pstrdup(r->pool, flag ? "on" : "off");
}
break;
@@ -2430,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));
@@ -2538,6 +2576,7 @@ static void add_cookie(request_rec *r, char *s)
char *path;
char *secure;
char *httponly;
+ char *samesite;
char *tok_cntx;
char *cookie;
@@ -2572,6 +2611,7 @@ static void add_cookie(request_rec *r, char *s)
path = expires ? apr_strtok(NULL, sep, &tok_cntx) : NULL;
secure = path ? apr_strtok(NULL, sep, &tok_cntx) : NULL;
httponly = secure ? apr_strtok(NULL, sep, &tok_cntx) : NULL;
+ samesite = httponly ? apr_strtok(NULL, sep, &tok_cntx) : NULL;
if (expires) {
apr_time_exp_t tms;
@@ -2599,18 +2639,23 @@ static void add_cookie(request_rec *r, char *s)
: NULL,
expires ? (exp_time ? exp_time : "")
: NULL,
- (secure && (!strcasecmp(secure, "true")
+ (secure && (!ap_cstr_casecmp(secure, "true")
|| !strcmp(secure, "1")
- || !strcasecmp(secure,
+ || !ap_cstr_casecmp(secure,
"secure"))) ?
"; secure" : NULL,
- (httponly && (!strcasecmp(httponly, "true")
+ (httponly && (!ap_cstr_casecmp(httponly, "true")
|| !strcmp(httponly, "1")
- || !strcasecmp(httponly,
+ || !ap_cstr_casecmp(httponly,
"HttpOnly"))) ?
"; HttpOnly" : NULL,
NULL);
+ if (samesite && strcmp(samesite, "0") && ap_cstr_casecmp(samesite,"false")) {
+ cookie = apr_pstrcat(rmain->pool, cookie, "; SameSite=",
+ samesite, NULL);
+ }
+
apr_table_addn(rmain->err_headers_out, "Set-Cookie", cookie);
apr_pool_userdata_set("set", notename, NULL, rmain->pool);
rewritelog((rmain, 5, NULL, "setting cookie '%s'", cookie));
@@ -2724,7 +2769,7 @@ static apr_status_t rewritelock_remove(void *data)
* XXX: what an inclined parser. Seems we have to leave it so
* for backwards compat. *sigh*
*/
-static int parseargline(char *str, char **a1, char **a2, char **a3)
+static int parseargline(char *str, char **a1, char **a2, char **a2_end, char **a3)
{
char quote;
@@ -2775,8 +2820,10 @@ static int parseargline(char *str, char **a1, char **a2, char **a3)
if (!*str) {
*a3 = NULL; /* 3rd argument is optional */
+ *a2_end = str;
return 0;
}
+ *a2_end = str;
*str++ = '\0';
while (apr_isspace(*str)) {
@@ -3316,7 +3363,7 @@ static const char *cmd_rewritecond(cmd_parms *cmd, void *in_dconf,
rewrite_server_conf *sconf;
rewritecond_entry *newcond;
ap_regex_t *regexp;
- char *a1 = NULL, *a2 = NULL, *a3 = NULL;
+ char *a1 = NULL, *a2 = NULL, *a2_end, *a3 = NULL;
const char *err;
sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
@@ -3334,7 +3381,7 @@ static const char *cmd_rewritecond(cmd_parms *cmd, void *in_dconf,
* of the argument line. So we can use a1 .. a3 without
* copying them again.
*/
- if (parseargline(str, &a1, &a2, &a3)) {
+ if (parseargline(str, &a1, &a2, &a2_end, &a3)) {
return apr_pstrcat(cmd->pool, "RewriteCond: bad argument line '", str,
"'", NULL);
}
@@ -3493,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;
}
@@ -3742,7 +3800,7 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
rewrite_server_conf *sconf;
rewriterule_entry *newrule;
ap_regex_t *regexp;
- char *a1 = NULL, *a2 = NULL, *a3 = NULL;
+ char *a1 = NULL, *a2 = NULL, *a2_end, *a3 = NULL;
const char *err;
sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
@@ -3756,12 +3814,11 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
}
/* parse the argument line ourself */
- if (parseargline(str, &a1, &a2, &a3)) {
+ if (parseargline(str, &a1, &a2, &a2_end, &a3)) {
return apr_pstrcat(cmd->pool, "RewriteRule: bad argument line '", str,
"'", NULL);
}
- /* arg3: optional flags field */
newrule->forced_mimetype = NULL;
newrule->forced_handler = NULL;
newrule->forced_responsecode = HTTP_MOVED_TEMPORARILY;
@@ -3770,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) {
@@ -3803,6 +3863,25 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
newrule->flags |= RULEFLAG_NOSUB;
}
+ if (*(a2_end-1) == '?') {
+ /* a literal ? at the end of the unsubstituted rewrite rule */
+ 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, '?')) {
+ newrule->flags |= RULEFLAG_QSNONE;
+ }
+ }
+
/* now, if the server or per-dir config holds an
* array of RewriteCond entries, we take it for us
* and clear the array
@@ -4090,7 +4169,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
}
/* Additionally we strip the physical path from the url to match
- * it independent from the underlaying filesystem.
+ * it independent from the underlying filesystem.
*/
if (!is_proxyreq && strlen(ctx->uri) >= dirlen &&
!strncmp(ctx->uri, ctx->perdir, dirlen)) {
@@ -4208,9 +4287,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
r->path_info = NULL;
}
- splitout_queryargs(r, p->flags & RULEFLAG_QSAPPEND,
- p->flags & RULEFLAG_QSDISCARD,
- p->flags & RULEFLAG_QSLAST);
+ splitout_queryargs(r, p->flags);
/* Add the previously stripped per-directory location prefix, unless
* (1) it's an absolute URL path and
@@ -4516,9 +4593,6 @@ static int post_config(apr_pool_t *p,
}
}
- rewrite_ssl_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
- rewrite_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
-
return OK;
}
@@ -4692,8 +4766,25 @@ static int hook_uri2file(request_rec *r)
}
if (rulestatus) {
- unsigned skip;
- apr_size_t flen;
+ 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 "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
+ }
if (ACTION_STATUS == rulestatus) {
int n = r->status;
@@ -4702,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
@@ -4745,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 */
@@ -4753,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 */
@@ -4977,7 +5067,26 @@ 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;
+
+ 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.
+ */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10411)
+ "Rewritten query string contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
+ }
if (ACTION_STATUS == rulestatus) {
int n = r->status;
@@ -4986,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
@@ -5011,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
@@ -5020,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,
@@ -5065,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 */