mod_rewrite.c revision fc0e39b58d9ebd19c4d5cba5e9d535af2b756b78
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/* ====================================================================
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * The Apache Software License, Version 1.1
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * reserved.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Redistribution and use in source and binary forms, with or without
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * modification, are permitted provided that the following conditions
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * 1. Redistributions of source code must retain the above copyright
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * notice, this list of conditions and the following disclaimer.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * 2. Redistributions in binary form must reproduce the above copyright
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * notice, this list of conditions and the following disclaimer in
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * the documentation and/or other materials provided with the
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * distribution.
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * 3. The end-user documentation included with the redistribution,
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * if any, must include the following acknowledgment:
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * "This product includes software developed by the
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Apache Software Foundation (http://www.apache.org/)."
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Alternately, this acknowledgment may appear in the software itself,
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * if and wherever such third-party acknowledgments normally appear.
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * 4. The names "Apache" and "Apache Software Foundation" must
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * not be used to endorse or promote products derived from this
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * software without prior written permission. For written
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * permission, please contact apache@apache.org.
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * 5. Products derived from this software may not be called "Apache",
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * nor may "Apache" appear in their name, without prior written
64185f9824e42f21ca7b9ae6c004484215c031a7rbb * permission of the Apache Software Foundation.
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * SUCH DAMAGE.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * ====================================================================
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * This software consists of voluntary contributions made by many
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * individuals on behalf of the Apache Software Foundation. For more
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * information on the Apache Software Foundation, please see
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Portions of this software are based upon public domain software
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * originally written at the National Center for Supercomputing Applications,
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * University of Illinois, Urbana-Champaign.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** _ __ ___ ___ __| | _ __ _____ ___ __(_) |_ ___
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** | '_ ` _ \ / _ \ / _` | | '__/ _ \ \ /\ / / '__| | __/ _ \
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** | | | | | | (_) | (_| | | | | __/\ V V /| | | | || __/
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** |_| |_| |_|\___/ \__,_|___|_| \___| \_/\_/ |_| |_|\__\___|
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** URL Rewriting Module
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** This module uses a rule-based rewriting engine (based on a
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** regular-expression parser) to rewrite requested URLs on the fly.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** It supports an unlimited number of additional rule conditions (which can
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** operate on a lot of variables, even on HTTP headers) for granular
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** matching and even external database lookups (either via plain text
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** tables, DBM hash files or even external processes) for advanced URL
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** substitution.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** It operates on the full URLs (including the PATH_INFO part) both in
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** per-server context (httpd.conf) and per-dir context (.htaccess) and even
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** can generate QUERY_STRING parts on result. The rewriting result finally
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** can lead to internal subprocessing, external request redirection or even
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** to internal proxy throughput.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** This module was originally written in April 1996 and
c7d0205ec1649076e7742d72a25ac53779768312stoddard** gifted exclusively to the The Apache Software Foundation in July 1997 by
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** Ralf S. Engelschall
c7d0205ec1649076e7742d72a25ac53779768312stoddard** rse@engelschall.com
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#define MOD_REWRITE_SET_MUTEX_PERMS /* XXX Apache should define something */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** +-------------------------------------------------------+
c7d0205ec1649076e7742d72a25ac53779768312stoddard** | static module configuration
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** +-------------------------------------------------------+
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** Our interface to the Apache server kernel:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** o Runtime logic of a request is as following:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** while(request or subrequest)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** foreach(stage #0...#9)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** foreach(module) (**)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** try to run hook
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** o the order of modules at (**) is the inverted order as
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** given in the "Configuration" file, i.e. the last module
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald** specified is the first one called for each hook!
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** The core module is always the last!
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** o there are two different types of result checking and
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** continue processing:
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald** for hook #0,#1,#4,#5,#6,#8:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** hook run loop stops on first modules which gives
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** back a result != DECLINED, i.e. it usually returns OK
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** which says "OK, module has handled this _stage_" and for #1
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** this have not to mean "Ok, the filename is now valid".
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** for hook #2,#3,#7,#9:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** all hooks are run, independend of result
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** o at the last stage, the core module always
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** - says "HTTP_BAD_REQUEST" if r->filename does not begin with "/"
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** - prefix URL with document_root or replaced server_root
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** with document_root and sets r->filename
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** - always return a "OK" independed if the file really exists
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* the module (predeclaration) */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* rewritemap int: handler function registry */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* the cache */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* whether proxy module is available or not */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *lockname;
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic apr_global_mutex_t *rewrite_mapr_lock_acquire = NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** +-------------------------------------------------------+
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** | configuration directive handling
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** +-------------------------------------------------------+
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** per-server configuration structure handling
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic void *config_server_create(apr_pool_t *p, server_rec *s)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a = (rewrite_server_conf *)apr_pcalloc(p, sizeof(rewrite_server_conf));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a->rewritemaps = apr_array_make(p, 2, sizeof(rewritemap_entry));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a->rewriteconds = apr_array_make(p, 2, sizeof(rewritecond_entry));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a->rewriterules = apr_array_make(p, 2, sizeof(rewriterule_entry));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return (void *)a;
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic void *config_server_merge(apr_pool_t *p, void *basev, void *overridesv)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * local directives override
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * and anything else is inherited
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a->rewriteloglevel = overrides->rewriteloglevel != 0
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a->rewritelogfile = overrides->rewritelogfile != NULL
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a->rewritemaps = apr_array_append(p, overrides->rewritemaps,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a->rewriteconds = apr_array_append(p, overrides->rewriteconds,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a->rewriterules = apr_array_append(p, overrides->rewriterules,
c7d0205ec1649076e7742d72a25ac53779768312stoddard * local directives override
c7d0205ec1649076e7742d72a25ac53779768312stoddard * and anything else gets defaults
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return (void *)a;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** per-directory configuration structure handling
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic void *config_perdir_create(apr_pool_t *p, char *path)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a = (rewrite_perdir_conf *)apr_pcalloc(p, sizeof(rewrite_perdir_conf));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a->rewriteconds = apr_array_make(p, 2, sizeof(rewritecond_entry));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a->rewriterules = apr_array_make(p, 2, sizeof(rewriterule_entry));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a->redirect_limit = 0; /* unset (use server config) */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* make sure it has a trailing slash */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return (void *)a;
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic void *config_perdir_merge(apr_pool_t *p, void *basev, void *overridesv)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a->rewriteconds = apr_array_append(p, overrides->rewriteconds,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding a->rewriterules = apr_array_append(p, overrides->rewriterules,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return (void *)a;
c7d0205ec1649076e7742d72a25ac53779768312stoddard** the configuration commands
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *cmd_rewriteengine(cmd_parms *cmd,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding sconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED);
404e2e1f8ad30c2d996f5fb6b3a9a4a4a14a004brbb else /* is per-directory command */ {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding dconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED);
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *cmd_rewriteoptions(cmd_parms *cmd,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return "RewriteOptions: MaxRedirects takes a number greater "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "than zero.";
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else if (!strcasecmp(w, "MaxRedirects")) { /* be nice */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return "RewriteOptions: MaxRedirects has the format MaxRedirects"
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return apr_pstrcat(cmd->pool, "RewriteOptions: unknown option '",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* put it into the appropriate config */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else { /* is per-directory command */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *cmd_rewritelog(cmd_parms *cmd, void *dconf, const char *a1)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *a1)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, const char *a1,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *a2)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return apr_pstrcat(cmd->pool, "RewriteMap: bad map:",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rv = apr_dbm_get_usednames_ex(cmd->pool, newmap->dbmtype,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return apr_pstrcat(cmd->pool, "RewriteMap: dbm type ",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_tokenize_to_argv(a2 + 4, &newmap->argv, cmd->pool);
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald if ((sconf->state == ENGINE_ENABLED) && (newmap->func == NULL)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return apr_pstrcat(cmd->pool, "RewriteMap: internal map not found:",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (newmap->checkfile && (sconf->state == ENGINE_ENABLED)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding && (apr_stat(&st, newmap->checkfile, APR_FINFO_MIN,
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *cmd_rewritelock(cmd_parms *cmd, void *dconf, const char *a1)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *error;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ((error = ap_check_cmd_context(cmd, GLOBAL_ONLY)) != NULL)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* fixup the path, especially for rewritelock_remove() */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return apr_pstrcat(cmd->pool, "Invalid RewriteLock path ", a1);
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *cmd_rewritebase(cmd_parms *cmd, void *in_dconf,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *a1)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return "RewriteBase: only valid in per-directory config files";
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return "RewriteBase: empty URL not allowed";
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return "RewriteBase: argument is not a valid URL";
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *cmd_rewritecond(cmd_parms *cmd, void *in_dconf,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *in_str)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *err;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* make a new entry in the internal temporary rewrite rule list */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else { /* is per-directory command */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* parse the argument line ourself */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return apr_pstrcat(cmd->pool, "RewriteCond: bad argument line '", str,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* arg1: the input string */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* arg3: optional flags field
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding (this have to be first parsed, because we need to
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding know if the regex should be compiled with ICASE!) */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ((err = cmd_rewritecond_parseflagfield(cmd->pool, newcond,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* arg2: the pattern
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding try to compile the regexp to test if is ok */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* now be careful: Under the POSIX regex library
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding we can compile the pattern for case insensitive matching,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding under the old V8 library we have to do it self via a hack */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rc = ((regexp = ap_pregcomp(cmd->pool, cp, REG_EXTENDED|REG_ICASE))
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rc = ((regexp = ap_pregcomp(cmd->pool, cp, REG_EXTENDED)) == NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "RewriteCond: cannot compile regular expression '",
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *cmd_rewritecond_parseflagfield(apr_pool_t *p,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *err;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return "RewriteCond: bad flag delimiters";
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding str[strlen(str)-1] = ','; /* for simpler parsing */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* skip whitespaces */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for ( ; (*cp == ' ' || *cp == '\t') && *cp != '\0'; cp++)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for ( ; (*(cp2-1) == ' ' || *(cp2-1) == '\t'); cp2--)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ((err = cmd_rewritecond_setflag(p, cfg, key, val)) != NULL) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *cmd_rewritecond_setflag(apr_pool_t *p,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return apr_pstrcat(p, "RewriteCond: unknown flag '", key, "'", NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *in_str)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *err;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* make a new entry in the internal rewrite rule list */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else { /* is per-directory command */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* parse the argument line ourself */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return apr_pstrcat(cmd->pool, "RewriteRule: bad argument line '", str,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* arg3: optional flags field */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding newrule->forced_responsecode = HTTP_MOVED_TEMPORARILY;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ((err = cmd_rewriterule_parseflagfield(cmd->pool, newrule,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* arg1: the pattern
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * try to compile the regexp to test if is ok
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ((regexp = ap_pregcomp(cmd->pool, cp, mode)) == NULL) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "RewriteRule: cannot compile regular expression '",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* arg2: the output string
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * replace the $<N> by \<n> which is needed by the currently
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * used Regular Expression library
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * TODO: Is this still required for PCRE? If not, does it *work* with PCRE?
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* now, if the server or per-dir config holds an
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * array of RewriteCond entries, we take it for us
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * and clear the array
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else { /* is per-directory command */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *cmd_rewriterule_parseflagfield(apr_pool_t *p,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *err;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return "RewriteRule: bad flag delimiters";
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding str[strlen(str)-1] = ','; /* for simpler parsing */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* skip whitespaces */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for ( ; (*cp == ' ' || *cp == '\t') && *cp != '\0'; cp++)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for ( ; (*(cp2-1) == ' ' || *(cp2-1) == '\t'); cp2--)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ((err = cmd_rewriterule_setflag(p, cfg, key, val)) != NULL) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *cmd_rewriterule_setflag(apr_pool_t *p,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding switch (*key++) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!*key || !strcasecmp(key, "hain")) { /* chain */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return "RewriteRule: too many cookie flags 'CO'";
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return "RewriteRule: too many environment flags 'E'";
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!*key || !strcasecmp(key, "orbidden")) { /* forbidden */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else if (!*key || !strcasecmp(key, "ext")) { /* next */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!*key || !strcasecmp(key, "roxy")) { /* proxy */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding || !strcasecmp(key, "assthrough")) { /* passthrough */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!*key || !strcasecmp(key, "edirect")) { /* redirect */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return "RewriteRule: invalid HTTP response code "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "for flag 'R'";
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return apr_pstrcat(p, "RewriteRule: unknown flag '", key, "'", NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** Global Module Initialization
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding APR_OPTIONAL_FN_TYPE(ap_register_rewrite_mapfunc) *map_pfn_register;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* register int: rewritemap handlers */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding map_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_rewrite_mapfunc);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding map_pfn_register("tolower", rewrite_mapfunc_tolower);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding map_pfn_register("toupper", rewrite_mapfunc_toupper);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding map_pfn_register("escape", rewrite_mapfunc_escape);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding map_pfn_register("unescape", rewrite_mapfunc_unescape);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_pool_userdata_get(&data, userdata_key, s->process->pool);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_pool_userdata_set((const void *)1, userdata_key,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* check if proxy module is available */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding proxy_available = (ap_find_linked_module("mod_proxy.c") != NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* create the rewriting lockfiles in the parent */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ((rv = apr_global_mutex_create(&rewrite_log_lock, NULL,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "mod_rewrite: could not create rewrite_log_lock");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rv = unixd_set_global_mutex_perms(rewrite_log_lock);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "mod_rewrite: Could not set permissions on "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "rewrite_log_lock; check User and Group directives");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_pool_cleanup_register(p, (void *)s, rewritelock_remove,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* step through the servers and
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * - open each rewriting logfile
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * - open the RewriteMap prg:xxx programs
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (; s; s = s->next) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (run_rewritemap_programs(s, p) != APR_SUCCESS) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** Per-Child Module Initialization
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** [called after a child process is spawned]
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic void init_child(apr_pool_t *p, server_rec *s)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rv = apr_global_mutex_child_init(&rewrite_mapr_lock_acquire,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "mod_rewrite: could not init rewrite_mapr_lock_acquire"
404e2e1f8ad30c2d996f5fb6b3a9a4a4a14a004brbb " in child");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rv = apr_global_mutex_child_init(&rewrite_log_lock, NULL, p);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "mod_rewrite: could not init rewrite log lock in child");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* create the lookup cache */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** +-------------------------------------------------------+
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** | runtime hooks
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** +-------------------------------------------------------+
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** URI-to-filename hook
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** [used for the rewriting engine triggered by
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** the per-server 'RewriteRule' directives]
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *var;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *thisurl;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding unsigned int port;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * retrieve the config structures
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding conf = ap_get_module_config(r->server->module_config, &rewrite_module);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * only do something under runtime if the engine is really enabled,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * else return immediately!
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * check for the ugly API case of a virtual host section where no
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * mod_rewrite directives exists. In this situation we became no chance
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * by the API to setup our default per-server config so we have to
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * on-the-fly assume we have the default config. But because the default
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * config has a disabled rewriting engine we are lucky because can
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * just stop operating now.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * add the SCRIPT_URL variable to the env. this is a bit complicated
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * due to the fact that apache uses subrequests and internal redirects
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding var = apr_table_get(r->subprocess_env, REDIRECT_ENVVAR_SCRIPT_URL);
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URL, r->uri);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URL, var);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding var = apr_table_get(r->main->subprocess_env, ENVVAR_SCRIPT_URL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URL, var);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * create the SCRIPT_URI variable for the env
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* add the canonical URI of this URL */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding thisurl = apr_table_get(r->subprocess_env, ENVVAR_SCRIPT_URL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* set the variable */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding var = apr_pstrcat(r->pool, ap_http_method(r), "://", thisserver, thisport,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URI, var);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!(saved_rulestatus = apr_table_get(r->notes,"mod_rewrite_rewritten"))) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* if filename was not initially set,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * we start with the requested URI
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog(r, 2, "init rewrite engine with requested uri %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog(r, 2, "init rewrite engine with passed filename %s."
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * now apply the rules ...
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rulestatus = apply_rewrite_list(r, conf->rewriterules, NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "uri already rewritten. Status %s, Uri %s, r->filename %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* it should be go on as an internal proxy request */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* check if the proxy module is enabled, so
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * we can actually use it!
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "attempt to make remote request from mod_rewrite "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* make sure the QUERY_STRING and
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * PATH_INFO parts get incorporated
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* see proxy_http:proxy_http_canon() */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* now make sure the request gets handled by the proxy handler */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog(r, 1, "go-ahead with proxy request %s [OK]",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else if ((skip = is_absolute_uri(r->filename)) > 0) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* it was finally rewritten to a remote URL */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog(r, 1, "escaping %s for redirect", r->filename);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->filename = escape_absolute_uri(r->pool, r->filename, skip);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* append the QUERY_STRING part */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->filename = apr_pstrcat(r->pool, r->filename, "?",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* determine HTTP redirect response code */
c7d0205ec1649076e7742d72a25ac53779768312stoddard r->status = HTTP_OK; /* make Apache kernel happy */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* now do the redirection */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_setn(r->headers_out, "Location", r->filename);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog(r, 1, "redirect to %s [REDIRECT/%d]", r->filename, n);
c7d0205ec1649076e7742d72a25ac53779768312stoddard /* This URLs is forced to be forbidden for the requester */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* This URLs is forced to be gone */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Hack because of underpowered API: passing the current
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * rewritten filename through to other URL-to-filename handlers
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * just as it were the requested URL. This is to enable
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * post-processing by mod_alias, etc. which always act on
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * r->uri! The difference here is: We do not try to
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * add the document root
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* it was finally rewritten to a local path */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* expand "/~user" prefix */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog(r, 2, "local path result: %s", r->filename);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* the filename must be either an absolute local path or an
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * absolute local URL.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding && !ap_os_is_path_absolute(r->pool, r->filename)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* if there is no valid prefix, we call
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * the translator from the core and
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * prefix the filename with document_root
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * We cannot leave out the prefix_stat because
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * - when we always prefix with document_root
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * then no absolute path can be created, e.g. via
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * emulating a ScriptAlias directive, etc.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * - when we always NOT prefix with document_root
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * then the files under document_root have to
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * be references directly and document_root
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * gets never used and will be a dummy parameter -
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * this is also bad
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Under real Unix systems this is no problem,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * because we only do stat() on the first directory
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * and this gets cached by the kernel for along time!
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog(r, 1, "prefixing with document_root of %s "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog(r, 2, "prefixed with document_root to %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog(r, 1, "go-ahead with %s [OK]", r->filename);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** MIME-type hook
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** [used to support the forced-MIME-type feature]
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *t;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* now check if we have to force a MIME-type */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding t = apr_table_get(r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (t == NULL) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog(r, 1, "force filename %s to have MIME-type '%s'",
b79b743d4cff02d6a830bb7118826a2fd608742amartin** Fixup hook
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** [used for the rewriting engine triggered by
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** the per-directory 'RewriteRule' directives]
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald const char *ccp;
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald dconf = (rewrite_perdir_conf *)ap_get_module_config(r->per_dir_config,
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald /* if there is no per-dir config we return immediately */
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald /* we shouldn't do anything in subrequests */
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald /* if there are no real (i.e. no RewriteRule directives!)
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald per-dir config of us, we return also immediately */
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald * .htaccess file is called before really entering the directory, i.e.:
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald * URL: http://localhost/foo and .htaccess is located in foo directory
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald * Ignore such attempts, since they may lead to undefined behaviour.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * only do something under runtime if the engine is really enabled,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * for this directory, else return immediately!
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Do the Options check after engine check, so
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * the user is able to explicitely turn RewriteEngine Off.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!(ap_allow_options(r) & (OPT_SYM_LINKS | OPT_SYM_OWNER))) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* FollowSymLinks is mandatory! */
b79b743d4cff02d6a830bb7118826a2fd608742amartin "Options FollowSymLinks or SymLinksIfOwnerMatch is off "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "which implies that RewriteRule directive is forbidden: "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * remember the current filename before rewriting for later check
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * to prevent deadlooping because of internal redirects
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * on final URL/filename which can be equal to the inital one.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * now apply the rules ...
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* it should go on as an internal proxy request */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* make sure the QUERY_STRING and
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * PATH_INFO parts get incorporated
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * (r->path_info was already appended by the
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * rewriting engine because of the per-dir context!)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* now make sure the request gets handled by the proxy handler */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog(r, 1, "[per-dir %s] go-ahead with proxy request "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else if ((skip = is_absolute_uri(r->filename)) > 0) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* it was finally rewritten to a remote URL */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* because we are in a per-dir context
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * first try to replace the directory with its base-URL
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * if there is a base-URL available
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* skip 'scheme://' */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ((cp = ap_strchr(cp, '/')) != NULL && *(++cp)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "[per-dir %s] trying to replace "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "prefix %s with %s",
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald /* I think, that hack needs an explanation:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * well, here is it:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * mod_rewrite was written for unix systems, were
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * absolute file-system paths start with a slash.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * URL-paths _also_ start with slashes, so they
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * can be easily compared with system paths.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * the following assumes, that the actual url-path
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * may be prefixed by the current directory path and
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * tries to replace the system path with the RewriteBase
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * That assumption is true if we use a RewriteRule like
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * RewriteRule ^foo bar [R]
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * (see apply_rewrite_rule function)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * However on systems that don't have a / as system
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * root this will never match, so we skip the / after the
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * hostname and compare/substitute only the stuff after it.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * (note that cp was already increased to the right value)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding cp2 = subst_prefix_path(r, cp, (*dconf->directory == '/')
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* now prepare the redirect... */
b79b743d4cff02d6a830bb7118826a2fd608742amartin rewritelog(r, 1, "[per-dir %s] escaping %s for redirect",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->filename = escape_absolute_uri(r->pool, r->filename, skip);
404e2e1f8ad30c2d996f5fb6b3a9a4a4a14a004brbb /* append the QUERY_STRING part */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->filename = apr_pstrcat(r->pool, r->filename, "?",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* determine HTTP redirect response code */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->status = HTTP_OK; /* make Apache kernel happy */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* now do the redirection */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_setn(r->headers_out, "Location", r->filename);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog(r, 1, "[per-dir %s] redirect to %s [REDIRECT/%d]",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* This URL is forced to be forbidden for the requester */
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald /* This URL is forced to be gone */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* it was finally rewritten to a local path */
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald /* if someone used the PASSTHROUGH flag in per-dir
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * context we just ignore it. It is only useful
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * in per-server context
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->filename = apr_pstrdup(r->pool, r->filename+12);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* the filename must be either an absolute local path or an
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * absolute local URL.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding && !ap_os_is_path_absolute(r->pool, r->filename)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* Check for deadlooping:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * At this point we KNOW that at least one rewriting
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * rule was applied, but when the resulting URL is
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * the same as the initial URL, we are not allowed to
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * use the following internal redirection stuff because
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * this would lead to a deadloop.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog(r, 1, "[per-dir %s] initial URL equal rewritten "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "URL: %s [IGNORING REWRITE]",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* if there is a valid base-URL then substitute
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * the per-dir prefix with this base-URL if the
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * current filename still is inside this per-dir
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * context. If not then treat the result as a
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * plain URL
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "[per-dir %s] trying to replace prefix %s with %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding dconf->directory, dconf->directory, dconf->baseurl);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* if no explicit base-URL exists we assume
b79b743d4cff02d6a830bb7118826a2fd608742amartin * that the directory prefix is also a valid URL
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * for this webserver and only try to remove the
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * document_root if it is prefix
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* always NOT have a trailing slash */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "[per-dir %s] strip document_root "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "prefix: %s -> %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* now initiate the internal redirect */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog(r, 1, "[per-dir %s] internal redirect with %s "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "[INTERNAL REDIRECT]", dconf->directory, r->filename);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->filename = apr_pstrcat(r->pool, "redirect:", r->filename, NULL);
c7d0205ec1649076e7742d72a25ac53779768312stoddard** Content-Handlers
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** [used for redirect support]
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* just make sure that we are really meant! */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "mod_rewrite: maximum number of internal redirects "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "reached. Assuming configuration error. Use "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "'RewriteOptions MaxRedirects' to increase the limit "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "if neccessary.");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* now do the internal redirect */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_internal_redirect(apr_pstrcat(r->pool, r->filename+9,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* and return gracefully */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * check whether redirect limit is reached
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic int is_redirect_limit_exceeded(request_rec *r)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* we store it in the top request */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* fetch our config */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding reqc = (rewrite_request_conf *) ap_get_module_config(top->request_config,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* no config there? create one. */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding reqc = apr_palloc(top->pool, sizeof(rewrite_request_conf));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding sconf = ap_get_module_config(r->server->module_config, &rewrite_module);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* associate it with this request */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_set_module_config(top->request_config, &rewrite_module, reqc);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* allow to change the limit during redirects. */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding dconf = (rewrite_perdir_conf *)ap_get_module_config(r->per_dir_config,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* 0 == unset; take server conf ... */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "mod_rewrite's internal redirect status: %d/%d.",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* and now give the caller a hint */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return (reqc->redirects++ >= reqc->redirect_limit);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** +-------------------------------------------------------+
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** | the rewriting engine
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding** +-------------------------------------------------------+
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Apply a complete rule set,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * i.e. a list of rewrite rules
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Iterate over all existing rules
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Ignore this rule on subrequests if we are explicitly
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * asked to do so or this is a proxy-throughput or a
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * forced redirect rule.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Apply the current rule.
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald * Indicate a change if this was not a match-only rule.
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald * Pass-Through Feature (`RewriteRule .. .. [PT]'):
c7d0205ec1649076e7742d72a25ac53779768312stoddard * Because the Apache 1.x API is very limited we
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * need this hack to pass the rewritten URL to other
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald * modules like mod_alias, mod_userdir, etc.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog(r, 2, "forcing '%s' to get passed through "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "to next API URI-to-filename handler", r->filename);
goto loop;
if (p->skip > 0) {
s = p->skip;
p = &entries[i];
p = &entries[i];
return changed;
char *perdir)
char *uri;
char *output;
const char *vary;
char *newuri;
int prefixstrip;
int failed;
int rc;
prefixstrip = 0;
sizeof(regmatch));
failed = 0;
c = &conds[i];
if (rc == 0) {
c = &conds[i];
if (rc == 0) {
if (failed) {
p->forced_mimetype);
reduce_uri(r);
r->filename);
p->forced_mimetype);
char *input;
int rc;
rc = 0;
#if !defined(OS2)
sizeof(regmatch));
return rc;
++outlen;
char *endp;
if (!endp) {
char *key;
if (!key) {
if (dflt) {
if (key) {
++outlen;
p += span;
} while (result);
char *olduri;
if (q != NULL) {
if (qsappend) {
r->filename);
char *cp;
apr_size_t l;
unsigned short port;
++cp;
++cp;
if (!*url) {
const char *thisserver;
char *thisport;
int port;
switch (*uri++) {
char *cp;
return NULL;
++cp;
++cp;
NULL);
#if APR_HAS_USER
char *newuri;
char *homedir;
return newuri;
rewritemap_entry *s;
char *value;
s = &entries[i];
return NULL;
if ((value =
return value;
return NULL;
return NULL;
if ((value =
return value;
return NULL;
if ((value =
return value;
return value;
return NULL;
if ((value =
return NULL;
value);
return value;
return NULL;
char *cpT;
char *curkey;
char *curval;
return NULL;
if (skip == 0) {
++cpT;
if (skip == 0) {
return value;
return value;
#ifndef NO_WRITEV
return NULL;
if (rewrite_mapr_lock_acquire) {
#ifdef NO_WRITEV
buf[i++] = c;
if (rewrite_mapr_lock_acquire) {
return NULL;
cp++) {
return value;
cp++) {
return value;
char *value;
return value;
char *value;
return value;
static int rewrite_rand_init_done = 0;
static void rewrite_rand_init(void)
if (!rewrite_rand_init_done) {
static int rewrite_rand(int l, int h)
char *buf;
return value;
return buf;
const char *fname;
if (!fname) {
!= APR_SUCCESS) {
char *str1;
const char *type;
char *ruser;
const char *rhost;
(unsigned long)(r->server), (unsigned long)r,
return APR_SUCCESS;
APR_LOCK_DEFAULT, p);
return rc;
#ifdef MOD_REWRITE_SET_MUTEX_PERMS
return rc;
return APR_SUCCESS;
return APR_SUCCESS;
return APR_SUCCESS;
return rc;
return APR_SUCCESS;
const char *desc)
!= APR_SUCCESS) ||
procattr, p);
if (fpin) {
if (fpout) {
return (rc);
const char *result;
/* XXX: wow this has gotta be slow if you actually use it for a lot, recalculates exploded time for each variable */
return (char *)result; \
if (val) {
return val;
cache *c;
return NULL;
#if APR_HAS_THREADS
return NULL;
return NULL;
return NULL;
return n % CACHE_TLB_ROWS;
char *key)
for (i=0; i < CACHE_TLB_COLS; ++i) {
return NULL;
return &elt[j];
return NULL;
cacheentry *e)
cachelist *l;
cacheentry *e;
cachetlbentry *t;
int found_list;
#if APR_HAS_THREADS
found_list = 0;
if (e != NULL) {
#if APR_HAS_THREADS
#if APR_HAS_THREADS
if (!found_list) {
sizeof(cachetlbentry));
for (i=0; i<CACHE_TLB_ROWS; ++i) {
for (j=0; j<CACHE_TLB_COLS; ++j)
#if APR_HAS_THREADS
#if APR_HAS_THREADS
cachelist *l;
cacheentry *e;
#if APR_HAS_THREADS
if (e != NULL) {
#if APR_HAS_THREADS
#if APR_HAS_THREADS
#if APR_HAS_THREADS
return NULL;
const char *subst)
--len;
char *output;
++slen;
return output;
return input;
char *cp;
int isquoted;
cp++; \
isquoted = 0; \
cp++; \
cp++; \
char *val;
char *var;
char *val;
char *domain;
char *expires;
char *path;
char *tok_cntx;
char *cookie;
if (expires) {
char *notename;
void *data;
(expires)?
r->request_time +
: NULL,
NULL);
const char *root;
const char *slash;
char *statpath;
for (i = 0; i < n1; i++) {
int depth;
else if (*s == left) {
++depth;
return NULL;
int depth;
return NULL;
else if (*s == left) {
++depth;
return NULL;
{ NULL }