mod_rewrite.c revision 855d6aa9f641cd160ee4265824a3ad3d06231c76
6de8046f8f7e07cd83895a528df25d977e502c76nd/* Licensed to the Apache Software Foundation (ASF) under one or more
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * contributor license agreements. See the NOTICE file distributed with
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * this work for additional information regarding copyright ownership.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * The ASF licenses this file to You under the Apache License, Version 2.0
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * (the "License"); you may not use this file except in compliance with
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * the License. You may obtain a copy of the License at
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Unless required by applicable law or agreed to in writing, software
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * distributed under the License is distributed on an "AS IS" BASIS,
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * See the License for the specific language governing permissions and
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein * limitations under the License.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * _ __ ___ ___ __| | _ __ _____ ___ __(_) |_ ___
f4c310fd2555c6faca1f980f00b161eadb089023gstein * | '_ ` _ \ / _ \ / _` | | '__/ _ \ \ /\ / / '__| | __/ _ \
f4c310fd2555c6faca1f980f00b161eadb089023gstein * | | | | | | (_) | (_| | | | | __/\ V V /| | | | || __/
cd5c0afc86ca2eb23d6d12e14590e03cf2f80450gstein * |_| |_| |_|\___/ \__,_|___|_| \___| \_/\_/ |_| |_|\__\___|
f6b86fd524444dacf82f64148300d8be04918314gstein * URL Rewriting Module
f4c310fd2555c6faca1f980f00b161eadb089023gstein * This module uses a rule-based rewriting engine (based on a
f69b31136266022effeb1272d153c92a09de072djerenkrantz * regular-expression parser) to rewrite requested URLs on the fly.
f6b86fd524444dacf82f64148300d8be04918314gstein * It supports an unlimited number of additional rule conditions (which can
f4c310fd2555c6faca1f980f00b161eadb089023gstein * operate on a lot of variables, even on HTTP headers) for granular
aa552377469071a421252dab6568c204a99cf770gstein * matching and even external database lookups (either via plain text
f4c310fd2555c6faca1f980f00b161eadb089023gstein * tables, DBM hash files or even external processes) for advanced URL
aa552377469071a421252dab6568c204a99cf770gstein * substitution.
3a02a42c92afc04c1cfca12eabdf19963784ae83nd * It operates on the full URLs (including the PATH_INFO part) both in
aa552377469071a421252dab6568c204a99cf770gstein * per-server context (httpd.conf) and per-dir context (.htaccess) and even
aa552377469071a421252dab6568c204a99cf770gstein * can generate QUERY_STRING parts on result. The rewriting result finally
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz * can lead to internal subprocessing, external request redirection or even
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz * to internal proxy throughput.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * This module was originally written in April 1996 and
aa552377469071a421252dab6568c204a99cf770gstein * gifted exclusively to the The Apache Software Foundation in July 1997 by
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Ralf S. Engelschall
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz/* XXX: Do we really need these headers? */
1a08a3eb0808297eb4157e30ad9dcdabe92fc4eajerenkrantzstatic ap_dbd_t *(*dbd_acquire)(request_rec*) = NULL;
1a08a3eb0808297eb4157e30ad9dcdabe92fc4eajerenkrantzstatic void (*dbd_prepare)(server_rec*, const char*, const char*) = NULL;
1a08a3eb0808297eb4157e30ad9dcdabe92fc4eajerenkrantzstatic const char* really_last_key = "rewrite_really_last";
2d399cd7535887fceaa9f8f116eb98ce68ddd602trawick * in order to improve performance on running production systems, you
f4cc246f8dd56a23d93d6e9afa8efd406b01f135gstein * may strip all rewritelog code entirely from mod_rewrite by using the
f4cc246f8dd56a23d93d6e9afa8efd406b01f135gstein * -DREWRITELOG_DISABLED compiler option.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * DO NOT USE THIS OPTION FOR PUBLIC BINARY RELEASES. Otherwise YOU are
c364a517c4f0db3d0a33c662c02f2d567a33e135martin * responsible for answering all the mod_rewrite questions out there.
c364a517c4f0db3d0a33c662c02f2d567a33e135martin/* If logging is limited to APLOG_DEBUG or lower, disable rewrite log, too */
aa552377469071a421252dab6568c204a99cf770gstein#define REWRITELOG_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
f4c310fd2555c6faca1f980f00b161eadb089023gstein#define REWRITELOG_FLAGS ( APR_WRITE | APR_APPEND | APR_CREATE )
a4804918bbbb650c03f1954aa09a8e957589b1ccjerenkrantz#else /* !REWRITELOG_DISABLED */
#ifndef RAND_MAX
#ifndef REWRITE_MAX_TXT_MAP_LINE
#ifndef REWRITE_PRG_MAP_BUF
CONDPAT_REGEX = 0,
} pattern_type;
typedef struct data_item {
char *data;
} data_item;
typedef struct cache {
#if APR_HAS_THREADS
} cache;
} cachedmap;
typedef struct backrefinfo {
const char *source;
} backrefinfo;
typedef struct result_list {
const char *string;
} result_list;
request_rec *r;
const char *uri;
const char *vary_this;
const char *vary;
char *perdir;
} rewrite_ctx;
static int proxy_available;
#ifndef REWRITELOG_DISABLED
const char *fmt, ...)
const char *fmt, ...)
int redir;
++redir;
(void *)(r->server),
text);
*sqs = 0;
switch (*uri++) {
unsigned char *where)
return where;
const unsigned char *s = (const unsigned char *)path;
unsigned char *d = (unsigned char *)copy;
return copy;
char *cp;
return NULL;
++cp;
++cp;
NULL);
int split;
&& !split) {
if ( qsdiscard ) {
if (q != NULL) {
char *olduri;
if (qsappend) {
if (!len) {
char *cp;
apr_size_t l;
unsigned short port;
++cp;
++cp;
if (!*url) {
const char *thisserver;
char *thisport;
int port;
r->filename);
const char *root;
const char *slash;
char *statpath;
const char *subst)
--len;
char *output;
++slen;
output));
return output;
return input;
char *val)
if (cachep) {
#if APR_HAS_THREADS
if (!map) {
apr_pool_t *p;
#if APR_HAS_THREADS
#if APR_HAS_THREADS
apr_pool_t *p)
if (cachep) {
#if APR_HAS_THREADS
if (map) {
if (val) {
#if APR_HAS_THREADS
return val;
#if APR_HAS_THREADS
return key;
return key;
return key;
char *p = value;
++value;
return value;
const char *desc)
procattr, p);
if (fpin) {
if (fpout) {
return (rc);
return APR_SUCCESS;
void *val;
return rc;
return APR_SUCCESS;
return NULL;
p = line;
c = key;
while (*p && apr_isspace(*p)) {
while (*p && !apr_isspace(*p)) {
return value;
char *value;
return NULL;
return value;
const char *errmsg;
if (rv != 0) {
return NULL;
return NULL;
char *buf;
int found_nl = 0;
#ifndef NO_WRITEV
return NULL;
if (rewrite_mapr_lock_acquire) {
#ifdef NO_WRITEV
--eolc;
if (i < eolc) {
i -= eolc;
++found_nl;
else if (eolc) {
eolc = 0;
++found_nl;
buf[i++] = c;
if (!buflist) {
combined_len += i;
if (buflist) {
while (buflist) {
i = combined_len;
if (rewrite_mapr_lock_acquire) {
return NULL;
return buf;
rewritemap_entry *s;
char *value;
return NULL;
switch (s->type) {
case MAPTYPE_RND:
case MAPTYPE_TXT:
s->checkfile);
return NULL;
if (!value) {
if (!value) {
return NULL;
case MAPTYPE_DBM:
s->checkfile);
return NULL;
if (!value) {
if (!value) {
return NULL;
return value;
case MAPTYPE_DBD:
if (!value) {
return NULL;
return value;
case MAPTYPE_DBD_CACHE:
if (!value) {
if (!value) {
return NULL;
return value;
case MAPTYPE_PRG:
if (!value) {
key));
return NULL;
return value;
case MAPTYPE_INT:
if (!value) {
key));
return NULL;
return value;
return NULL;
if (val) {
return val;
const char *result;
if (!result) {
if (!result) {
const char *path;
ctx->r = r;
return (char *)result;
NULL);
ctx->r = r;
return (char *)result;
switch (varlen) {
return (char *)result;
#if APR_HAVE_IPV6
r->pool);
r->pool);
unsigned depth;
else if (*s == LEFT_CURLY) {
++depth;
return NULL;
unsigned depth;
return NULL;
else if (*s == LEFT_CURLY) {
++depth;
return NULL;
unsigned spc = 0;
sizeof(result_list));
++outlen;
char *endp;
if (!endp) {
char *key;
if (!key) {
if (dflt) {
if (key) {
++outlen;
sizeof(result_list));
p += span;
} while (result);
while (env) {
name++;
char *var;
char *val;
char *domain;
char *expires;
char *path;
char *secure;
char *httponly;
char *tok_cntx;
char *cookie;
char *notename;
void *data;
if (!data) {
if (expires) {
long exp_min;
if (exp_min) {
: NULL,
: NULL,
NULL);
var));
while (cookie) {
#if APR_HAS_USER
char *p, *user;
if (p > user) {
char *homedir;
return homedir;
return uri;
return rc;
return APR_SUCCESS;
if (rewrite_mapr_lock_acquire) {
char quote;
++str;
++str;
if (!*str) {
++str;
++str;
if (!*str) {
++str;
if (!*str) {
++str;
a->server = s;
sizeof(rewrite_server_conf));
sizeof(rewrite_perdir_conf));
return NULL;
int options = 0;
while (*option) {
return NULL;
const char *a2)
const char *fname;
if (colon) {
if (!fname) {
return NULL;
const char *a1)
return NULL;
const char *err;
++key;
while (*key) {
++key;
--endp;
if (val) {
if (err) {
return err;
return NULL;
return NULL;
const char *in_str)
char *a1;
char *a2;
char *a3;
const char *err;
++a2;
switch (*a2) {
? AP_REG_ICASE : 0));
if (!regexp) {
if (err)
return NULL;
int error = 0;
switch (*key++) {
++error;
if (!cp) {
++error;
if (!cp) {
++error;
++error;
++error;
++error;
++error;
++error;
++error;
++error;
int status = 0;
if (*val) {
int idx =
val);
++error;
++error;
++error;
++error;
if (error) {
return NULL;
const char *in_str)
char *a1;
char *a2;
char *a3;
const char *err;
++a1;
? AP_REG_ICASE : 0));
if (!regexp) {
sizeof(rewritecond_entry));
sizeof(rewritecond_entry));
return NULL;
for (i = 0; i < lena; ++i) {
int rc = 0;
int basis;
switch (p->ptype) {
case CONDPAT_FILE_EXISTS:
case CONDPAT_FILE_SIZE:
case CONDPAT_FILE_LINK:
#if !defined(OS2)
case CONDPAT_FILE_DIR:
case CONDPAT_FILE_XBIT:
case CONDPAT_LU_URL:
case CONDPAT_LU_FILE:
case CONDPAT_STR_GE:
basis = 0;
goto test_str_g;
case CONDPAT_STR_GT:
case CONDPAT_STR_LE:
basis = 0;
goto test_str_l;
case CONDPAT_STR_LT:
case CONDPAT_STR_EQ:
case CONDPAT_AP_EXPR:
rc = 0;
return rc;
char *expanded;
if (p->forced_mimetype) {
if (*expanded) {
expanded);
if (p->forced_handler) {
if (*expanded) {
expanded);
int i, rc;
int is_proxyreq = 0;
if (!rc) {
c = &conds[++i];
else if (!rc) {
NULL)
newuri));
r->filename));
r->filename));
reduce_uri(r);
char *perdir)
int changed;
int rc;
ctx->r = r;
changed = 0;
loop:
p = &entries[i];
if (rc) {
return ACTION_STATUS;
goto loop;
if (p->skip > 0) {
s = p->skip;
p = &entries[i];
return changed;
if (map_pfn_register) {
return OK;
server_rec *s)
return HTTP_INTERNAL_SERVER_ERROR;
for (; s; s = s->next) {
return HTTP_INTERNAL_SERVER_ERROR;
return OK;
if (rewrite_mapr_lock_acquire) {
if (!init_cache(p)) {
const char *saved_rulestatus;
const char *var;
const char *thisserver;
char *thisport;
const char *thisurl;
unsigned int port;
int rulestatus;
void *skipdata;
return DECLINED;
return DECLINED;
return DECLINED;
r->uri));
return DECLINED;
r->filename));
if (rulestatus) {
unsigned skip;
int n = r->status;
if (!proxy_available) {
return HTTP_FORBIDDEN;
r->filename));
return OK;
r->filename));
if (r->args) {
? r->args
NULL);
n = r->status;
return DECLINED;
#if APR_HAS_USER
return HTTP_BAD_REQUEST;
int res;
return res;
r->filename));
return OK;
return DECLINED;
char *cp;
char *cp2;
const char *ccp;
apr_size_t l;
int rulestatus;
int is_proxyreq;
void *skipdata;
return DECLINED;
return DECLINED;
return DECLINED;
* URL: http://localhost/foo and .htaccess is located in foo directory
return DECLINED;
return DECLINED;
return HTTP_FORBIDDEN;
if (rulestatus) {
unsigned skip;
int n = r->status;
return OK;
* hostname and compare/substitute only the stuff after it.
r->filename));
if (r->args) {
? r->args
NULL);
r->args ,
n = r->status;
r->filename, n));
return HTTP_BAD_REQUEST;
return OK;
r->filename+l));
return OK;
return DECLINED;
r->filename, t));
ap_set_content_type(r, t);
r->handler = t;
return OK;
return DECLINED;
return DECLINED;
return OK;
{ NULL }