mod_rewrite.c revision 6f2fbf354b34981f398cf0313aa44702ea2a7066
842ae4bd224140319ae7feec1872b93dfd491143fielding/* Licensed to the Apache Software Foundation (ASF) under one or more
842ae4bd224140319ae7feec1872b93dfd491143fielding * contributor license agreements. See the NOTICE file distributed with
842ae4bd224140319ae7feec1872b93dfd491143fielding * this work for additional information regarding copyright ownership.
842ae4bd224140319ae7feec1872b93dfd491143fielding * The ASF licenses this file to You under the Apache License, Version 2.0
842ae4bd224140319ae7feec1872b93dfd491143fielding * (the "License"); you may not use this file except in compliance with
842ae4bd224140319ae7feec1872b93dfd491143fielding * the License. You may obtain a copy of the License at
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * http://www.apache.org/licenses/LICENSE-2.0
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *
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
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * limitations under the License.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/* _ _ _
36a72c96fc2dda27eadbae8a108fa428cc1419c1wrowe * _ __ ___ ___ __| | _ __ _____ ___ __(_) |_ ___
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm * | '_ ` _ \ / _ \ / _` | | '__/ _ \ \ /\ / / '__| | __/ _ \
59b96ad34c087942eea06884c97d12c2796a977amturk * | | | | | | (_) | (_| | | | | __/\ V V /| | | | || __/
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe * |_| |_| |_|\___/ \__,_|___|_| \___| \_/\_/ |_| |_|\__\___|
2555a6b5da21d61804f47084d8fcc98eb4acbc42wrowe * |_____|
2555a6b5da21d61804f47084d8fcc98eb4acbc42wrowe *
70535d6421eb979ac79d8f49d31cd94d75dd8b2fjorton * URL Rewriting Module
2555a6b5da21d61804f47084d8fcc98eb4acbc42wrowe *
2555a6b5da21d61804f47084d8fcc98eb4acbc42wrowe * This module uses a rule-based rewriting engine (based on a
2555a6b5da21d61804f47084d8fcc98eb4acbc42wrowe * regular-expression parser) to rewrite requested URLs on the fly.
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk *
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk * It supports an unlimited number of additional rule conditions (which can
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk * operate on a lot of variables, even on HTTP headers) for granular
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk * matching and even external database lookups (either via plain text
2555a6b5da21d61804f47084d8fcc98eb4acbc42wrowe * tables, DBM hash files or even external processes) for advanced URL
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm * substitution.
e9501b71b8a1e76384cb010b1e41e76a1e47aacctrawick *
e9501b71b8a1e76384cb010b1e41e76a1e47aacctrawick * It operates on the full URLs (including the PATH_INFO part) both in
e9501b71b8a1e76384cb010b1e41e76a1e47aacctrawick * per-server context (httpd.conf) and per-dir context (.htaccess) and even
6335eb31f0f0ed54628a04ed32946360b8b77684minfrin * 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 *
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * This module was originally written in April 1996 and
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * gifted exclusively to the The Apache Software Foundation in July 1997 by
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe *
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * Ralf S. Engelschall
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * rse engelschall.com
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * www.engelschall.com
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include "apr.h"
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include "apr_strings.h"
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include "apr_hash.h"
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include "apr_user.h"
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include "apr_lib.h"
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include "apr_signal.h"
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe#include "apr_global_mutex.h"
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe#include "apr_dbm.h"
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include "apr_dbd.h"
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include "mod_dbd.h"
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#if APR_HAS_THREADS
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include "apr_thread_mutex.h"
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem#endif
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#define APR_WANT_MEMFUNC
9f1a88897168c3f1e5009acb585daf01e38a0299jim#define APR_WANT_STRFUNC
9f1a88897168c3f1e5009acb585daf01e38a0299jim#define APR_WANT_IOVEC
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#include "apr_want.h"
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim/* XXX: Do we really need these headers? */
7af19efc4667363f74d332a8d010b49e88d56fd5trawick#if APR_HAVE_UNISTD_H
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include <unistd.h>
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#endif
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#if APR_HAVE_SYS_TYPES_H
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#include <sys/types.h>
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#endif
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#if APR_HAVE_STDARG_H
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include <stdarg.h>
f251b576aa9caeb8876ce9f78fb10bf65eddc97emturk#endif
f251b576aa9caeb8876ce9f78fb10bf65eddc97emturk#if APR_HAVE_STDLIB_H
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#include <stdlib.h>
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#endif
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#if APR_HAVE_CTYPE_H
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include <ctype.h>
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#endif
0c888b8088644f3a39dcf1998e0304c289532057jim#if APR_HAVE_NETINET_IN_H
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#include <netinet/in.h>
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#endif
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#include "ap_config.h"
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#include "httpd.h"
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include "http_config.h"
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include "http_request.h"
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#include "http_core.h"
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#include "http_log.h"
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include "http_protocol.h"
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include "http_vhost.h"
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#include "util_mutex.h"
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include "mod_ssl.h"
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#include "mod_rewrite.h"
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowestatic ap_dbd_t *(*dbd_acquire)(request_rec*) = NULL;
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowestatic void (*dbd_prepare)(server_rec*, const char*, const char*) = NULL;
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowestatic const char* really_last_key = "rewrite_really_last";
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe/*
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe * in order to improve performance on running production systems, you
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe * may strip all rewritelog code entirely from mod_rewrite by using the
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk * -DREWRITELOG_DISABLED compiler option.
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk *
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk * DO NOT USE THIS OPTION FOR PUBLIC BINARY RELEASES. Otherwise YOU are
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe * responsible for answering all the mod_rewrite questions out there.
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe */
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe/* If logging is limited to APLOG_DEBUG or lower, disable rewrite log, too */
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#ifdef APLOG_MAX_LOGLEVEL
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#if APLOG_MAX_LOGLEVEL < APLOG_TRACE1
9621e4c4056383e4a2b844b14687bae500b33a82wrowe#ifndef REWRITELOG_DISABLED
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem#define REWRITELOG_DISABLED
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#endif
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#endif
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#endif
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem#ifndef REWRITELOG_DISABLED
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem
61d82a1991928d3fa5ee50dc57f2ae3f4b5c781ajim#define rewritelog(x) do_rewritelog x
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define REWRITELOG_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define REWRITELOG_FLAGS ( APR_WRITE | APR_APPEND | APR_CREATE )
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe
4c67ef499845a08771e81254ce6eb2324a160bc7wrowe#else /* !REWRITELOG_DISABLED */
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#define rewritelog(x)
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk
4c67ef499845a08771e81254ce6eb2324a160bc7wrowe#endif /* REWRITELOG_DISABLED */
4c67ef499845a08771e81254ce6eb2324a160bc7wrowe
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe/* remembered mime-type for [T=...] */
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define REWRITE_FORCED_MIMETYPE_NOTEVAR "rewrite-forced-mimetype"
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define REWRITE_FORCED_HANDLER_NOTEVAR "rewrite-forced-handler"
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define ENVVAR_SCRIPT_URL "SCRIPT_URL"
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define REDIRECT_ENVVAR_SCRIPT_URL "REDIRECT_" ENVVAR_SCRIPT_URL
5eb56df4054a0bca4d740eedd7ef277355a2c0adjim#define ENVVAR_SCRIPT_URI "SCRIPT_URI"
5eb56df4054a0bca4d740eedd7ef277355a2c0adjim
5eb56df4054a0bca4d740eedd7ef277355a2c0adjim#define CONDFLAG_NONE 1<<0
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define CONDFLAG_NOCASE 1<<1
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define CONDFLAG_NOTMATCH 1<<2
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define CONDFLAG_ORNEXT 1<<3
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define CONDFLAG_NOVARY 1<<4
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define RULEFLAG_NONE 1<<0
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define RULEFLAG_FORCEREDIRECT 1<<1
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define RULEFLAG_LASTRULE 1<<2
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define RULEFLAG_NEWROUND 1<<3
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define RULEFLAG_CHAIN 1<<4
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define RULEFLAG_IGNOREONSUBREQ 1<<5
41c38e78e8e5dc73544571cc2b749d40869e84fawrowe#define RULEFLAG_NOTMATCH 1<<6
41c38e78e8e5dc73544571cc2b749d40869e84fawrowe#define RULEFLAG_PROXY 1<<7
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define RULEFLAG_PASSTHROUGH 1<<8
41c38e78e8e5dc73544571cc2b749d40869e84fawrowe#define RULEFLAG_QSAPPEND 1<<9
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define RULEFLAG_NOCASE 1<<10
41c38e78e8e5dc73544571cc2b749d40869e84fawrowe#define RULEFLAG_NOESCAPE 1<<11
41c38e78e8e5dc73544571cc2b749d40869e84fawrowe#define RULEFLAG_NOSUB 1<<12
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define RULEFLAG_STATUS 1<<13
e8f95a682820a599fe41b22977010636be5c2717jim#define RULEFLAG_ESCAPEBACKREF 1<<14
b842b65e0618c5535233b197f03dc917d184adb3jim#define RULEFLAG_DISCARDPATHINFO 1<<15
b842b65e0618c5535233b197f03dc917d184adb3jim#define RULEFLAG_QSDISCARD 1<<16
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define RULEFLAG_END 1<<17
b842b65e0618c5535233b197f03dc917d184adb3jim
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim/* return code of the rewrite rule
b842b65e0618c5535233b197f03dc917d184adb3jim * the result may be escaped - or not
b842b65e0618c5535233b197f03dc917d184adb3jim */
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define ACTION_NORMAL 1<<0
b842b65e0618c5535233b197f03dc917d184adb3jim#define ACTION_NOESCAPE 1<<1
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe#define ACTION_STATUS 1<<2
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define MAPTYPE_TXT 1<<0
1d2ff7570139286b0f0d16f92187a16ed5932291mturk#define MAPTYPE_DBM 1<<1
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define MAPTYPE_PRG 1<<2
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe#define MAPTYPE_INT 1<<3
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe#define MAPTYPE_RND 1<<4
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#define MAPTYPE_DBD 1<<5
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#define MAPTYPE_DBD_CACHE 1<<6
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim
1d2ff7570139286b0f0d16f92187a16ed5932291mturk#define ENGINE_DISABLED 1<<0
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define ENGINE_ENABLED 1<<1
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk#define OPTION_NONE 1<<0
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk#define OPTION_INHERIT 1<<1
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk#define OPTION_INHERIT_BEFORE 1<<2
4e0b7720fce1e872ea6afd2421b8b6addacf9bd0jim
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk#ifndef RAND_MAX
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk#define RAND_MAX 32767
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk#endif
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk/* max cookie size in rfc 2109 */
e8f95a682820a599fe41b22977010636be5c2717jim/* XXX: not used at all. We should do a check somewhere and/or cut the cookie */
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk#define MAX_COOKIE_LEN 4096
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk/* max line length (incl.\n) in text rewrite maps */
e8f95a682820a599fe41b22977010636be5c2717jim#ifndef REWRITE_MAX_TXT_MAP_LINE
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk#define REWRITE_MAX_TXT_MAP_LINE 1024
e2b702094817c78498e6de567b9548ef794c33d3jim#endif
4e0b7720fce1e872ea6afd2421b8b6addacf9bd0jim
7ce17736e4802a923eed275812647a7c3e9ad76ejim/* buffer length for prg rewrite maps */
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk#ifndef REWRITE_PRG_MAP_BUF
e8f95a682820a599fe41b22977010636be5c2717jim#define REWRITE_PRG_MAP_BUF 1024
07ac837c886b356dc96e83cf82fb348eb56406d9jim#endif
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim/* for better readbility */
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim#define LEFT_CURLY '{'
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define RIGHT_CURLY '}'
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim/*
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim * expansion result items on the stack to save some cycles
07ac837c886b356dc96e83cf82fb348eb56406d9jim *
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim * (5 == about 2 variables like "foo%{var}bar%{var}baz")
07ac837c886b356dc96e83cf82fb348eb56406d9jim */
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim#define SMALL_EXPANSION 5
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim
07ac837c886b356dc96e83cf82fb348eb56406d9jim/*
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim * check that a subrequest won't cause infinite recursion
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim *
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim * either not in a subrequest, or in a subrequest
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim * and URIs aren't NULL and sub/main URIs differ
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim */
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim#define subreq_ok(r) (!r->main || \
188befd3a49e3a126bd801d7dc5a7f6e63ad4332mturk (r->main->uri && r->uri && strcmp(r->main->uri, r->uri)))
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem
188befd3a49e3a126bd801d7dc5a7f6e63ad4332mturk
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem/*
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem * +-------------------------------------------------------+
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem * | |
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem * | Types and Structures
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim * | |
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim * +-------------------------------------------------------+
188befd3a49e3a126bd801d7dc5a7f6e63ad4332mturk */
f185ce14f5dd540ae54659f764989c017c619485jim
f185ce14f5dd540ae54659f764989c017c619485jimtypedef struct {
f185ce14f5dd540ae54659f764989c017c619485jim const char *datafile; /* filename for map data files */
f185ce14f5dd540ae54659f764989c017c619485jim const char *dbmtype; /* dbm type for dbm map data files */
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim const char *checkfile; /* filename to check for map existence */
f185ce14f5dd540ae54659f764989c017c619485jim const char *cachename; /* for cached maps (txt/rnd/dbm) */
f921cd430a2ea23fcaedfdfc7439163f63c8472arpluem int type; /* the type of the map */
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem apr_file_t *fpin; /* in file pointer for program maps */
f921cd430a2ea23fcaedfdfc7439163f63c8472arpluem apr_file_t *fpout; /* out file pointer for program maps */
f921cd430a2ea23fcaedfdfc7439163f63c8472arpluem apr_file_t *fperr; /* err file pointer for program maps */
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem char *(*func)(request_rec *, /* function pointer for internal maps */
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem char *);
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem char **argv; /* argv of the external rewrite map */
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem const char *dbdq; /* SQL SELECT statement for rewritemap */
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim const char *checkfile2; /* filename to check for map existence
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim NULL if only one file */
f921cd430a2ea23fcaedfdfc7439163f63c8472arpluem} rewritemap_entry;
bf3f3b52289ee37f40842fc836ff92dd202742afpquerna
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim/* special pattern types for RewriteCond */
2f1146e06a1bfa371573a3f3fb0379448e18aaedjimtypedef enum {
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim CONDPAT_REGEX = 0,
bf3f3b52289ee37f40842fc836ff92dd202742afpquerna CONDPAT_FILE_EXISTS,
4415d997ac73262e513c0a571bd5be4f609040bawrowe CONDPAT_FILE_SIZE,
65efbf0826de766a90d745cc44427bfa4e2447b6mturk CONDPAT_FILE_LINK,
4415d997ac73262e513c0a571bd5be4f609040bawrowe CONDPAT_FILE_DIR,
4415d997ac73262e513c0a571bd5be4f609040bawrowe CONDPAT_FILE_XBIT,
4415d997ac73262e513c0a571bd5be4f609040bawrowe CONDPAT_LU_URL,
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe CONDPAT_LU_FILE,
1febae173a82bc2a71c3c0ba4105cf674000791bjim CONDPAT_STR_LT,
1febae173a82bc2a71c3c0ba4105cf674000791bjim CONDPAT_STR_LE,
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe CONDPAT_STR_EQ,
4415d997ac73262e513c0a571bd5be4f609040bawrowe CONDPAT_STR_GT,
4415d997ac73262e513c0a571bd5be4f609040bawrowe CONDPAT_STR_GE,
4415d997ac73262e513c0a571bd5be4f609040bawrowe CONDPAT_INT_LT,
4415d997ac73262e513c0a571bd5be4f609040bawrowe CONDPAT_INT_LE,
4415d997ac73262e513c0a571bd5be4f609040bawrowe CONDPAT_INT_EQ,
4415d997ac73262e513c0a571bd5be4f609040bawrowe CONDPAT_INT_GT,
c3dc78855363fa6e8ecfc2bb8e2927efcd31d31djfclere CONDPAT_INT_GE
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk} pattern_type;
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturktypedef struct {
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk char *input; /* Input string of RewriteCond */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim char *pattern; /* the RegExp pattern string */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim ap_regex_t *regexp; /* the precompiled regexp */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim int flags; /* Flags which control the match */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim pattern_type ptype; /* pattern type */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim int pskip; /* back-index to display pattern */
d20993e12a1caa8952c6d964ed0fbb92b7f97d79jim} rewritecond_entry;
c3dc78855363fa6e8ecfc2bb8e2927efcd31d31djfclere
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim/* single linked list for env vars and cookies */
c3dc78855363fa6e8ecfc2bb8e2927efcd31d31djfcleretypedef struct data_item {
4415d997ac73262e513c0a571bd5be4f609040bawrowe struct data_item *next;
4415d997ac73262e513c0a571bd5be4f609040bawrowe char *data;
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk} data_item;
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturktypedef struct {
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk apr_array_header_t *rewriteconds;/* the corresponding RewriteCond entries */
4415d997ac73262e513c0a571bd5be4f609040bawrowe char *pattern; /* the RegExp pattern string */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim ap_regex_t *regexp; /* the RegExp pattern compilation */
4415d997ac73262e513c0a571bd5be4f609040bawrowe char *output; /* the Substitution string */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim int flags; /* Flags which control the substitution */
4415d997ac73262e513c0a571bd5be4f609040bawrowe char *forced_mimetype; /* forced MIME type of substitution */
4415d997ac73262e513c0a571bd5be4f609040bawrowe char *forced_handler; /* forced content handler of subst. */
4415d997ac73262e513c0a571bd5be4f609040bawrowe int forced_responsecode; /* forced HTTP response status */
4415d997ac73262e513c0a571bd5be4f609040bawrowe data_item *env; /* added environment variables */
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk data_item *cookie; /* added cookies */
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk int skip; /* number of next rules to skip */
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk} rewriterule_entry;
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturktypedef struct {
4415d997ac73262e513c0a571bd5be4f609040bawrowe int state; /* the RewriteEngine state */
4415d997ac73262e513c0a571bd5be4f609040bawrowe int options; /* the RewriteOption state */
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe apr_hash_t *rewritemaps; /* the RewriteMap entries */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim apr_array_header_t *rewriteconds; /* the RewriteCond entries (temp.) */
4415d997ac73262e513c0a571bd5be4f609040bawrowe apr_array_header_t *rewriterules; /* the RewriteRule entries */
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk server_rec *server; /* the corresponding server indicator */
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk int state_set:1;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk int options_set:1;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk} rewrite_server_conf;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk
00b70ae978854b5eb51722cbeda99c9067b5faf2mturktypedef struct {
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk int state; /* the RewriteEngine state */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim int options; /* the RewriteOption state */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim apr_array_header_t *rewriteconds; /* the RewriteCond entries (temp.) */
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk apr_array_header_t *rewriterules; /* the RewriteRule entries */
9e3209bc06ddf32f23e4b254faa45914bc323cc9jim char *directory; /* the directory where it applies */
c332befc1519a1016d8de07608f0b859e6fab580jim const char *baseurl; /* the base-URL where it applies */
5b439d3976ab9363288cf5132902fad230777523jim int state_set:1;
5b439d3976ab9363288cf5132902fad230777523jim int options_set:1;
361051c5d96d51ff2f707777b8f629a56799ef02jorton int baseurl_set:1;
361051c5d96d51ff2f707777b8f629a56799ef02jorton} rewrite_perdir_conf;
5b439d3976ab9363288cf5132902fad230777523jim
5b439d3976ab9363288cf5132902fad230777523jim/* the (per-child) cache structures.
c332befc1519a1016d8de07608f0b859e6fab580jim */
1febae173a82bc2a71c3c0ba4105cf674000791bjimtypedef struct cache {
1febae173a82bc2a71c3c0ba4105cf674000791bjim apr_pool_t *pool;
9e3209bc06ddf32f23e4b254faa45914bc323cc9jim apr_hash_t *maps;
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim#if APR_HAS_THREADS
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim apr_thread_mutex_t *lock;
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim#endif
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim} cache;
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim/* cached maps contain an mtime for the whole map and live in a subpool
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim * of the cachep->pool. That makes it easy to forget them if necessary.
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jimtypedef struct {
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim apr_time_t mtime;
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim apr_pool_t *pool;
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim apr_hash_t *entries;
b92a868b537899a51efd8c200c396fa51c63839dtrawick} cachedmap;
9f22e9ea026e74271ddced44f6d54fa846ddc9bcwrowe
d46dfdce9351f52a971777948d9b02f8fc668ff8niq/* the regex structure for the
d46dfdce9351f52a971777948d9b02f8fc668ff8niq * substitution of backreferences
d46dfdce9351f52a971777948d9b02f8fc668ff8niq */
9f22e9ea026e74271ddced44f6d54fa846ddc9bcwrowetypedef struct backrefinfo {
9f22e9ea026e74271ddced44f6d54fa846ddc9bcwrowe char *source;
d46dfdce9351f52a971777948d9b02f8fc668ff8niq int nsub;
d46dfdce9351f52a971777948d9b02f8fc668ff8niq ap_regmatch_t regmatch[AP_MAX_REG_MATCH];
9f22e9ea026e74271ddced44f6d54fa846ddc9bcwrowe} backrefinfo;
d46dfdce9351f52a971777948d9b02f8fc668ff8niq
d46dfdce9351f52a971777948d9b02f8fc668ff8niq/* single linked list used for
d46dfdce9351f52a971777948d9b02f8fc668ff8niq * variable expansion
3a49a6c98ef80c71830e66e7f8f46083001b494ctrawick */
d46dfdce9351f52a971777948d9b02f8fc668ff8niqtypedef struct result_list {
d46dfdce9351f52a971777948d9b02f8fc668ff8niq struct result_list *next;
b92a868b537899a51efd8c200c396fa51c63839dtrawick apr_size_t len;
d46dfdce9351f52a971777948d9b02f8fc668ff8niq const char *string;
d46dfdce9351f52a971777948d9b02f8fc668ff8niq} result_list;
d46dfdce9351f52a971777948d9b02f8fc668ff8niq
d46dfdce9351f52a971777948d9b02f8fc668ff8niq/* context structure for variable lookup and expansion
d46dfdce9351f52a971777948d9b02f8fc668ff8niq */
a652b68dea502131f70084ead7981d5fc754cd34jimtypedef struct {
a652b68dea502131f70084ead7981d5fc754cd34jim request_rec *r;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim const char *uri;
a652b68dea502131f70084ead7981d5fc754cd34jim const char *vary_this;
a652b68dea502131f70084ead7981d5fc754cd34jim const char *vary;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim char *perdir;
a652b68dea502131f70084ead7981d5fc754cd34jim backrefinfo briRR;
a652b68dea502131f70084ead7981d5fc754cd34jim backrefinfo briRC;
a652b68dea502131f70084ead7981d5fc754cd34jim} rewrite_ctx;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim
a652b68dea502131f70084ead7981d5fc754cd34jim/*
a652b68dea502131f70084ead7981d5fc754cd34jim * +-------------------------------------------------------+
a652b68dea502131f70084ead7981d5fc754cd34jim * | |
a652b68dea502131f70084ead7981d5fc754cd34jim * | static module data
a652b68dea502131f70084ead7981d5fc754cd34jim * | |
a652b68dea502131f70084ead7981d5fc754cd34jim * +-------------------------------------------------------+
a652b68dea502131f70084ead7981d5fc754cd34jim */
a652b68dea502131f70084ead7981d5fc754cd34jim
a652b68dea502131f70084ead7981d5fc754cd34jim/* the global module structure */
4415d997ac73262e513c0a571bd5be4f609040bawrowemodule AP_MODULE_DECLARE_DATA rewrite_module;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
4415d997ac73262e513c0a571bd5be4f609040bawrowe/* rewritemap int: handler function registry */
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowestatic apr_hash_t *mapfunc_hash;
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe/* the cache */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic cache *cachep;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/* whether proxy module is available or not */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic int proxy_available;
00211b036b78699ace57a6d800a52e6c2d57652fnd
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/* whether random seed can be reaped */
00211b036b78699ace57a6d800a52e6c2d57652fndstatic int rewrite_rand_init_done = 0;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard/* Locks/Mutexes */
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddardstatic apr_global_mutex_t *rewrite_mapr_lock_acquire = NULL;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddardconst char *rewritemap_mutex_type = "rewrite-map";
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard/* Optional functions imported from mod_ssl when loaded: */
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddardstatic APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *rewrite_ssl_lookup = NULL;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddardstatic APR_OPTIONAL_FN_TYPE(ssl_is_https) *rewrite_is_https = NULL;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddardstatic char *escape_uri(apr_pool_t *p, const char *path);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard/*
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * +-------------------------------------------------------+
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * | |
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * | rewriting logfile support
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * | |
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * +-------------------------------------------------------+
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#ifndef REWRITELOG_DISABLED
00211b036b78699ace57a6d800a52e6c2d57652fndstatic void do_rewritelog(request_rec *r, int level, char *perdir,
00211b036b78699ace57a6d800a52e6c2d57652fnd const char *fmt, ...)
00211b036b78699ace57a6d800a52e6c2d57652fnd __attribute__((format(printf,4,5)));
00211b036b78699ace57a6d800a52e6c2d57652fnd
00211b036b78699ace57a6d800a52e6c2d57652fndstatic void do_rewritelog(request_rec *r, int level, char *perdir,
00211b036b78699ace57a6d800a52e6c2d57652fnd const char *fmt, ...)
00211b036b78699ace57a6d800a52e6c2d57652fnd{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding char *logline, *text;
50b2d068ddf98cf75622a0020cd143d379d1b235jfclere const char *rhost, *rname;
50b2d068ddf98cf75622a0020cd143d379d1b235jfclere int redir;
50b2d068ddf98cf75622a0020cd143d379d1b235jfclere request_rec *req;
35630e8756729a29273ef1a5c879b90df3594d66rjung va_list ap;
50b2d068ddf98cf75622a0020cd143d379d1b235jfclere
50b2d068ddf98cf75622a0020cd143d379d1b235jfclere if (!APLOG_R_IS_LEVEL(r, APLOG_DEBUG + level))
50b2d068ddf98cf75622a0020cd143d379d1b235jfclere return;
00211b036b78699ace57a6d800a52e6c2d57652fnd
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rhost = ap_get_remote_host(r->connection, r->per_dir_config,
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard REMOTE_NOLOOKUP, NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rname = ap_get_remote_logname(r);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (redir=0, req=r; req->prev; req = req->prev) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ++redir;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding va_start(ap, fmt);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding text = apr_pvsprintf(r->pool, fmt, ap);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding va_end(ap);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding logline = apr_psprintf(r->pool, "%s %s %s [%s/sid#%pp][rid#%pp/%s%s%s] "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "%s%s%s%s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rhost ? rhost : "UNKNOWN-HOST",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rname ? rname : "-",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->user ? (*r->user ? r->user : "\"\"") : "-",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_get_server_name(r),
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding (void *)(r->server),
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding (void *)r,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->main ? "subreq" : "initial",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding redir ? "/redir#" : "",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding redir ? apr_itoa(r->pool, redir) : "",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding perdir ? "[perdir " : "",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding perdir ? perdir : "",
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq perdir ? "] ": "",
a812b025d139f465a31c76fc02ed162ed5271b03nd text);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
16d38ac65d7e54cd44eeda7b23f84ee68b35094ewrowe AP_REWRITE_LOG((uintptr_t)r, level, r->main ? 0 : 1, (char *)ap_get_server_name(r), logline);
16d38ac65d7e54cd44eeda7b23f84ee68b35094ewrowe
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_DEBUG + level, 0, r, "%s", logline);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return;
7b6ba9c468f26bdb3492d5e8cb79628a3b04e8c8wrowe}
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard#endif /* !REWRITELOG_DISABLED */
e8f95a682820a599fe41b22977010636be5c2717jim
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard/*
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * +-------------------------------------------------------+
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * | |
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * | URI and path functions
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * | |
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * +-------------------------------------------------------+
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard/* return number of chars of the scheme (incl. '://')
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * if the URI is absolute (includes a scheme etc.)
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * otherwise 0.
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard *
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * NOTE: If you add new schemes here, please have a
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * look at escape_absolute_uri and splitout_queryargs.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Not every scheme takes query strings and some schemes
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * may be handled in a special way.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * XXX: we may consider a scheme registry, perhaps with
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq * appropriate escape callbacks to allow other modules
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq * to extend mod_rewrite at runtime.
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq */
e99dfd55d29a7b4209b814efc7270d0b74ccee74niqstatic unsigned is_absolute_uri(char *uri)
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq{
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq /* fast exit */
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq if (*uri == '/' || strlen(uri) <= 5) {
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq return 0;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq }
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq switch (*uri++) {
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq case 'a':
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq case 'A':
188befd3a49e3a126bd801d7dc5a7f6e63ad4332mturk if (!strncasecmp(uri, "jp://", 5)) { /* ajp:// */
9df9016759ec9327e256d7fff1af56ddfadb721cniq return 6;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq }
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq break;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
9df9016759ec9327e256d7fff1af56ddfadb721cniq case 'b':
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq case 'B':
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq if (!strncasecmp(uri, "alancer://", 10)) { /* balancer:// */
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq return 11;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq }
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq break;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq case 'f':
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq case 'F':
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq if (!strncasecmp(uri, "tp://", 5)) { /* ftp:// */
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq return 6;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq }
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq if (!strncasecmp(uri, "cgi://", 6)) { /* fcgi:// */
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq return 7;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq }
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq break;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq case 'g':
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq case 'G':
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq if (!strncasecmp(uri, "opher://", 8)) { /* gopher:// */
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq return 9;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq }
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq break;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq case 'h':
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq case 'H':
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq if (!strncasecmp(uri, "ttp://", 6)) { /* http:// */
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq return 7;
997023faa943892aae20d092044aa983c2936982niq }
997023faa943892aae20d092044aa983c2936982niq else if (!strncasecmp(uri, "ttps://", 7)) { /* https:// */
997023faa943892aae20d092044aa983c2936982niq return 8;
997023faa943892aae20d092044aa983c2936982niq }
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq break;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq case 'l':
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'L':
e8ecc839fc57f2157ff10eba188d7aa3c0244174jim if (!strncasecmp(uri, "dap://", 6)) { /* ldap:// */
e8ecc839fc57f2157ff10eba188d7aa3c0244174jim return 7;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
df419be6d7d4b68823efa05722375552af49c2b6minfrin break;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq case 'm':
dcda744296f197717c5105fd197e94ceba7880d7jim case 'M':
28fe44817329b1183f64e878c258962f90423a8dniq if (!strncasecmp(uri, "ailto:", 6)) { /* mailto: */
dcda744296f197717c5105fd197e94ceba7880d7jim return 7;
28fe44817329b1183f64e878c258962f90423a8dniq }
df419be6d7d4b68823efa05722375552af49c2b6minfrin break;
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'n':
e8ecc839fc57f2157ff10eba188d7aa3c0244174jim case 'N':
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (!strncasecmp(uri, "ews:", 4)) { /* news: */
df419be6d7d4b68823efa05722375552af49c2b6minfrin return 5;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin else if (!strncasecmp(uri, "ntp://", 6)) { /* nntp:// */
df419be6d7d4b68823efa05722375552af49c2b6minfrin return 7;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin break;
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 's':
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'S':
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (!strncasecmp(uri, "cgi://", 6)) { /* scgi:// */
df419be6d7d4b68823efa05722375552af49c2b6minfrin return 7;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin break;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin return 0;
df419be6d7d4b68823efa05722375552af49c2b6minfrin}
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrinstatic const char c2x_table[] = "0123456789abcdef";
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrinstatic APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
df419be6d7d4b68823efa05722375552af49c2b6minfrin unsigned char *where)
df419be6d7d4b68823efa05722375552af49c2b6minfrin{
df419be6d7d4b68823efa05722375552af49c2b6minfrin#if APR_CHARSET_EBCDIC
df419be6d7d4b68823efa05722375552af49c2b6minfrin what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
df419be6d7d4b68823efa05722375552af49c2b6minfrin#endif /*APR_CHARSET_EBCDIC*/
df419be6d7d4b68823efa05722375552af49c2b6minfrin *where++ = prefix;
df419be6d7d4b68823efa05722375552af49c2b6minfrin *where++ = c2x_table[what >> 4];
df419be6d7d4b68823efa05722375552af49c2b6minfrin *where++ = c2x_table[what & 0xf];
df419be6d7d4b68823efa05722375552af49c2b6minfrin return where;
df419be6d7d4b68823efa05722375552af49c2b6minfrin}
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin/*
df419be6d7d4b68823efa05722375552af49c2b6minfrin * Escapes a uri in a similar way as php's urlencode does.
df419be6d7d4b68823efa05722375552af49c2b6minfrin * Based on ap_os_escape_path in server/util.c
df419be6d7d4b68823efa05722375552af49c2b6minfrin */
df419be6d7d4b68823efa05722375552af49c2b6minfrinstatic char *escape_uri(apr_pool_t *p, const char *path) {
df419be6d7d4b68823efa05722375552af49c2b6minfrin char *copy = apr_palloc(p, 3 * strlen(path) + 3);
df419be6d7d4b68823efa05722375552af49c2b6minfrin const unsigned char *s = (const unsigned char *)path;
df419be6d7d4b68823efa05722375552af49c2b6minfrin unsigned char *d = (unsigned char *)copy;
df419be6d7d4b68823efa05722375552af49c2b6minfrin unsigned c;
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin while ((c = *s)) {
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (apr_isalnum(c) || c == '_') {
df419be6d7d4b68823efa05722375552af49c2b6minfrin *d++ = c;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin else if (c == ' ') {
df419be6d7d4b68823efa05722375552af49c2b6minfrin *d++ = '+';
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin else {
df419be6d7d4b68823efa05722375552af49c2b6minfrin d = c2x(c, '%', d);
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin ++s;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin *d = '\0';
df419be6d7d4b68823efa05722375552af49c2b6minfrin return copy;
df419be6d7d4b68823efa05722375552af49c2b6minfrin}
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin/*
df419be6d7d4b68823efa05722375552af49c2b6minfrin * escape absolute uri, which may or may not be path oriented.
df419be6d7d4b68823efa05722375552af49c2b6minfrin * So let's handle them differently.
df419be6d7d4b68823efa05722375552af49c2b6minfrin */
df419be6d7d4b68823efa05722375552af49c2b6minfrinstatic char *escape_absolute_uri(apr_pool_t *p, char *uri, unsigned scheme)
df419be6d7d4b68823efa05722375552af49c2b6minfrin{
df419be6d7d4b68823efa05722375552af49c2b6minfrin char *cp;
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin /* be safe.
df419be6d7d4b68823efa05722375552af49c2b6minfrin * NULL should indicate elsewhere, that something's wrong
df419be6d7d4b68823efa05722375552af49c2b6minfrin */
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (!scheme || strlen(uri) < scheme) {
df419be6d7d4b68823efa05722375552af49c2b6minfrin return NULL;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin cp = uri + scheme;
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin /* scheme with authority part? */
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (cp[-1] == '/') {
df419be6d7d4b68823efa05722375552af49c2b6minfrin /* skip host part */
df419be6d7d4b68823efa05722375552af49c2b6minfrin while (*cp && *cp != '/') {
df419be6d7d4b68823efa05722375552af49c2b6minfrin ++cp;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin
a812b025d139f465a31c76fc02ed162ed5271b03nd /* nothing after the hostpart. ready! */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!*cp || !*++cp) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return apr_pstrdup(p, uri);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard /* remember the hostname stuff */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding scheme = cp - uri;
a812b025d139f465a31c76fc02ed162ed5271b03nd
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* special thing for ldap.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * The parts are separated by question marks. From RFC 2255:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * ldapurl = scheme "://" [hostport] ["/"
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * [dn ["?" [attributes] ["?" [scope]
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * ["?" [filter] ["?" extensions]]]]]]
df419be6d7d4b68823efa05722375552af49c2b6minfrin */
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if (!strncasecmp(uri, "ldap", 4)) {
df419be6d7d4b68823efa05722375552af49c2b6minfrin char *token[5];
df419be6d7d4b68823efa05722375552af49c2b6minfrin int c = 0;
e8ecc839fc57f2157ff10eba188d7aa3c0244174jim
df419be6d7d4b68823efa05722375552af49c2b6minfrin token[0] = cp = apr_pstrdup(p, cp);
df419be6d7d4b68823efa05722375552af49c2b6minfrin while (*cp && c < 4) {
28fe44817329b1183f64e878c258962f90423a8dniq if (*cp == '?') {
df419be6d7d4b68823efa05722375552af49c2b6minfrin token[++c] = cp + 1;
28fe44817329b1183f64e878c258962f90423a8dniq *cp = '\0';
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin ++cp;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin return apr_pstrcat(p, apr_pstrndup(p, uri, scheme),
df419be6d7d4b68823efa05722375552af49c2b6minfrin ap_escape_uri(p, token[0]),
df419be6d7d4b68823efa05722375552af49c2b6minfrin (c >= 1) ? "?" : NULL,
e8ecc839fc57f2157ff10eba188d7aa3c0244174jim (c >= 1) ? ap_escape_uri(p, token[1]) : NULL,
df419be6d7d4b68823efa05722375552af49c2b6minfrin (c >= 2) ? "?" : NULL,
df419be6d7d4b68823efa05722375552af49c2b6minfrin (c >= 2) ? ap_escape_uri(p, token[2]) : NULL,
28fe44817329b1183f64e878c258962f90423a8dniq (c >= 3) ? "?" : NULL,
dcda744296f197717c5105fd197e94ceba7880d7jim (c >= 3) ? ap_escape_uri(p, token[3]) : NULL,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding (c >= 4) ? "?" : NULL,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding (c >= 4) ? ap_escape_uri(p, token[4]) : NULL,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
9b3001f2097437c3c605d29e353fda5131b9952bminfrin }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe /* Nothing special here. Apply normal escaping. */
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe return apr_pstrcat(p, apr_pstrndup(p, uri, scheme),
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe ap_escape_uri(p, cp), NULL);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe}
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe/*
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * split out a QUERY_STRING part from
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * the current URI string
e8f95a682820a599fe41b22977010636be5c2717jim */
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddardstatic void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard)
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe{
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe char *q;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
e8f95a682820a599fe41b22977010636be5c2717jim /* don't touch, unless it's an http or mailto URL.
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * See RFC 1738 and RFC 2368.
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe */
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (is_absolute_uri(r->filename)
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe && strncasecmp(r->filename, "ajp", 3)
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe && strncasecmp(r->filename, "balancer", 8)
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe && strncasecmp(r->filename, "http", 4)
e8f95a682820a599fe41b22977010636be5c2717jim && strncasecmp(r->filename, "mailto", 6)) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe r->args = NULL; /* forget the query that's still flying around */
e8f95a682820a599fe41b22977010636be5c2717jim return;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if ( qsdiscard ) {
e8f95a682820a599fe41b22977010636be5c2717jim r->args = NULL; /* Discard query string */
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe rewritelog((r, 2, NULL, "discarding query string"));
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe q = ap_strchr(r->filename, '?');
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (q != NULL) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe char *olduri;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe apr_size_t len;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe olduri = apr_pstrdup(r->pool, r->filename);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe *q++ = '\0';
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (qsappend) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe r->args = apr_pstrcat(r->pool, q, "&", r->args, NULL);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe else {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe r->args = apr_pstrdup(r->pool, q);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
8632261c895a84c88ae6ade6ea4c62b27bd22b3ebrianp
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe len = strlen(r->args);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (!len) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe r->args = NULL;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe else if (r->args[len-1] == '&') {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe r->args[len-1] = '\0';
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe rewritelog((r, 3, NULL, "split uri=%s -> uri=%s, args=%s", olduri,
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe r->filename, r->args ? r->args : "<none>"));
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * strip 'http[s]://ourhost/' from URI
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic void reduce_uri(request_rec *r)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding char *cp;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_size_t l;
68ce856106f153813339db8670f6cd0ab8dea484minfrin
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq cp = (char *)ap_http_scheme(r);
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq l = strlen(cp);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ( strlen(r->filename) > l+3
45dac0729754e413ff7c673481b219e9ab1a11f1bnicholes && strncasecmp(r->filename, cp, l) == 0
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard && r->filename[l] == ':'
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding && r->filename[l+1] == '/'
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe && r->filename[l+2] == '/' ) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding unsigned short port;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq char *portp, *host, *url, *scratch;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq scratch = apr_pstrdup(r->pool, r->filename); /* our scratchpad */
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq /* cut the hostname and port out of the URI */
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq cp = host = scratch + l + 3; /* 3 == strlen("://") */
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq while (*cp && *cp != '/' && *cp != ':') {
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq ++cp;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq }
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq if (*cp == ':') { /* additional port given */
68ce856106f153813339db8670f6cd0ab8dea484minfrin *cp++ = '\0';
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin portp = cp;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard while (*cp && *cp != '/') {
68ce856106f153813339db8670f6cd0ab8dea484minfrin ++cp;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *cp = '\0';
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard port = atoi(portp);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding url = r->filename + (cp - scratch);
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (!*url) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding url = "/";
11c3b5180e1de6776035320b012a28bb146e7b46chuck }
11c3b5180e1de6776035320b012a28bb146e7b46chuck }
11c3b5180e1de6776035320b012a28bb146e7b46chuck else if (*cp == '/') { /* default port */
11c3b5180e1de6776035320b012a28bb146e7b46chuck *cp = '\0';
11c3b5180e1de6776035320b012a28bb146e7b46chuck
11c3b5180e1de6776035320b012a28bb146e7b46chuck port = ap_default_port(r);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding url = r->filename + (cp - scratch);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding port = ap_default_port(r);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding url = "/";
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
d7387fcd4969206172e3a2a8bbcd25a3d7011ac5rbb
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard /* now check whether we could reduce it to a local path... */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (ap_matches_request_vhost(r, host, port)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 3, NULL, "reduce %s -> %s", r->filename, url));
d4a7ca64aa12da0c1b44b0281e93973a89cefeedmartin r->filename = apr_pstrdup(r->pool, url);
d4a7ca64aa12da0c1b44b0281e93973a89cefeedmartin }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * add 'http[s]://ourhost[:ourport]/' to URI
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * if URI is still not fully qualified
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard */
b999f6ba2a266bf9a92687f31bb7e76021ac5891ianhstatic void fully_qualify_uri(request_rec *r)
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard{
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if (r->method_number == M_CONNECT) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm }
1cde33c7e2019830f8fb3224e01649305583916etrawick else if (!is_absolute_uri(r->filename)) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard const char *thisserver;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard char *thisport;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard int port;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding thisserver = ap_get_server_name_for_url(r);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding port = ap_get_server_port(r);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding thisport = ap_is_default_port(port, r)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ? ""
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding : apr_psprintf(r->pool, ":%u", port);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->filename = apr_psprintf(r->pool, "%s://%s%s%s%s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_http_scheme(r), thisserver, thisport,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding (*r->filename == '/') ? "" : "/",
a8523e2451f03f4a30030b7bda643a23a75d91demturk r->filename);
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
5babe00918c88eda487771fa6d6d4a1a19c0ced0chuck return;
5babe00918c88eda487771fa6d6d4a1a19c0ced0chuck}
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/*
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin * stat() only the first segment of a path
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
35c9e4d2c0a6465746a98958ef756114834461e6minfrinstatic int prefix_stat(const char *path, apr_pool_t *pool)
35c9e4d2c0a6465746a98958ef756114834461e6minfrin{
5a5a6c22260854843c973e2ea9a14bec64362ab5wrowe const char *curpath = path;
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe const char *root;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk const char *slash;
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk char *statpath;
11c3b5180e1de6776035320b012a28bb146e7b46chuck apr_status_t rv;
35c9e4d2c0a6465746a98958ef756114834461e6minfrin
45dac0729754e413ff7c673481b219e9ab1a11f1bnicholes rv = apr_filepath_root(&root, &curpath, APR_FILEPATH_TRUENAME, pool);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
11c3b5180e1de6776035320b012a28bb146e7b46chuck if (rv != APR_SUCCESS) {
35c9e4d2c0a6465746a98958ef756114834461e6minfrin return 0;
35c9e4d2c0a6465746a98958ef756114834461e6minfrin }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard /* let's recognize slashes only, the mod_rewrite semantics are opaque
e2b2e15108eb7cb566b1d70ce4e479276d951de5minfrin * enough.
e2b2e15108eb7cb566b1d70ce4e479276d951de5minfrin */
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if ((slash = ap_strchr_c(curpath, '/')) != NULL) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard rv = apr_filepath_merge(&statpath, root,
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard apr_pstrndup(pool, curpath,
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard (apr_size_t)(slash - curpath)),
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard APR_FILEPATH_NOTABOVEROOT |
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard APR_FILEPATH_NOTRELATIVE, pool);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
e2b2e15108eb7cb566b1d70ce4e479276d951de5minfrin else {
e2b2e15108eb7cb566b1d70ce4e479276d951de5minfrin rv = apr_filepath_merge(&statpath, root, curpath,
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard APR_FILEPATH_NOTABOVEROOT |
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard APR_FILEPATH_NOTRELATIVE, pool);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if (rv == APR_SUCCESS) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard apr_finfo_t sb;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e2b2e15108eb7cb566b1d70ce4e479276d951de5minfrin if (apr_stat(&sb, statpath, APR_FINFO_MIN, pool) == APR_SUCCESS) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return 1;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
e2b2e15108eb7cb566b1d70ce4e479276d951de5minfrin
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return 0;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard}
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
35c9e4d2c0a6465746a98958ef756114834461e6minfrin/*
35c9e4d2c0a6465746a98958ef756114834461e6minfrin * substitute the prefix path 'match' in 'input' with 'subst' (RewriteBase)
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard */
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddardstatic char *subst_prefix_path(request_rec *r, char *input, char *match,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *subst)
3d81c6f18deabacd15101eda69f7d16bf466d22dniq{
04d6458a2cd3b44376f00a56804bb6bf6bc46865sf apr_size_t len = strlen(match);
04d6458a2cd3b44376f00a56804bb6bf6bc46865sf
3d81c6f18deabacd15101eda69f7d16bf466d22dniq if (len && match[len - 1] == '/') {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding --len;
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe }
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe
7184de27ec1d62a83c41cdeac0953ca9fd661e8csf if (!strncmp(input, match, len) && input[len++] == '/') {
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe apr_size_t slen, outlen;
e8f95a682820a599fe41b22977010636be5c2717jim char *output;
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe rewritelog((r, 5, NULL, "strip matching prefix: %s -> %s", input,
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe input+len));
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe slen = strlen(subst);
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe if (slen && subst[slen - 1] != '/') {
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe ++slen;
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe }
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe
b5983a3623a081981a69c201fb66f765586aaa9eniq outlen = strlen(input) + slen - len;
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe output = apr_palloc(r->pool, outlen + 1); /* don't forget the \0 */
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe memcpy(output, subst, slen);
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe if (slen && !output[slen-1]) {
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe output[slen-1] = '/';
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe }
e8f95a682820a599fe41b22977010636be5c2717jim memcpy(output+slen, input+len, outlen - slen);
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe output[outlen] = '\0';
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe rewritelog((r, 4, NULL, "add subst prefix: %s -> %s", input+len,
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe output));
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe return output;
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe }
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe /* prefix didn't match */
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe return input;
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe}
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe/*
a8523e2451f03f4a30030b7bda643a23a75d91demturk * +-------------------------------------------------------+
a8523e2451f03f4a30030b7bda643a23a75d91demturk * | |
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk * | caching support
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk * | |
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk * +-------------------------------------------------------+
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk */
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic void set_cache_value(const char *name, apr_time_t t, char *key,
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk char *val)
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk{
a8523e2451f03f4a30030b7bda643a23a75d91demturk cachedmap *map;
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk if (cachep) {
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk#if APR_HAS_THREADS
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk apr_thread_mutex_lock(cachep->lock);
a8523e2451f03f4a30030b7bda643a23a75d91demturk#endif
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk map = apr_hash_get(cachep->maps, name, APR_HASH_KEY_STRING);
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk if (!map) {
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk apr_pool_t *p;
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk if (apr_pool_create(&p, cachep->pool) != APR_SUCCESS) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#if APR_HAS_THREADS
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk apr_thread_mutex_unlock(cachep->lock);
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk#endif
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk map = apr_palloc(cachep->pool, sizeof(cachedmap));
a8523e2451f03f4a30030b7bda643a23a75d91demturk map->pool = p;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk map->entries = apr_hash_make(map->pool);
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk map->mtime = t;
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem apr_hash_set(cachep->maps, name, APR_HASH_KEY_STRING, map);
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem }
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem else if (map->mtime != t) {
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem apr_pool_clear(map->pool);
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem map->entries = apr_hash_make(map->pool);
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem map->mtime = t;
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem }
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem /* Now we should have a valid map->entries hash, where we
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem * can store our value.
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem *
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem * We need to copy the key and the value into OUR pool,
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem * so that we don't leave it during the r->pool cleanup.
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem */
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem apr_hash_set(map->entries,
6a4043fd04bbd44ca0d084c096318df035abc46djfclere apr_pstrdup(map->pool, key), APR_HASH_KEY_STRING,
6a4043fd04bbd44ca0d084c096318df035abc46djfclere apr_pstrdup(map->pool, val));
6a4043fd04bbd44ca0d084c096318df035abc46djfclere
14c8c18e6caab1bdeb0f26b2b031e000fef58ef9jim#if APR_HAS_THREADS
6a4043fd04bbd44ca0d084c096318df035abc46djfclere apr_thread_mutex_unlock(cachep->lock);
6a4043fd04bbd44ca0d084c096318df035abc46djfclere#endif
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim }
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk return;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk}
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk
00b70ae978854b5eb51722cbeda99c9067b5faf2mturkstatic char *get_cache_value(const char *name, apr_time_t t, char *key,
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk apr_pool_t *p)
b1306729566b49fb30aed5c46adaf07a637115afjerenkrantz{
b1306729566b49fb30aed5c46adaf07a637115afjerenkrantz cachedmap *map;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk char *val = NULL;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk if (cachep) {
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk#if APR_HAS_THREADS
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk apr_thread_mutex_lock(cachep->lock);
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk#endif
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk map = apr_hash_get(cachep->maps, name, APR_HASH_KEY_STRING);
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk if (map) {
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk /* if this map is outdated, forget it. */
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk if (map->mtime != t) {
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk apr_pool_clear(map->pool);
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk map->entries = apr_hash_make(map->pool);
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem map->mtime = t;
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem }
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem else {
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem val = apr_hash_get(map->entries, key, APR_HASH_KEY_STRING);
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem if (val) {
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem /* copy the cached value into the supplied pool,
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem * where it belongs (r->pool usually)
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem */
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem val = apr_pstrdup(p, val);
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem }
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem }
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem }
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem#if APR_HAS_THREADS
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem apr_thread_mutex_unlock(cachep->lock);
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem#endif
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem }
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem return val;
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem}
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem
5fbd1e97905738791e7359ccbc9b02e913948d2erpluemstatic int init_cache(apr_pool_t *p)
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem{
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem cachep = apr_palloc(p, sizeof(cache));
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem if (apr_pool_create(&cachep->pool, p) != APR_SUCCESS) {
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem cachep = NULL; /* turns off cache */
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem return 0;
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem }
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem cachep->maps = apr_hash_make(cachep->pool);
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem#if APR_HAS_THREADS
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem (void)apr_thread_mutex_create(&(cachep->lock), APR_THREAD_MUTEX_DEFAULT, p);
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem#endif
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk return 1;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard}
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin/*
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk * +-------------------------------------------------------+
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk * | |
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk * | Map Functions
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk * | |
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk * +-------------------------------------------------------+
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk */
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk/*
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk * General Note: key is already a fresh string, created (expanded) just
a42b70fa75429d73ef00d6ae212676f8a652f51cpquerna * for the purpose to be passed in here. So one can modify key itself.
a8523e2451f03f4a30030b7bda643a23a75d91demturk */
a8523e2451f03f4a30030b7bda643a23a75d91demturk
a8523e2451f03f4a30030b7bda643a23a75d91demturkstatic char *rewrite_mapfunc_toupper(request_rec *r, char *key)
a8523e2451f03f4a30030b7bda643a23a75d91demturk{
a8523e2451f03f4a30030b7bda643a23a75d91demturk char *p;
a8523e2451f03f4a30030b7bda643a23a75d91demturk
a8523e2451f03f4a30030b7bda643a23a75d91demturk for (p = key; *p; ++p) {
a8523e2451f03f4a30030b7bda643a23a75d91demturk *p = apr_toupper(*p);
a8523e2451f03f4a30030b7bda643a23a75d91demturk }
12d1342bd29aa7b15080f28cd8ed65d33ce00328rpluem
a8523e2451f03f4a30030b7bda643a23a75d91demturk return key;
12d1342bd29aa7b15080f28cd8ed65d33ce00328rpluem}
12d1342bd29aa7b15080f28cd8ed65d33ce00328rpluem
00b70ae978854b5eb51722cbeda99c9067b5faf2mturkstatic char *rewrite_mapfunc_tolower(request_rec *r, char *key)
a8523e2451f03f4a30030b7bda643a23a75d91demturk{
a8523e2451f03f4a30030b7bda643a23a75d91demturk ap_str_tolower(key);
a8523e2451f03f4a30030b7bda643a23a75d91demturk
e8f95a682820a599fe41b22977010636be5c2717jim return key;
a8523e2451f03f4a30030b7bda643a23a75d91demturk}
a8523e2451f03f4a30030b7bda643a23a75d91demturk
a8523e2451f03f4a30030b7bda643a23a75d91demturkstatic char *rewrite_mapfunc_escape(request_rec *r, char *key)
a8523e2451f03f4a30030b7bda643a23a75d91demturk{
12d1342bd29aa7b15080f28cd8ed65d33ce00328rpluem return ap_escape_uri(r->pool, key);
a8523e2451f03f4a30030b7bda643a23a75d91demturk}
a8523e2451f03f4a30030b7bda643a23a75d91demturk
a8523e2451f03f4a30030b7bda643a23a75d91demturkstatic char *rewrite_mapfunc_unescape(request_rec *r, char *key)
a8523e2451f03f4a30030b7bda643a23a75d91demturk{
a8523e2451f03f4a30030b7bda643a23a75d91demturk ap_unescape_url(key);
a8523e2451f03f4a30030b7bda643a23a75d91demturk
a8523e2451f03f4a30030b7bda643a23a75d91demturk return key;
a8523e2451f03f4a30030b7bda643a23a75d91demturk}
a8523e2451f03f4a30030b7bda643a23a75d91demturk
a8523e2451f03f4a30030b7bda643a23a75d91demturkstatic char *select_random_value_part(request_rec *r, char *value)
a8523e2451f03f4a30030b7bda643a23a75d91demturk{
e8f95a682820a599fe41b22977010636be5c2717jim char *p = value;
67d13599fd4a5f73a2d3fc2b566a9aad60b1c892mturk unsigned n = 1;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin /* count number of distinct values */
1cde33c7e2019830f8fb3224e01649305583916etrawick while ((p = ap_strchr(p, '|')) != NULL) {
6bdb2c094666367615890147775bb18761216c8dminfrin ++n;
6bdb2c094666367615890147775bb18761216c8dminfrin ++p;
6bdb2c094666367615890147775bb18761216c8dminfrin }
6bdb2c094666367615890147775bb18761216c8dminfrin
0280926d9c3e5deb48961117a60a817d6905dd3dniq if (n > 1) {
c1c0628ca9788908a5fc7502d04a89c348b75ee6wrowe /* initialize random generator
9865751743e928ea0a9ad83faa04a738001932deminfrin *
c1c0628ca9788908a5fc7502d04a89c348b75ee6wrowe * XXX: Probably this should be wrapped into a thread mutex,
d9efe39afed3db4bbdc32e40ddb67075c56e689djim * shouldn't it? Is it worth the effort?
bda7a7d57377f45932c237d5aba00b189d85c2a9ianh */
bda7a7d57377f45932c237d5aba00b189d85c2a9ianh if (!rewrite_rand_init_done) {
a42b70fa75429d73ef00d6ae212676f8a652f51cpquerna srand((unsigned)(getpid()));
bda7a7d57377f45932c237d5aba00b189d85c2a9ianh rewrite_rand_init_done = 1;
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* select a random subvalue */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding n = (int)(((double)(rand() % RAND_MAX) / RAND_MAX) * n + 1);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* extract it from the whole string */
11c3b5180e1de6776035320b012a28bb146e7b46chuck while (--n && (value = ap_strchr(value, '|')) != NULL) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ++value;
fd61dbd57eb4ee63c3c647c178979ed817d13be3jim }
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe if (value) { /* should not be NULL, but ... */
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe p = ap_strchr(value, '|');
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe if (p) {
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe *p = '\0';
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe }
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe }
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe }
5a5a6c22260854843c973e2ea9a14bec64362ab5wrowe
609ecc54ccbd06a9286e1aaf891f80f62450b1aamturk return value;
a865e849a3b00dc8524ecdda09a1699452876219mturk}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
fd61dbd57eb4ee63c3c647c178979ed817d13be3jim/* child process code */
d993198d8a18c11aa4e80bc647587df10e663f88jimstatic void rewrite_child_errfn(apr_pool_t *p, apr_status_t err,
fd61dbd57eb4ee63c3c647c178979ed817d13be3jim const char *desc)
d993198d8a18c11aa4e80bc647587df10e663f88jim{
fd61dbd57eb4ee63c3c647c178979ed817d13be3jim ap_log_error(APLOG_MARK, APLOG_ERR, err, NULL, "%s", desc);
d993198d8a18c11aa4e80bc647587df10e663f88jim}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
af952917c05e56874069e1e5f64e6473bb478b68minfrinstatic apr_status_t rewritemap_program_child(apr_pool_t *p,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *progname, char **argv,
7ce40500bfead8781bab964eb6e01944acbf3915jim apr_file_t **fpout,
7ce40500bfead8781bab964eb6e01944acbf3915jim apr_file_t **fpin)
7ce40500bfead8781bab964eb6e01944acbf3915jim{
af952917c05e56874069e1e5f64e6473bb478b68minfrin apr_status_t rc;
af952917c05e56874069e1e5f64e6473bb478b68minfrin apr_procattr_t *procattr;
af952917c05e56874069e1e5f64e6473bb478b68minfrin apr_proc_t *procnew;
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin if ( APR_SUCCESS == (rc=apr_procattr_create(&procattr, p))
35c9e4d2c0a6465746a98958ef756114834461e6minfrin && APR_SUCCESS == (rc=apr_procattr_io_set(procattr, APR_FULL_BLOCK,
35c9e4d2c0a6465746a98958ef756114834461e6minfrin APR_FULL_BLOCK, APR_NO_PIPE))
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim && APR_SUCCESS == (rc=apr_procattr_dir_set(procattr,
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim ap_make_dirstr_parent(p, argv[0])))
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim && APR_SUCCESS == (rc=apr_procattr_cmdtype_set(procattr, APR_PROGRAM))
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim && APR_SUCCESS == (rc=apr_procattr_child_errfn_set(procattr,
b2b9b7f0644773b50aee41956a841ac884086250niq rewrite_child_errfn))
b2b9b7f0644773b50aee41956a841ac884086250niq && APR_SUCCESS == (rc=apr_procattr_error_check_set(procattr, 1))) {
c4d7b5c09544149ad4585a13b7e6a4b943d135c8mturk
e8f95a682820a599fe41b22977010636be5c2717jim procnew = apr_pcalloc(p, sizeof(*procnew));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rc = apr_proc_create(procnew, argv[0], (const char **)argv, NULL,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding procattr, p);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
af952917c05e56874069e1e5f64e6473bb478b68minfrin if (rc == APR_SUCCESS) {
af952917c05e56874069e1e5f64e6473bb478b68minfrin apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe
af952917c05e56874069e1e5f64e6473bb478b68minfrin if (fpin) {
af952917c05e56874069e1e5f64e6473bb478b68minfrin (*fpin) = procnew->in;
af952917c05e56874069e1e5f64e6473bb478b68minfrin }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (fpout) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe (*fpout) = procnew->out;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe }
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe
609ecc54ccbd06a9286e1aaf891f80f62450b1aamturk return (rc);
a865e849a3b00dc8524ecdda09a1699452876219mturk}
af952917c05e56874069e1e5f64e6473bb478b68minfrin
af952917c05e56874069e1e5f64e6473bb478b68minfrinstatic apr_status_t run_rewritemap_programs(server_rec *s, apr_pool_t *p)
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim{
af952917c05e56874069e1e5f64e6473bb478b68minfrin rewrite_server_conf *conf;
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq apr_hash_index_t *hi;
af952917c05e56874069e1e5f64e6473bb478b68minfrin apr_status_t rc;
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq
7ce40500bfead8781bab964eb6e01944acbf3915jim conf = ap_get_module_config(s->module_config, &rewrite_module);
7ce40500bfead8781bab964eb6e01944acbf3915jim
7ce40500bfead8781bab964eb6e01944acbf3915jim /* If the engine isn't turned on,
af952917c05e56874069e1e5f64e6473bb478b68minfrin * don't even try to do anything.
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq */
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin if (conf->state == ENGINE_DISABLED) {
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq return APR_SUCCESS;
35c9e4d2c0a6465746a98958ef756114834461e6minfrin }
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq
35630e8756729a29273ef1a5c879b90df3594d66rjung for (hi = apr_hash_first(p, conf->rewritemaps); hi; hi = apr_hash_next(hi)){
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq apr_file_t *fpin = NULL;
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim apr_file_t *fpout = NULL;
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq rewritemap_entry *map;
00dd9a5a2b0c1f507c332b918ea390f9c1fa991cmturk void *val;
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq
b2b9b7f0644773b50aee41956a841ac884086250niq apr_hash_this(hi, NULL, NULL, &val);
b2b9b7f0644773b50aee41956a841ac884086250niq map = val;
c4d7b5c09544149ad4585a13b7e6a4b943d135c8mturk
af952917c05e56874069e1e5f64e6473bb478b68minfrin if (map->type != MAPTYPE_PRG) {
af952917c05e56874069e1e5f64e6473bb478b68minfrin continue;
b2b9b7f0644773b50aee41956a841ac884086250niq }
b2b9b7f0644773b50aee41956a841ac884086250niq if (!(map->argv[0]) || !*(map->argv[0]) || map->fpin || map->fpout) {
b2b9b7f0644773b50aee41956a841ac884086250niq continue;
b2b9b7f0644773b50aee41956a841ac884086250niq }
b2b9b7f0644773b50aee41956a841ac884086250niq
b2b9b7f0644773b50aee41956a841ac884086250niq rc = rewritemap_program_child(p, map->argv[0], map->argv,
b2b9b7f0644773b50aee41956a841ac884086250niq &fpout, &fpin);
b2b9b7f0644773b50aee41956a841ac884086250niq if (rc != APR_SUCCESS || fpin == NULL || fpout == NULL) {
b2b9b7f0644773b50aee41956a841ac884086250niq ap_log_error(APLOG_MARK, APLOG_ERR, rc, s,
b2b9b7f0644773b50aee41956a841ac884086250niq "mod_rewrite: could not start RewriteMap "
b2b9b7f0644773b50aee41956a841ac884086250niq "program %s", map->checkfile);
b2b9b7f0644773b50aee41956a841ac884086250niq return rc;
b2b9b7f0644773b50aee41956a841ac884086250niq }
b2b9b7f0644773b50aee41956a841ac884086250niq map->fpin = fpin;
b2b9b7f0644773b50aee41956a841ac884086250niq map->fpout = fpout;
b2b9b7f0644773b50aee41956a841ac884086250niq }
b2b9b7f0644773b50aee41956a841ac884086250niq
b2b9b7f0644773b50aee41956a841ac884086250niq return APR_SUCCESS;
af952917c05e56874069e1e5f64e6473bb478b68minfrin}
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe/*
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * +-------------------------------------------------------+
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * | |
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * | Lookup functions
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * | |
f86b4df17588d404f3da535a8054f43b0642f92aniq * +-------------------------------------------------------+
f86b4df17588d404f3da535a8054f43b0642f92aniq */
f86b4df17588d404f3da535a8054f43b0642f92aniq
f86b4df17588d404f3da535a8054f43b0642f92aniqstatic char *lookup_map_txtfile(request_rec *r, const char *file, char *key)
f86b4df17588d404f3da535a8054f43b0642f92aniq{
f86b4df17588d404f3da535a8054f43b0642f92aniq apr_file_t *fp = NULL;
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf char line[REWRITE_MAX_TXT_MAP_LINE + 1]; /* +1 for \0 */
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf char *value, *keylast;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq apr_status_t rv;
40b22d3b20454959fe51fdc89907908d77701078minfrin
40b22d3b20454959fe51fdc89907908d77701078minfrin if ((rv = apr_file_open(&fp, file, APR_READ|APR_BUFFERED, APR_OS_DEFAULT,
93cf7fc650197b941ae31a7c7e51e901b129e954igalic r->pool)) != APR_SUCCESS)
f86b4df17588d404f3da535a8054f43b0642f92aniq {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe "mod_rewrite: can't open text RewriteMap file %s", file);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe return NULL;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe keylast = key + strlen(key);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe value = NULL;
0b4d5285b176f443fd6c0fb07bef76f6b5eb81c7niq while (apr_file_gets(line, sizeof(line), fp) == APR_SUCCESS) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe char *p, *c;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe /* ignore comments and lines starting with whitespaces */
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (*line == '#' || apr_isspace(*line)) {
f86b4df17588d404f3da535a8054f43b0642f92aniq continue;
f86b4df17588d404f3da535a8054f43b0642f92aniq }
0b4d5285b176f443fd6c0fb07bef76f6b5eb81c7niq
f86b4df17588d404f3da535a8054f43b0642f92aniq p = line;
0b4d5285b176f443fd6c0fb07bef76f6b5eb81c7niq c = key;
f86b4df17588d404f3da535a8054f43b0642f92aniq while (c < keylast && *p == *c && !apr_isspace(*p)) {
0b4d5285b176f443fd6c0fb07bef76f6b5eb81c7niq ++p;
f86b4df17588d404f3da535a8054f43b0642f92aniq ++c;
f86b4df17588d404f3da535a8054f43b0642f92aniq }
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq /* key doesn't match - ignore. */
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf if (c != keylast || !apr_isspace(*p)) {
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf continue;
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf }
40b22d3b20454959fe51fdc89907908d77701078minfrin
40b22d3b20454959fe51fdc89907908d77701078minfrin /* jump to the value */
40b22d3b20454959fe51fdc89907908d77701078minfrin while (*p && apr_isspace(*p)) {
df419be6d7d4b68823efa05722375552af49c2b6minfrin ++p;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
93cf7fc650197b941ae31a7c7e51e901b129e954igalic
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe /* no value? ignore */
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (!*p) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe continue;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
9379749d811388a7d0e3410940ddd6743a33d330jim /* extract the value and return. */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding c = p;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding while (*p && !apr_isspace(*p)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ++p;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding value = apr_pstrmemdup(r->pool, c, p - c);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding break;
3c59b18ce62f97468aaa5951d4e21a5478ef36ecminfrin }
ef5650b61a8e35f3cc93ec07e73efc17ea329894jorton apr_file_close(fp);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return value;
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb}
3c59b18ce62f97468aaa5951d4e21a5478ef36ecminfrin
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbbstatic char *lookup_map_dbmfile(request_rec *r, const char *file,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *dbmtype, char *key)
3c59b18ce62f97468aaa5951d4e21a5478ef36ecminfrin{
9379749d811388a7d0e3410940ddd6743a33d330jim apr_dbm_t *dbmfp = NULL;
9379749d811388a7d0e3410940ddd6743a33d330jim apr_datum_t dbmkey;
9379749d811388a7d0e3410940ddd6743a33d330jim apr_datum_t dbmval;
9379749d811388a7d0e3410940ddd6743a33d330jim char *value;
3c59b18ce62f97468aaa5951d4e21a5478ef36ecminfrin apr_status_t rv;
3c59b18ce62f97468aaa5951d4e21a5478ef36ecminfrin
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if ((rv = apr_dbm_open_ex(&dbmfp, dbmtype, file, APR_DBM_READONLY,
3c59b18ce62f97468aaa5951d4e21a5478ef36ecminfrin APR_OS_DEFAULT, r->pool)) != APR_SUCCESS)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
9379749d811388a7d0e3410940ddd6743a33d330jim "mod_rewrite: can't open DBM RewriteMap %s", file);
9379749d811388a7d0e3410940ddd6743a33d330jim return NULL;
9379749d811388a7d0e3410940ddd6743a33d330jim }
9379749d811388a7d0e3410940ddd6743a33d330jim
9379749d811388a7d0e3410940ddd6743a33d330jim dbmkey.dptr = key;
9379749d811388a7d0e3410940ddd6743a33d330jim dbmkey.dsize = strlen(key);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (apr_dbm_fetch(dbmfp, dbmkey, &dbmval) == APR_SUCCESS && dbmval.dptr) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding value = apr_pstrmemdup(r->pool, dbmval.dptr, dbmval.dsize);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else {
9379749d811388a7d0e3410940ddd6743a33d330jim value = NULL;
ef5650b61a8e35f3cc93ec07e73efc17ea329894jorton }
9379749d811388a7d0e3410940ddd6743a33d330jim
9379749d811388a7d0e3410940ddd6743a33d330jim apr_dbm_close(dbmfp);
9379749d811388a7d0e3410940ddd6743a33d330jim
9379749d811388a7d0e3410940ddd6743a33d330jim return value;
9379749d811388a7d0e3410940ddd6743a33d330jim}
65efbf0826de766a90d745cc44427bfa4e2447b6mturkstatic char *lookup_map_dbd(request_rec *r, char *key, const char *label)
65efbf0826de766a90d745cc44427bfa4e2447b6mturk{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_status_t rv;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_dbd_prepared_t *stmt;
24efed0910118b762a4eb84830875d4714b8d315ianh const char *errmsg;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_dbd_results_t *res = NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_dbd_row_t *row = NULL;
066877f1a045103acfdd376d48cdd473c33f409bdougm const char *ret = NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding int n = 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_dbd_t *db = dbd_acquire(r);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding stmt = apr_hash_get(db->prepared, label, APR_HASH_KEY_STRING);
9379749d811388a7d0e3410940ddd6743a33d330jim
9379749d811388a7d0e3410940ddd6743a33d330jim rv = apr_dbd_pvselect(db->driver, r->pool, db->handle, &res,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding stmt, 0, key, NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (rv != 0) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding errmsg = apr_dbd_error(db->driver, db->handle, rv);
9379749d811388a7d0e3410940ddd6743a33d330jim ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
9379749d811388a7d0e3410940ddd6743a33d330jim "rewritemap: error %s querying for %s", errmsg, key);
9379749d811388a7d0e3410940ddd6743a33d330jim return NULL;
9379749d811388a7d0e3410940ddd6743a33d330jim }
9379749d811388a7d0e3410940ddd6743a33d330jim while (rv = apr_dbd_get_row(db->driver, r->pool, res, &row, -1), rv == 0) {
9379749d811388a7d0e3410940ddd6743a33d330jim ++n;
9379749d811388a7d0e3410940ddd6743a33d330jim if (ret == NULL) {
9379749d811388a7d0e3410940ddd6743a33d330jim ret = apr_dbd_get_entry(db->driver, row, 0);
9379749d811388a7d0e3410940ddd6743a33d330jim }
9379749d811388a7d0e3410940ddd6743a33d330jim else {
9379749d811388a7d0e3410940ddd6743a33d330jim /* randomise crudely amongst multiple results */
9379749d811388a7d0e3410940ddd6743a33d330jim if ((double)rand() < (double)RAND_MAX/(double)n) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ret = apr_dbd_get_entry(db->driver, row, 0);
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (rv != -1) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding errmsg = apr_dbd_error(db->driver, db->handle, rv);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "rewritemap: error %s looking up %s", errmsg, key);
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe }
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe switch (n) {
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe case 0:
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe return NULL;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe case 1:
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe return apr_pstrdup(r->pool, ret);
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe default:
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim /* what's a fair rewritelog level for this? */
28fe44817329b1183f64e878c258962f90423a8dniq rewritelog((r, 3, NULL, "Multiple values found for %s", key));
b588214d6e6fe09abe709e83e894921fbc7e25c8covener return apr_pstrdup(r->pool, ret);
b588214d6e6fe09abe709e83e894921fbc7e25c8covener }
b588214d6e6fe09abe709e83e894921fbc7e25c8covener}
14c8c18e6caab1bdeb0f26b2b031e000fef58ef9jim
b588214d6e6fe09abe709e83e894921fbc7e25c8covenerstatic char *lookup_map_program(request_rec *r, apr_file_t *fpin,
b588214d6e6fe09abe709e83e894921fbc7e25c8covener apr_file_t *fpout, char *key)
e8f95a682820a599fe41b22977010636be5c2717jim{
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe char *buf;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe char c;
dcda744296f197717c5105fd197e94ceba7880d7jim apr_size_t i, nbytes, combined_len = 0;
dcda744296f197717c5105fd197e94ceba7880d7jim apr_status_t rv;
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim const char *eol = APR_EOL_STR;
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim apr_size_t eolc = 0;
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim int found_nl = 0;
dcda744296f197717c5105fd197e94ceba7880d7jim result_list *buflist = NULL, *curbuf = NULL;
dcda744296f197717c5105fd197e94ceba7880d7jim
dcda744296f197717c5105fd197e94ceba7880d7jim#ifndef NO_WRITEV
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe struct iovec iova[2];
dcda744296f197717c5105fd197e94ceba7880d7jim apr_size_t niov;
28fe44817329b1183f64e878c258962f90423a8dniq#endif
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe
28fe44817329b1183f64e878c258962f90423a8dniq /* when `RewriteEngine off' was used in the per-server
28fe44817329b1183f64e878c258962f90423a8dniq * context then the rewritemap-programs were not spawned.
28fe44817329b1183f64e878c258962f90423a8dniq * In this case using such a map (usually in per-dir context)
28fe44817329b1183f64e878c258962f90423a8dniq * is useless because it is not available.
997023faa943892aae20d092044aa983c2936982niq *
997023faa943892aae20d092044aa983c2936982niq * newlines in the key leave bytes in the pipe and cause
997023faa943892aae20d092044aa983c2936982niq * bad things to happen (next map lookup will use the chars
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe * after the \n instead of the new key etc etc - in other words,
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe * the Rewritemap falls out of sync with the requests).
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe */
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem if (fpin == NULL || fpout == NULL || ap_strchr(key, '\n')) {
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem return NULL;
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim }
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem /* take the lock */
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem if (rewrite_mapr_lock_acquire) {
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim rv = apr_global_mutex_lock(rewrite_mapr_lock_acquire);
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem if (rv != APR_SUCCESS) {
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem "apr_global_mutex_lock(rewrite_mapr_lock_acquire) "
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem "failed");
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim return NULL; /* Maybe this should be fatal? */
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem }
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem }
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe /* write out the request key */
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe#ifdef NO_WRITEV
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe nbytes = strlen(key);
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe apr_file_write(fpin, key, &nbytes);
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe nbytes = 1;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe apr_file_write(fpin, "\n", &nbytes);
df419be6d7d4b68823efa05722375552af49c2b6minfrin#else
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim iova[0].iov_base = key;
df419be6d7d4b68823efa05722375552af49c2b6minfrin iova[0].iov_len = strlen(key);
df419be6d7d4b68823efa05722375552af49c2b6minfrin iova[1].iov_base = "\n";
df419be6d7d4b68823efa05722375552af49c2b6minfrin iova[1].iov_len = 1;
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin niov = 2;
df419be6d7d4b68823efa05722375552af49c2b6minfrin apr_file_writev(fpin, iova, niov, &nbytes);
df419be6d7d4b68823efa05722375552af49c2b6minfrin#endif
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin buf = apr_palloc(r->pool, REWRITE_PRG_MAP_BUF + 1);
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin /* read in the response value */
df419be6d7d4b68823efa05722375552af49c2b6minfrin nbytes = 1;
df419be6d7d4b68823efa05722375552af49c2b6minfrin apr_file_read(fpout, &c, &nbytes);
df419be6d7d4b68823efa05722375552af49c2b6minfrin do {
df419be6d7d4b68823efa05722375552af49c2b6minfrin i = 0;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe while (nbytes == 1 && (i < REWRITE_PRG_MAP_BUF)) {
75b0a6a06ca1f4de80e3dd2a09c9f0c7d0a56089wrowe if (c == eol[eolc]) {
75b0a6a06ca1f4de80e3dd2a09c9f0c7d0a56089wrowe if (!eol[++eolc]) {
28fe44817329b1183f64e878c258962f90423a8dniq /* remove eol from the buffer */
dcda744296f197717c5105fd197e94ceba7880d7jim --eolc;
dcda744296f197717c5105fd197e94ceba7880d7jim if (i < eolc) {
dcda744296f197717c5105fd197e94ceba7880d7jim curbuf->len -= eolc-i;
dcda744296f197717c5105fd197e94ceba7880d7jim i = 0;
dcda744296f197717c5105fd197e94ceba7880d7jim }
dcda744296f197717c5105fd197e94ceba7880d7jim else {
dcda744296f197717c5105fd197e94ceba7880d7jim i -= eolc;
dcda744296f197717c5105fd197e94ceba7880d7jim }
dcda744296f197717c5105fd197e94ceba7880d7jim ++found_nl;
efddae96ddb58b8604704137a9221d7dc61868b0mturk break;
efddae96ddb58b8604704137a9221d7dc61868b0mturk }
e8f95a682820a599fe41b22977010636be5c2717jim }
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe /* only partial (invalid) eol sequence -> reset the counter */
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq else if (eolc) {
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim eolc = 0;
5a5a6c22260854843c973e2ea9a14bec64362ab5wrowe }
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim /* catch binary mode, e.g. on Win32 */
4415d997ac73262e513c0a571bd5be4f609040bawrowe else if (c == '\n') {
de274dca1be855ebb66bb7857951aae26fcb54c7wrowe ++found_nl;
e8f95a682820a599fe41b22977010636be5c2717jim break;
4415d997ac73262e513c0a571bd5be4f609040bawrowe }
1febae173a82bc2a71c3c0ba4105cf674000791bjim
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe buf[i++] = c;
4415d997ac73262e513c0a571bd5be4f609040bawrowe apr_file_read(fpout, &c, &nbytes);
de274dca1be855ebb66bb7857951aae26fcb54c7wrowe }
4415d997ac73262e513c0a571bd5be4f609040bawrowe
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe /* well, if there wasn't a newline yet, we need to read further */
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe if (buflist || (nbytes == 1 && !found_nl)) {
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim if (!buflist) {
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung curbuf = buflist = apr_palloc(r->pool, sizeof(*buflist));
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe }
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim else if (i) {
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe curbuf->next = apr_palloc(r->pool, sizeof(*buflist));
de274dca1be855ebb66bb7857951aae26fcb54c7wrowe curbuf = curbuf->next;
0c4b0ffd3db7ae8e34662826098b5e46dadc1e88jim
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung }
7ba381d8371d632d25ba1256a9047fe601cb984djfclere curbuf->next = NULL;
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung
acfed915e00d4d0ca436b388b93610ceccd58a64minfrin if (i) {
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung curbuf->string = buf;
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim curbuf->len = i;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe combined_len += i;
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe buf = apr_palloc(r->pool, REWRITE_PRG_MAP_BUF);
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe }
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung if (nbytes == 1 && !found_nl) {
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung i = 0;
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim continue;
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung }
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung }
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung break;
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung } while (1);
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe /* concat the stuff */
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe if (buflist) {
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe char *p;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding p = buf = apr_palloc(r->pool, combined_len + 1); /* \0 */
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim while (buflist) {
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim if (buflist->len) {
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim memcpy(p, buflist->string, buflist->len);
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim p += buflist->len;
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim }
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim buflist = buflist->next;
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim }
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim *p = '\0';
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim i = combined_len;
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim }
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim else {
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim buf[i] = '\0';
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim }
997023faa943892aae20d092044aa983c2936982niq
997023faa943892aae20d092044aa983c2936982niq /* give the lock back */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (rewrite_mapr_lock_acquire) {
f86b4df17588d404f3da535a8054f43b0642f92aniq rv = apr_global_mutex_unlock(rewrite_mapr_lock_acquire);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (rv != APR_SUCCESS) {
997023faa943892aae20d092044aa983c2936982niq ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
997023faa943892aae20d092044aa983c2936982niq "apr_global_mutex_unlock(rewrite_mapr_lock_acquire) "
997023faa943892aae20d092044aa983c2936982niq "failed");
b588214d6e6fe09abe709e83e894921fbc7e25c8covener return NULL; /* Maybe this should be fatal? */
b588214d6e6fe09abe709e83e894921fbc7e25c8covener }
b588214d6e6fe09abe709e83e894921fbc7e25c8covener }
14c8c18e6caab1bdeb0f26b2b031e000fef58ef9jim
b588214d6e6fe09abe709e83e894921fbc7e25c8covener /* catch the "failed" case */
b588214d6e6fe09abe709e83e894921fbc7e25c8covener if (i == 4 && !strcasecmp(buf, "NULL")) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return NULL;
997023faa943892aae20d092044aa983c2936982niq }
997023faa943892aae20d092044aa983c2936982niq
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return buf;
997023faa943892aae20d092044aa983c2936982niq}
ea64665b1de60d55641104e018f696c4a310d2f1jim
ea64665b1de60d55641104e018f696c4a310d2f1jim/*
ea64665b1de60d55641104e018f696c4a310d2f1jim * generic map lookup
997023faa943892aae20d092044aa983c2936982niq */
997023faa943892aae20d092044aa983c2936982niqstatic char *lookup_map(request_rec *r, char *name, char *key)
997023faa943892aae20d092044aa983c2936982niq{
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard rewrite_server_conf *conf;
997023faa943892aae20d092044aa983c2936982niq rewritemap_entry *s;
ea64665b1de60d55641104e018f696c4a310d2f1jim char *value;
ea64665b1de60d55641104e018f696c4a310d2f1jim apr_finfo_t st;
997023faa943892aae20d092044aa983c2936982niq apr_status_t rv;
529005244758297d4415aa912c67a67f805349bcianh
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard /* get map configuration */
997023faa943892aae20d092044aa983c2936982niq conf = ap_get_module_config(r->server->module_config, &rewrite_module);
997023faa943892aae20d092044aa983c2936982niq s = apr_hash_get(conf->rewritemaps, name, APR_HASH_KEY_STRING);
997023faa943892aae20d092044aa983c2936982niq
997023faa943892aae20d092044aa983c2936982niq /* map doesn't exist */
997023faa943892aae20d092044aa983c2936982niq if (!s) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
997023faa943892aae20d092044aa983c2936982niq
997023faa943892aae20d092044aa983c2936982niq switch (s->type) {
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq /*
f86b4df17588d404f3da535a8054f43b0642f92aniq * Text file map (perhaps random)
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq */
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq case MAPTYPE_RND:
a812b025d139f465a31c76fc02ed162ed5271b03nd case MAPTYPE_TXT:
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq rv = apr_stat(&st, s->checkfile, APR_FINFO_MIN, r->pool);
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq if (rv != APR_SUCCESS) {
997023faa943892aae20d092044aa983c2936982niq ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
a812b025d139f465a31c76fc02ed162ed5271b03nd "mod_rewrite: can't access text RewriteMap file %s",
a812b025d139f465a31c76fc02ed162ed5271b03nd s->checkfile);
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq return NULL;
997023faa943892aae20d092044aa983c2936982niq }
997023faa943892aae20d092044aa983c2936982niq
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq value = get_cache_value(s->cachename, st.mtime, key, r->pool);
f86b4df17588d404f3da535a8054f43b0642f92aniq if (!value) {
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq rewritelog((r, 6, NULL,
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq "cache lookup FAILED, forcing new map lookup"));
a812b025d139f465a31c76fc02ed162ed5271b03nd
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq value = lookup_map_txtfile(r, s->datafile, key);
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq if (!value) {
997023faa943892aae20d092044aa983c2936982niq rewritelog((r, 5, NULL, "map lookup FAILED: map=%s[txt] key=%s",
a812b025d139f465a31c76fc02ed162ed5271b03nd name, key));
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq set_cache_value(s->cachename, st.mtime, key, "");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return NULL;
11c3b5180e1de6776035320b012a28bb146e7b46chuck }
11c3b5180e1de6776035320b012a28bb146e7b46chuck
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 5, NULL,"map lookup OK: map=%s[txt] key=%s -> val=%s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding name, key, value));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding set_cache_value(s->cachename, st.mtime, key, value);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r,5,NULL,"cache lookup OK: map=%s[txt] key=%s -> val=%s",
a6314dfa8dd8a0d69db16288581e4950a2dd3955minfrin name, key, value));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (s->type == MAPTYPE_RND && *value) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding value = select_random_value_part(r, value);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 5, NULL, "randomly chosen the subvalue `%s'",value));
edc346c3223efd41e6a2057c37cea69744b73dccwrowe }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return *value ? value : NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * DBM file map
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard */
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard case MAPTYPE_DBM:
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard rv = apr_stat(&st, s->checkfile, APR_FINFO_MIN, r->pool);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if (rv != APR_SUCCESS) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard "mod_rewrite: can't access DBM RewriteMap file %s",
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard s->checkfile);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else if(s->checkfile2 != NULL) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_finfo_t st2;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rv = apr_stat(&st2, s->checkfile2, APR_FINFO_MIN, r->pool);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (rv != APR_SUCCESS) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "mod_rewrite: can't access DBM RewriteMap "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "file %s", s->checkfile2);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
11c3b5180e1de6776035320b012a28bb146e7b46chuck else if(st2.mtime > st.mtime) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding st.mtime = st2.mtime;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if(rv != APR_SUCCESS) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding value = get_cache_value(s->cachename, st.mtime, key, r->pool);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!value) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 6, NULL,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "cache lookup FAILED, forcing new map lookup"));
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard value = lookup_map_dbmfile(r, s->datafile, s->dbmtype, key);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!value) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 5, NULL, "map lookup FAILED: map=%s[dbm] key=%s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding name, key));
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard set_cache_value(s->cachename, st.mtime, key, "");
11c3b5180e1de6776035320b012a28bb146e7b46chuck return NULL;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
65efbf0826de766a90d745cc44427bfa4e2447b6mturk rewritelog((r, 5, NULL, "map lookup OK: map=%s[dbm] key=%s -> "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "val=%s", name, key, value));
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk set_cache_value(s->cachename, st.mtime, key, value);
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk return value;
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
65efbf0826de766a90d745cc44427bfa4e2447b6mturk rewritelog((r, 5, NULL, "cache lookup OK: map=%s[dbm] key=%s -> val=%s",
65efbf0826de766a90d745cc44427bfa4e2447b6mturk name, key, value));
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk return *value ? value : NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk /*
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk * SQL map without cache
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard case MAPTYPE_DBD:
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard value = lookup_map_dbd(r, key, s->dbdq);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if (!value) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 5, NULL, "SQL map lookup FAILED: map %s key=%s",
1cde33c7e2019830f8fb3224e01649305583916etrawick name, key));
407cde44becba3694e7c3d81ac99b5d86f4b03a9rbb return NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard rewritelog((r, 5, NULL, "SQL map lookup OK: map %s key=%s, val=%s",
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard name, key, value));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return value;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard /*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * SQL map with cache
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding case MAPTYPE_DBD_CACHE:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding value = get_cache_value(s->cachename, 0, key, r->pool);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!value) {
11c3b5180e1de6776035320b012a28bb146e7b46chuck rewritelog((r, 6, NULL,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "cache lookup FAILED, forcing new map lookup"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding value = lookup_map_dbd(r, key, s->dbdq);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!value) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 5, NULL, "SQL map lookup FAILED: map %s key=%s",
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard name, key));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding set_cache_value(s->cachename, 0, key, "");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 5, NULL, "SQL map lookup OK: map %s key=%s, val=%s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding name, key, value));
11c3b5180e1de6776035320b012a28bb146e7b46chuck
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding set_cache_value(s->cachename, 0, key, value);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return value;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 5, NULL, "cache lookup OK: map=%s[SQL] key=%s, val=%s",
af952917c05e56874069e1e5f64e6473bb478b68minfrin name, key, value));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return *value ? value : NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
609ecc54ccbd06a9286e1aaf891f80f62450b1aamturk /*
ff1234e45aca1b8171d711ecb87f58b9d9100a99ianh * Program file map
40b22d3b20454959fe51fdc89907908d77701078minfrin */
ff1234e45aca1b8171d711ecb87f58b9d9100a99ianh case MAPTYPE_PRG:
40b22d3b20454959fe51fdc89907908d77701078minfrin value = lookup_map_program(r, s->fpin, s->fpout, key);
ff1234e45aca1b8171d711ecb87f58b9d9100a99ianh if (!value) {
40b22d3b20454959fe51fdc89907908d77701078minfrin rewritelog((r, 5,NULL,"map lookup FAILED: map=%s key=%s", name,
40b22d3b20454959fe51fdc89907908d77701078minfrin key));
ff1234e45aca1b8171d711ecb87f58b9d9100a99ianh return NULL;
ff1234e45aca1b8171d711ecb87f58b9d9100a99ianh }
93cf7fc650197b941ae31a7c7e51e901b129e954igalic
93cf7fc650197b941ae31a7c7e51e901b129e954igalic rewritelog((r, 5, NULL, "map lookup OK: map=%s key=%s -> val=%s",
93cf7fc650197b941ae31a7c7e51e901b129e954igalic name, key, value));
93cf7fc650197b941ae31a7c7e51e901b129e954igalic return value;
93cf7fc650197b941ae31a7c7e51e901b129e954igalic
93cf7fc650197b941ae31a7c7e51e901b129e954igalic /*
93cf7fc650197b941ae31a7c7e51e901b129e954igalic * Internal Map
fd3fa792f04fc9c4e8f5f83dceb0fc34e71f8570ianh */
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf case MAPTYPE_INT:
fd3fa792f04fc9c4e8f5f83dceb0fc34e71f8570ianh value = s->func(r, key);
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf if (!value) {
fd3fa792f04fc9c4e8f5f83dceb0fc34e71f8570ianh rewritelog((r, 5,NULL,"map lookup FAILED: map=%s key=%s", name,
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf key));
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf return NULL;
fd3fa792f04fc9c4e8f5f83dceb0fc34e71f8570ianh }
fd3fa792f04fc9c4e8f5f83dceb0fc34e71f8570ianh
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 5, NULL, "map lookup OK: map=%s key=%s -> val=%s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding name, key, value));
11c3b5180e1de6776035320b012a28bb146e7b46chuck return value;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard/*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * lookup a HTTP header and set VARY note
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic const char *lookup_header(const char *name, rewrite_ctx *ctx)
af952917c05e56874069e1e5f64e6473bb478b68minfrin{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *val = apr_table_get(ctx->r->headers_in, name);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (val) {
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin ctx->vary_this = ctx->vary_this
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin ? apr_pstrcat(ctx->r->pool, ctx->vary_this, ", ",
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin name, NULL)
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin : apr_pstrdup(ctx->r->pool, name);
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin }
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin
5eb56df4054a0bca4d740eedd7ef277355a2c0adjim return val;
5eb56df4054a0bca4d740eedd7ef277355a2c0adjim}
5eb56df4054a0bca4d740eedd7ef277355a2c0adjim
5eb56df4054a0bca4d740eedd7ef277355a2c0adjim/*
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin * lookahead helper function
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin * Determine the correct URI path in perdir context
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin */
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrinstatic APR_INLINE const char *la_u(rewrite_ctx *ctx)
35c9e4d2c0a6465746a98958ef756114834461e6minfrin{
35c9e4d2c0a6465746a98958ef756114834461e6minfrin rewrite_perdir_conf *conf;
35c9e4d2c0a6465746a98958ef756114834461e6minfrin
35c9e4d2c0a6465746a98958ef756114834461e6minfrin if (*ctx->uri == '/') {
35c9e4d2c0a6465746a98958ef756114834461e6minfrin return ctx->uri;
35c9e4d2c0a6465746a98958ef756114834461e6minfrin }
35c9e4d2c0a6465746a98958ef756114834461e6minfrin
35c9e4d2c0a6465746a98958ef756114834461e6minfrin conf = ap_get_module_config(ctx->r->per_dir_config, &rewrite_module);
35c9e4d2c0a6465746a98958ef756114834461e6minfrin
35c9e4d2c0a6465746a98958ef756114834461e6minfrin return apr_pstrcat(ctx->r->pool, conf->baseurl
35c9e4d2c0a6465746a98958ef756114834461e6minfrin ? conf->baseurl : conf->directory,
4224d5789080ea5586d49420da1e1996f5653bb5ianh ctx->uri, NULL);
4224d5789080ea5586d49420da1e1996f5653bb5ianh}
4224d5789080ea5586d49420da1e1996f5653bb5ianh
4224d5789080ea5586d49420da1e1996f5653bb5ianh/*
4224d5789080ea5586d49420da1e1996f5653bb5ianh * generic variable lookup
4224d5789080ea5586d49420da1e1996f5653bb5ianh */
4224d5789080ea5586d49420da1e1996f5653bb5ianhstatic char *lookup_variable(char *var, rewrite_ctx *ctx)
35630e8756729a29273ef1a5c879b90df3594d66rjung{
4224d5789080ea5586d49420da1e1996f5653bb5ianh const char *result;
4224d5789080ea5586d49420da1e1996f5653bb5ianh request_rec *r = ctx->r;
4224d5789080ea5586d49420da1e1996f5653bb5ianh apr_size_t varlen = strlen(var);
35630e8756729a29273ef1a5c879b90df3594d66rjung
35630e8756729a29273ef1a5c879b90df3594d66rjung /* fast exit */
4224d5789080ea5586d49420da1e1996f5653bb5ianh if (varlen < 4) {
e8f95a682820a599fe41b22977010636be5c2717jim return apr_pstrdup(r->pool, "");
4224d5789080ea5586d49420da1e1996f5653bb5ianh }
35c9e4d2c0a6465746a98958ef756114834461e6minfrin
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding result = NULL;
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* fast tests for variable length variables (sic) first */
11c3b5180e1de6776035320b012a28bb146e7b46chuck if (var[3] == ':') {
11c3b5180e1de6776035320b012a28bb146e7b46chuck if (var[4] && !strncasecmp(var, "ENV", 3)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding var += 4;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding result = apr_table_get(r->notes, var);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!result) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding result = apr_table_get(r->subprocess_env, var);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!result) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding result = getenv(var);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard else if (var[4] && !strncasecmp(var, "SSL", 3) && rewrite_ssl_lookup) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard result = rewrite_ssl_lookup(r->pool, r->server, r->connection, r,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding var + 4);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
af952917c05e56874069e1e5f64e6473bb478b68minfrin }
e8f95a682820a599fe41b22977010636be5c2717jim else if (var[4] == ':') {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (var[5]) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding request_rec *rr;
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim const char *path;
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim if (!strncasecmp(var, "HTTP", 4)) {
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim result = lookup_header(var+5, ctx);
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim }
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim else if (!strncasecmp(var, "LA-U", 4)) {
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim if (ctx->uri && subreq_ok(r)) {
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim path = ctx->perdir ? la_u(ctx) : ctx->uri;
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim rr = ap_sub_req_lookup_uri(path, r, NULL);
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim ctx->r = rr;
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim result = apr_pstrdup(r->pool, lookup_variable(var+5, ctx));
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim ctx->r = r;
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim ap_destroy_sub_req(rr);
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim rewritelog((r, 5, ctx->perdir, "lookahead: path=%s var=%s "
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim "-> val=%s", path, var+5, result));
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim return (char *)result;
e8f95a682820a599fe41b22977010636be5c2717jim }
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim }
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim else if (!strncasecmp(var, "LA-F", 4)) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (ctx->uri && subreq_ok(r)) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe path = ctx->uri;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (ctx->perdir && *path == '/') {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe /* sigh, the user wants a file based subrequest, but
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe * we can't do one, since we don't know what the file
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe * path is! In this case behave like LA-U.
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe */
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe rr = ap_sub_req_lookup_uri(path, r, NULL);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe else {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (ctx->perdir) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe rewrite_perdir_conf *conf;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe conf = ap_get_module_config(r->per_dir_config,
6c05afd314b4ddd545d63b4ff5de822cc30eec79trawick &rewrite_module);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe path = apr_pstrcat(r->pool, conf->directory, path,
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe NULL);
e8f95a682820a599fe41b22977010636be5c2717jim }
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe rr = ap_sub_req_lookup_file(path, r, NULL);
7ce40500bfead8781bab964eb6e01944acbf3915jim }
7ce40500bfead8781bab964eb6e01944acbf3915jim
7ce40500bfead8781bab964eb6e01944acbf3915jim ctx->r = rr;
7ce40500bfead8781bab964eb6e01944acbf3915jim result = apr_pstrdup(r->pool, lookup_variable(var+5, ctx));
7ce40500bfead8781bab964eb6e01944acbf3915jim ctx->r = r;
7ce40500bfead8781bab964eb6e01944acbf3915jim ap_destroy_sub_req(rr);
7ce40500bfead8781bab964eb6e01944acbf3915jim
7ce40500bfead8781bab964eb6e01944acbf3915jim rewritelog((r, 5, ctx->perdir, "lookahead: path=%s var=%s "
7ce40500bfead8781bab964eb6e01944acbf3915jim "-> val=%s", path, var+5, result));
7ce40500bfead8781bab964eb6e01944acbf3915jim
7ce40500bfead8781bab964eb6e01944acbf3915jim return (char *)result;
7ce40500bfead8781bab964eb6e01944acbf3915jim }
7ce40500bfead8781bab964eb6e01944acbf3915jim }
7ce40500bfead8781bab964eb6e01944acbf3915jim }
7ce40500bfead8781bab964eb6e01944acbf3915jim }
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe /* well, do it the hard way */
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe else {
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe char *p;
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe apr_time_exp_t tm;
5a5a6c22260854843c973e2ea9a14bec64362ab5wrowe
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe /* can't do this above, because of the getenv call */
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe for (p = var; *p; ++p) {
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe *p = apr_toupper(*p);
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe }
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe switch (varlen) {
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe case 4:
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung if (!strcmp(var, "TIME")) {
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe apr_time_exp_lt(&tm, apr_time_now());
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim result = apr_psprintf(r->pool, "%04d%02d%02d%02d%02d%02d",
e8f95a682820a599fe41b22977010636be5c2717jim tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe tm.tm_hour, tm.tm_min, tm.tm_sec);
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe rewritelog((r, 1, ctx->perdir, "RESULT='%s'", result));
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere return (char *)result;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe }
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere else if (!strcmp(var, "IPV6")) {
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe int flag = FALSE;
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere#if APR_HAVE_IPV6
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere apr_sockaddr_t *addr = r->connection->remote_addr;
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere flag = (addr->family == AF_INET6 &&
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere !IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr->ipaddr_ptr));
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere rewritelog((r, 1, ctx->perdir, "IPV6='%s'", flag ? "on" : "off"));
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere#else
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere rewritelog((r, 1, ctx->perdir, "IPV6='off' (IPv6 is not enabled)"));
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere#endif
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe result = (flag ? "on" : "off");
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe }
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe break;
433dc2d5dae74ed067db6175010ff973d02511e9jerenkrantz
433dc2d5dae74ed067db6175010ff973d02511e9jerenkrantz case 5:
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere if (!strcmp(var, "HTTPS")) {
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere int flag = rewrite_is_https && rewrite_is_https(r->connection);
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere return apr_pstrdup(r->pool, flag ? "on" : "off");
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe }
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe break;
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe case 8:
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe switch (var[6]) {
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe case 'A':
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe if (!strcmp(var, "TIME_DAY")) {
e8f95a682820a599fe41b22977010636be5c2717jim apr_time_exp_lt(&tm, apr_time_now());
65efbf0826de766a90d745cc44427bfa4e2447b6mturk return apr_psprintf(r->pool, "%02d", tm.tm_mday);
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe }
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim break;
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim case 'E':
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim if (!strcmp(var, "TIME_SEC")) {
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim apr_time_exp_lt(&tm, apr_time_now());
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim return apr_psprintf(r->pool, "%02d", tm.tm_sec);
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim }
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim break;
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim case 'I':
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe if (!strcmp(var, "TIME_MIN")) {
0c4b0ffd3db7ae8e34662826098b5e46dadc1e88jim apr_time_exp_lt(&tm, apr_time_now());
0c4b0ffd3db7ae8e34662826098b5e46dadc1e88jim return apr_psprintf(r->pool, "%02d", tm.tm_min);
0c4b0ffd3db7ae8e34662826098b5e46dadc1e88jim }
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim break;
e8f95a682820a599fe41b22977010636be5c2717jim
0c4b0ffd3db7ae8e34662826098b5e46dadc1e88jim case 'O':
0c4b0ffd3db7ae8e34662826098b5e46dadc1e88jim if (!strcmp(var, "TIME_MON")) {
0c4b0ffd3db7ae8e34662826098b5e46dadc1e88jim apr_time_exp_lt(&tm, apr_time_now());
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung return apr_psprintf(r->pool, "%02d", tm.tm_mon+1);
7ba381d8371d632d25ba1256a9047fe601cb984djfclere }
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung break;
acfed915e00d4d0ca436b388b93610ceccd58a64minfrin }
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung break;
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe case 9:
e8f95a682820a599fe41b22977010636be5c2717jim switch (var[7]) {
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe case 'A':
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe if (var[8] == 'Y' && !strcmp(var, "TIME_WDAY")) {
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe apr_time_exp_lt(&tm, apr_time_now());
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung return apr_psprintf(r->pool, "%d", tm.tm_wday);
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung }
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung else if (!strcmp(var, "TIME_YEAR")) {
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim apr_time_exp_lt(&tm, apr_time_now());
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung return apr_psprintf(r->pool, "%04d", tm.tm_year+1900);
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim }
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung break;
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung case 'E':
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung if (!strcmp(var, "IS_SUBREQ")) {
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe result = (r->main ? "true" : "false");
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim }
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe break;
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe case 'F':
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (!strcmp(var, "PATH_INFO")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk result = r->path_info;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 'P':
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (!strcmp(var, "AUTH_TYPE")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk result = r->ap_auth_type;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
fef95ce9cdb638443693c21f181dd2494b467469mturk case 'S':
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (!strcmp(var, "HTTP_HOST")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk result = lookup_header("Host", ctx);
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 'U':
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (!strcmp(var, "TIME_HOUR")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk apr_time_exp_lt(&tm, apr_time_now());
65efbf0826de766a90d745cc44427bfa4e2447b6mturk return apr_psprintf(r->pool, "%02d", tm.tm_hour);
9738b63e3d24b2856b1b6a12fcddcbf325f26d4bnd }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk break;
fef95ce9cdb638443693c21f181dd2494b467469mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 11:
65efbf0826de766a90d745cc44427bfa4e2447b6mturk switch (var[8]) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 'A':
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (!strcmp(var, "SERVER_NAME")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk result = ap_get_server_name(r);
e8f95a682820a599fe41b22977010636be5c2717jim }
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 'D':
fef95ce9cdb638443693c21f181dd2494b467469mturk if (*var == 'R' && !strcmp(var, "REMOTE_ADDR")) {
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim result = r->connection->remote_ip;
fef95ce9cdb638443693c21f181dd2494b467469mturk }
fef95ce9cdb638443693c21f181dd2494b467469mturk else if (!strcmp(var, "SERVER_ADDR")) {
fef95ce9cdb638443693c21f181dd2494b467469mturk result = r->connection->local_ip;
fef95ce9cdb638443693c21f181dd2494b467469mturk }
fef95ce9cdb638443693c21f181dd2494b467469mturk break;
fef95ce9cdb638443693c21f181dd2494b467469mturk
fef95ce9cdb638443693c21f181dd2494b467469mturk case 'E':
e8f95a682820a599fe41b22977010636be5c2717jim if (*var == 'H' && !strcmp(var, "HTTP_ACCEPT")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk result = lookup_header("Accept", ctx);
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim else if (!strcmp(var, "THE_REQUEST")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk result = r->the_request;
fef95ce9cdb638443693c21f181dd2494b467469mturk }
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim break;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim
fef95ce9cdb638443693c21f181dd2494b467469mturk case 'I':
fef95ce9cdb638443693c21f181dd2494b467469mturk if (!strcmp(var, "API_VERSION")) {
fef95ce9cdb638443693c21f181dd2494b467469mturk return apr_psprintf(r->pool, "%d:%d",
fef95ce9cdb638443693c21f181dd2494b467469mturk MODULE_MAGIC_NUMBER_MAJOR,
fef95ce9cdb638443693c21f181dd2494b467469mturk MODULE_MAGIC_NUMBER_MINOR);
fef95ce9cdb638443693c21f181dd2494b467469mturk }
fef95ce9cdb638443693c21f181dd2494b467469mturk break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 'K':
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (!strcmp(var, "HTTP_COOKIE")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk result = lookup_header("Cookie", ctx);
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 'O':
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (*var == 'S' && !strcmp(var, "SERVER_PORT")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk return apr_psprintf(r->pool, "%u", ap_get_server_port(r));
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk else if (var[7] == 'H' && !strcmp(var, "REMOTE_HOST")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk result = ap_get_remote_host(r->connection,r->per_dir_config,
65efbf0826de766a90d745cc44427bfa4e2447b6mturk REMOTE_NAME, NULL);
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
1febae173a82bc2a71c3c0ba4105cf674000791bjim else if (!strcmp(var, "REMOTE_PORT")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk return apr_itoa(r->pool, r->connection->remote_addr->port);
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
c332befc1519a1016d8de07608f0b859e6fab580jim break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 'S':
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (*var == 'R' && !strcmp(var, "REMOTE_USER")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk result = r->user;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe else if (!strcmp(var, "SCRIPT_USER")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = "<unknown>";
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (r->finfo.valid & APR_FINFO_USER) {
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk apr_uid_name_get((char **)&result, r->finfo.user,
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe r->pool);
e8f95a682820a599fe41b22977010636be5c2717jim }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 'U':
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (!strcmp(var, "REQUEST_URI")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = r->uri;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
ef5650b61a8e35f3cc93ec07e73efc17ea329894jorton case 12:
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe switch (var[3]) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk case 'I':
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk if (!strcmp(var, "SCRIPT_GROUP")) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk result = "<unknown>";
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (r->finfo.valid & APR_FINFO_GROUP) {
bdf8801c51d958b1d3ff40f60ab16ccfd999b0fawrowe apr_gid_name_get((char **)&result, r->finfo.group,
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk r->pool);
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 'O':
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (!strcmp(var, "REMOTE_IDENT")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = ap_get_remote_logname(r);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 'P':
35630e8756729a29273ef1a5c879b90df3594d66rjung if (!strcmp(var, "HTTP_REFERER")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = lookup_header("Referer", ctx);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 'R':
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (!strcmp(var, "QUERY_STRING")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = r->args;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 'V':
52489511342e4ff3fe399e57f29d38e5c4227bc8trawick if (!strcmp(var, "SERVER_ADMIN")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = r->server->server_admin;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
e8f95a682820a599fe41b22977010636be5c2717jim break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 13:
ef5650b61a8e35f3cc93ec07e73efc17ea329894jorton if (!strcmp(var, "DOCUMENT_ROOT")) {
e6c244ee56578707b20a86e0e938498299a93b6cnd result = ap_document_root(r);
e6c244ee56578707b20a86e0e938498299a93b6cnd }
e6c244ee56578707b20a86e0e938498299a93b6cnd break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 14:
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if (*var == 'H' && !strcmp(var, "HTTP_FORWARDED")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = lookup_header("Forwarded", ctx);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe else if (!strcmp(var, "REQUEST_METHOD")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = r->method;
ef5650b61a8e35f3cc93ec07e73efc17ea329894jorton }
e6c244ee56578707b20a86e0e938498299a93b6cnd break;
e6c244ee56578707b20a86e0e938498299a93b6cnd
e6c244ee56578707b20a86e0e938498299a93b6cnd case 15:
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe switch (var[7]) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 'E':
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (!strcmp(var, "HTTP_USER_AGENT")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = lookup_header("User-Agent", ctx);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 'F':
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if (!strcmp(var, "SCRIPT_FILENAME")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = r->filename; /* same as request_filename (16) */
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
9a806b671337b22acf6418e60a83f6bbeabdf771wrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 'P':
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (!strcmp(var, "SERVER_PROTOCOL")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = r->protocol;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk break;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk case 'S':
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk if (!strcmp(var, "SERVER_SOFTWARE")) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk result = ap_get_server_banner();
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
7033ee56ea894e9b3fdf573ab9960149a4e88a11jorton break;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk break;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim case 16:
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk if (!strcmp(var, "REQUEST_FILENAME")) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk result = r->filename; /* same as script_filename (15) */
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim }
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim break;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk case 21:
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk if (!strcmp(var, "HTTP_PROXY_CONNECTION")) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk result = lookup_header("Proxy-Connection", ctx);
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk break;
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim return apr_pstrdup(r->pool, result ? result : "");
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim}
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk/*
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk * +-------------------------------------------------------+
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk * | |
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk * | Expansion functions
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk * | |
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk * +-------------------------------------------------------+
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk */
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk/*
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk * Bracketed expression handling
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk * s points after the opening bracket
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk */
144f8db798e3b92e4e4a3f51904e8f21ad160680mturkstatic APR_INLINE char *find_closing_curly(char *s)
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk{
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk unsigned depth;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk for (depth = 1; *s; ++s) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk if (*s == RIGHT_CURLY && --depth == 0) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk return s;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk else if (*s == LEFT_CURLY) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk ++depth;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk return NULL;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe}
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowestatic APR_INLINE char *find_char_in_curlies(char *s, int c)
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe{
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe unsigned depth;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe for (depth = 1; *s; ++s) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (*s == c && depth == 1) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return s;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
e8f95a682820a599fe41b22977010636be5c2717jim else if (*s == RIGHT_CURLY && --depth == 0) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe return NULL;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe else if (*s == LEFT_CURLY) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe ++depth;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb }
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb
9379749d811388a7d0e3410940ddd6743a33d330jim return NULL;
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb}
9379749d811388a7d0e3410940ddd6743a33d330jim
9379749d811388a7d0e3410940ddd6743a33d330jim/* perform all the expansions on the input string
b0ac1e83f8582a9b5a72bff798ffb31a419c8adesf * putting the result into a new string
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq *
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq * for security reasons this expansion must be performed in a
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim * single pass, otherwise an attacker can arrange for the result
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim * of an earlier expansion to include expansion specifiers that
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim * are interpreted by a later expansion, producing results that
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb * were not intended by the administrator.
997023faa943892aae20d092044aa983c2936982niq */
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbbstatic char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
997023faa943892aae20d092044aa983c2936982niq{
a812b025d139f465a31c76fc02ed162ed5271b03nd result_list *result, *current;
997023faa943892aae20d092044aa983c2936982niq result_list sresult[SMALL_EXPANSION];
a812b025d139f465a31c76fc02ed162ed5271b03nd unsigned spc = 0;
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb apr_size_t span, inputlen, outlen;
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb char *p, *c;
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb apr_pool_t *pool = ctx->r->pool;
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin span = strcspn(input, "\\$%");
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin inputlen = strlen(input);
35c9e4d2c0a6465746a98958ef756114834461e6minfrin
35c9e4d2c0a6465746a98958ef756114834461e6minfrin /* fast exit */
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb if (inputlen == span) {
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb return apr_pstrdup(pool, input);
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb }
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb /* well, actually something to do */
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb result = current = &(sresult[spc++]);
40b22d3b20454959fe51fdc89907908d77701078minfrin
4ecd546edd89824908c2a9ad2e07339d89368f9cmartin p = input + span;
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf current->next = NULL;
4ecd546edd89824908c2a9ad2e07339d89368f9cmartin current->string = input;
4224d5789080ea5586d49420da1e1996f5653bb5ianh current->len = span;
4224d5789080ea5586d49420da1e1996f5653bb5ianh outlen = span;
4224d5789080ea5586d49420da1e1996f5653bb5ianh
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim /* loop for specials */
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim do {
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe /* prepare next entry */
e8f95a682820a599fe41b22977010636be5c2717jim if (current->len) {
7ce40500bfead8781bab964eb6e01944acbf3915jim current->next = (spc < SMALL_EXPANSION)
7ce40500bfead8781bab964eb6e01944acbf3915jim ? &(sresult[spc++])
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe : (result_list *)apr_palloc(pool,
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe sizeof(result_list));
65efbf0826de766a90d745cc44427bfa4e2447b6mturk current = current->next;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk current->next = NULL;
b2b9b7f0644773b50aee41956a841ac884086250niq current->len = 0;
b2b9b7f0644773b50aee41956a841ac884086250niq }
93cf7fc650197b941ae31a7c7e51e901b129e954igalic
93cf7fc650197b941ae31a7c7e51e901b129e954igalic /* escaped character */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (*p == '\\') {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding current->len = 1;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ++outlen;
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm if (!p[1]) {
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm current->string = p;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk break;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk }
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm else {
de8799b6a9e8221681873ab5a81b6af6596faaafwrowe current->string = ++p;
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm ++p;
e8f95a682820a599fe41b22977010636be5c2717jim }
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm }
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm /* variable or map lookup */
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm else if (p[1] == '{') {
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm char *endp;
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm endp = find_closing_curly(p+2);
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm if (!endp) {
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm current->len = 2;
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm current->string = p;
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm outlen += 2;
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm p += 2;
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm }
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm /* variable lookup */
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm else if (*p == '%') {
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm p = lookup_variable(apr_pstrmemdup(pool, p+2, endp-p-2), ctx);
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm span = strlen(p);
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk current->len = span;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk current->string = p;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk outlen += span;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk p = endp + 1;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk }
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk /* map lookup */
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk else { /* *p == '$' */
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk char *key;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk /*
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk * To make rewrite maps useful, the lookup key and
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk * default values must be expanded, so we make
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk * recursive calls to do the work. For security
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk * reasons we must never expand a string that includes
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk * verbatim data from the network. The recursion here
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk * isn't a problem because the result of expansion is
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk * only passed to lookup_map() so it cannot be
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk * re-expanded, only re-looked-up. Another way of
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk * looking at it is that the recursion is entirely
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk * driven by the syntax of the nested curly brackets.
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm */
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm key = find_char_in_curlies(p+2, ':');
655b45ecbcfe204749cddff73f149dc0ec278905mturk if (!key) {
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm current->len = 2;
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm current->string = p;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk outlen += 2;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk p += 2;
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm }
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm else {
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm char *map, *dflt;
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe map = apr_pstrmemdup(pool, p+2, endp-p-2);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe key = map + (key-p-2);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe *key++ = '\0';
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe dflt = find_char_in_curlies(key, '|');
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (dflt) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe *dflt++ = '\0';
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe /* reuse of key variable as result */
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe key = lookup_map(ctx->r, map, do_expand(key, ctx, entry));
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (!key && dflt && *dflt) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe key = do_expand(dflt, ctx, entry);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (key) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe span = strlen(key);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->len = span;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->string = key;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe outlen += span;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
9e3209bc06ddf32f23e4b254faa45914bc323cc9jim
e8f95a682820a599fe41b22977010636be5c2717jim p = endp + 1;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim }
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim }
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim }
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim
c64fb33e0c4634fd352c4a6c143cd1a087c09b13nd /* backreference */
c64fb33e0c4634fd352c4a6c143cd1a087c09b13nd else if (apr_isdigit(p[1])) {
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim int n = p[1] - '0';
c64fb33e0c4634fd352c4a6c143cd1a087c09b13nd backrefinfo *bri = (*p == '$') ? &ctx->briRR : &ctx->briRC;
cd42921af450e87bc797da0ff899348b75732645jfclere
cd42921af450e87bc797da0ff899348b75732645jfclere /* see ap_pregsub() in server/util.c */
c64fb33e0c4634fd352c4a6c143cd1a087c09b13nd if (bri->source && n < AP_MAX_REG_MATCH
cd42921af450e87bc797da0ff899348b75732645jfclere && bri->regmatch[n].rm_eo > bri->regmatch[n].rm_so) {
9e3209bc06ddf32f23e4b254faa45914bc323cc9jim span = bri->regmatch[n].rm_eo - bri->regmatch[n].rm_so;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim if (entry && (entry->flags & RULEFLAG_ESCAPEBACKREF)) {
9e3209bc06ddf32f23e4b254faa45914bc323cc9jim /* escape the backreference */
5b439d3976ab9363288cf5132902fad230777523jim char *tmp2, *tmp;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe tmp = apr_pstrmemdup(pool, bri->source + bri->regmatch[n].rm_so, span);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe tmp2 = escape_uri(pool, tmp);
67d13599fd4a5f73a2d3fc2b566a9aad60b1c892mturk rewritelog((ctx->r, 5, ctx->perdir, "escaping backreference '%s' to '%s'",
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe tmp, tmp2));
f185ce14f5dd540ae54659f764989c017c619485jim
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->len = span = strlen(tmp2);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->string = tmp2;
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere } else {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->len = span;
166a9c7964cffc8193764d877edce5bb9b509551mturk current->string = bri->source + bri->regmatch[n].rm_so;
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim }
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim
48939aa0cd38f4f4f88e74ff696c77b52176ba1djim outlen += span;
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere }
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere p += 2;
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere }
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere /* not for us, just copy it */
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe else {
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere current->len = 1;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->string = p++;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe ++outlen;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe /* check the remainder */
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (*p && (span = strcspn(p, "\\$%")) > 0) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (current->len) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->next = (spc < SMALL_EXPANSION)
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe ? &(sresult[spc++])
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe : (result_list *)apr_palloc(pool,
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe sizeof(result_list));
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current = current->next;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->next = NULL;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
67d13599fd4a5f73a2d3fc2b566a9aad60b1c892mturk current->len = span;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->string = p;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe p += span;
d993198d8a18c11aa4e80bc647587df10e663f88jim outlen += span;
d993198d8a18c11aa4e80bc647587df10e663f88jim }
b6832863054a2d09233ce92945e0faceb932a620jwoolley
92e22cf3d516024d3ed9c6a85610e927e9b3b32djim } while (p < input+inputlen);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe /* assemble result */
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe c = p = apr_palloc(pool, outlen + 1); /* don't forget the \0 */
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe do {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (result->len) {
1d2ff7570139286b0f0d16f92187a16ed5932291mturk ap_assert(c+result->len <= p+outlen); /* XXX: can be removed after
1d2ff7570139286b0f0d16f92187a16ed5932291mturk * extensive testing and
a865e849a3b00dc8524ecdda09a1699452876219mturk * review
e8f95a682820a599fe41b22977010636be5c2717jim */
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim memcpy(c, result->string, result->len);
888c31d26ec2735b6e744697dcaec1ab12877b01mturk c += result->len;
888c31d26ec2735b6e744697dcaec1ab12877b01mturk }
888c31d26ec2735b6e744697dcaec1ab12877b01mturk result = result->next;
888c31d26ec2735b6e744697dcaec1ab12877b01mturk } while (result);
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim
888c31d26ec2735b6e744697dcaec1ab12877b01mturk p[outlen] = '\0';
888c31d26ec2735b6e744697dcaec1ab12877b01mturk
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim return p;
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim}
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim/*
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim * perform all the expansions on the environment variables
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim */
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jimstatic void do_expand_env(data_item *env, rewrite_ctx *ctx)
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim{
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere char *name, *val;
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim while (env) {
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim name = do_expand(env->data, ctx, NULL);
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim if ((val = ap_strchr(name, ':')) != NULL) {
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim *val++ = '\0';
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim } else {
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim val = "";
14c8c18e6caab1bdeb0f26b2b031e000fef58ef9jim }
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim apr_table_set(ctx->r->subprocess_env, name, val);
888c31d26ec2735b6e744697dcaec1ab12877b01mturk rewritelog((ctx->r, 5, NULL, "setting env variable '%s' to '%s'",
e8f95a682820a599fe41b22977010636be5c2717jim name, val));
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim env = env->next;
888c31d26ec2735b6e744697dcaec1ab12877b01mturk }
a865e849a3b00dc8524ecdda09a1699452876219mturk
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim return;
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim}
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim/*
14c8c18e6caab1bdeb0f26b2b031e000fef58ef9jim * perform all the expansions on the cookies
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim *
a865e849a3b00dc8524ecdda09a1699452876219mturk * TODO: use cached time similar to how logging does it
a865e849a3b00dc8524ecdda09a1699452876219mturk */
e8f95a682820a599fe41b22977010636be5c2717jimstatic void add_cookie(request_rec *r, char *s)
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim{
a865e849a3b00dc8524ecdda09a1699452876219mturk char *var;
a865e849a3b00dc8524ecdda09a1699452876219mturk char *val;
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim char *domain;
888c31d26ec2735b6e744697dcaec1ab12877b01mturk char *expires;
1d2ff7570139286b0f0d16f92187a16ed5932291mturk char *path;
1d2ff7570139286b0f0d16f92187a16ed5932291mturk char *secure;
1d2ff7570139286b0f0d16f92187a16ed5932291mturk char *httponly;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe char *tok_cntx;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe char *cookie;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe var = apr_strtok(s, ":", &tok_cntx);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe val = apr_strtok(NULL, ":", &tok_cntx);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe domain = apr_strtok(NULL, ":", &tok_cntx);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (var && val && domain) {
e8f95a682820a599fe41b22977010636be5c2717jim request_rec *rmain = r;
559db7681c06b49d8b57de9edb97b430c3b4d676mturk char *notename;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe void *data;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
73e8b26287de5c06fa470d36162e103dbac9c7e5wrowe while (rmain->main) {
5babe00918c88eda487771fa6d6d4a1a19c0ced0chuck rmain = rmain->main;
65aeb4185d6a108b19c27b89f311dc57dab62239nd }
65aeb4185d6a108b19c27b89f311dc57dab62239nd
65aeb4185d6a108b19c27b89f311dc57dab62239nd notename = apr_pstrcat(rmain->pool, var, "_rewrite", NULL);
35630e8756729a29273ef1a5c879b90df3594d66rjung apr_pool_userdata_get(&data, notename, rmain->pool);
1d2ff7570139286b0f0d16f92187a16ed5932291mturk if (!data) {
1d2ff7570139286b0f0d16f92187a16ed5932291mturk char *exp_time = NULL;
1d2ff7570139286b0f0d16f92187a16ed5932291mturk
1d2ff7570139286b0f0d16f92187a16ed5932291mturk expires = apr_strtok(NULL, ":", &tok_cntx);
4b155326ef6781820619c10e518dce1a44df7f91rjung path = expires ? apr_strtok(NULL, ":", &tok_cntx) : NULL;
e8f95a682820a599fe41b22977010636be5c2717jim secure = path ? apr_strtok(NULL, ":", &tok_cntx) : NULL;
fdacf528f0125e0165de42b7783b1dcbf961a189chuck httponly = secure ? apr_strtok(NULL, ":", &tok_cntx) : NULL;
fdacf528f0125e0165de42b7783b1dcbf961a189chuck
fdacf528f0125e0165de42b7783b1dcbf961a189chuck if (expires) {
e5882a36d7756850cc829f5f2286120b877458b1pquerna apr_time_exp_t tms;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe long exp_min;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
fdacf528f0125e0165de42b7783b1dcbf961a189chuck exp_min = atol(expires);
65aeb4185d6a108b19c27b89f311dc57dab62239nd if (exp_min) {
fdacf528f0125e0165de42b7783b1dcbf961a189chuck apr_time_exp_gmt(&tms, r->request_time
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe + apr_time_from_sec((60 * exp_min)));
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe exp_time = apr_psprintf(r->pool, "%s, %.2d-%s-%.4d "
e8f95a682820a599fe41b22977010636be5c2717jim "%.2d:%.2d:%.2d GMT",
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm apr_day_snames[tms.tm_wday],
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm tms.tm_mday,
1d2ff7570139286b0f0d16f92187a16ed5932291mturk apr_month_snames[tms.tm_mon],
e8f95a682820a599fe41b22977010636be5c2717jim tms.tm_year+1900,
1d2ff7570139286b0f0d16f92187a16ed5932291mturk tms.tm_hour, tms.tm_min, tms.tm_sec);
5babe00918c88eda487771fa6d6d4a1a19c0ced0chuck }
5babe00918c88eda487771fa6d6d4a1a19c0ced0chuck }
36ef8f77bffe75d1aa327882be1b5bdbe2ff567asf
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding cookie = apr_pstrcat(rmain->pool,
5babe00918c88eda487771fa6d6d4a1a19c0ced0chuck var, "=", val,
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe "; path=", path ? path : "/",
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe "; domain=", domain,
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk expires ? (exp_time ? "; expires=" : "")
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk : NULL,
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk expires ? (exp_time ? exp_time : "")
5babe00918c88eda487771fa6d6d4a1a19c0ced0chuck : NULL,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding (secure && (!strcasecmp(secure, "true")
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin || !strcmp(secure, "1")
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin || !strcasecmp(secure,
65efbf0826de766a90d745cc44427bfa4e2447b6mturk "secure"))) ?
65efbf0826de766a90d745cc44427bfa4e2447b6mturk "; secure" : NULL,
65efbf0826de766a90d745cc44427bfa4e2447b6mturk (httponly && (!strcasecmp(httponly, "true")
65efbf0826de766a90d745cc44427bfa4e2447b6mturk || !strcmp(httponly, "1")
bda7a7d57377f45932c237d5aba00b189d85c2a9ianh || !strcasecmp(httponly,
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin "HttpOnly"))) ?
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin "; HttpOnly" : NULL,
e8f95a682820a599fe41b22977010636be5c2717jim NULL);
446c6a9a1e1073798258f1237f8c848b5f917b66wrowe
e8f95a682820a599fe41b22977010636be5c2717jim apr_table_addn(rmain->err_headers_out, "Set-Cookie", cookie);
e8f95a682820a599fe41b22977010636be5c2717jim apr_pool_userdata_set("set", notename, NULL, rmain->pool);
446c6a9a1e1073798258f1237f8c848b5f917b66wrowe rewritelog((rmain, 5, NULL, "setting cookie '%s'", cookie));
446c6a9a1e1073798258f1237f8c848b5f917b66wrowe }
e8f95a682820a599fe41b22977010636be5c2717jim else {
446c6a9a1e1073798258f1237f8c848b5f917b66wrowe rewritelog((rmain, 5, NULL, "skipping already set cookie '%s'",
446c6a9a1e1073798258f1237f8c848b5f917b66wrowe var));
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe }
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe }
5a5a6c22260854843c973e2ea9a14bec64362ab5wrowe
e8f95a682820a599fe41b22977010636be5c2717jim return;
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe}
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe
d75bc22ab2702fa770f6935f07107efff16a76f0wrowestatic void do_expand_cookie(data_item *cookie, rewrite_ctx *ctx)
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe{
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe while (cookie) {
5a5a6c22260854843c973e2ea9a14bec64362ab5wrowe add_cookie(ctx->r, do_expand(cookie->data, ctx, NULL));
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe cookie = cookie->next;
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe }
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe
67f62b7a48ff9eb8d9f31898dceaf9f89280a723dougm return;
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk}
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk
bda7a7d57377f45932c237d5aba00b189d85c2a9ianh#if APR_HAS_USER
e8f95a682820a599fe41b22977010636be5c2717jim/*
bda7a7d57377f45932c237d5aba00b189d85c2a9ianh * Expand tilde-paths (/~user) through Unix /etc/passwd
bda7a7d57377f45932c237d5aba00b189d85c2a9ianh * database information (or other OS-specific database)
*/
static char *expand_tildepaths(request_rec *r, char *uri)
{
if (uri && *uri == '/' && uri[1] == '~') {
char *p, *user;
p = user = uri + 2;
while (*p && *p != '/') {
++p;
}
if (p > user) {
char *homedir;
user = apr_pstrmemdup(r->pool, user, p-user);
if (apr_uid_homepath_get(&homedir, user, r->pool) == APR_SUCCESS) {
if (*p) {
/* reuse of user variable */
user = homedir + strlen(homedir) - 1;
if (user >= homedir && *user == '/') {
*user = '\0';
}
return apr_pstrcat(r->pool, homedir, p, NULL);
}
else {
return homedir;
}
}
}
}
return uri;
}
#endif /* if APR_HAS_USER */
/*
* +-------------------------------------------------------+
* | |
* | rewriting lockfile support
* | |
* +-------------------------------------------------------+
*/
static apr_status_t rewritelock_create(server_rec *s, apr_pool_t *p)
{
apr_status_t rc;
/* create the lockfile */
/* XXX See if there are any rewrite map programs before creating
* the mutex.
*/
rc = ap_global_mutex_create(&rewrite_mapr_lock_acquire, NULL,
rewritemap_mutex_type, NULL, s, p, 0);
if (rc != APR_SUCCESS) {
return rc;
}
return APR_SUCCESS;
}
static apr_status_t rewritelock_remove(void *data)
{
/* destroy the rewritelock */
if (rewrite_mapr_lock_acquire) {
apr_global_mutex_destroy(rewrite_mapr_lock_acquire);
rewrite_mapr_lock_acquire = NULL;
}
return(0);
}
/*
* +-------------------------------------------------------+
* | |
* | configuration directive handling
* | |
* +-------------------------------------------------------+
*/
/*
* own command line parser for RewriteRule and RewriteCond,
* which doesn't have the '\\' problem.
* (returns true on error)
*
* 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)
{
char quote;
while (apr_isspace(*str)) {
++str;
}
/*
* determine first argument
*/
quote = (*str == '"' || *str == '\'') ? *str++ : '\0';
*a1 = str;
for (; *str; ++str) {
if ((apr_isspace(*str) && !quote) || (*str == quote)) {
break;
}
if (*str == '\\' && apr_isspace(str[1])) {
++str;
continue;
}
}
if (!*str) {
return 1;
}
*str++ = '\0';
while (apr_isspace(*str)) {
++str;
}
/*
* determine second argument
*/
quote = (*str == '"' || *str == '\'') ? *str++ : '\0';
*a2 = str;
for (; *str; ++str) {
if ((apr_isspace(*str) && !quote) || (*str == quote)) {
break;
}
if (*str == '\\' && apr_isspace(str[1])) {
++str;
continue;
}
}
if (!*str) {
*a3 = NULL; /* 3rd argument is optional */
return 0;
}
*str++ = '\0';
while (apr_isspace(*str)) {
++str;
}
if (!*str) {
*a3 = NULL; /* 3rd argument is still optional */
return 0;
}
/*
* determine third argument
*/
quote = (*str == '"' || *str == '\'') ? *str++ : '\0';
*a3 = str;
for (; *str; ++str) {
if ((apr_isspace(*str) && !quote) || (*str == quote)) {
break;
}
if (*str == '\\' && apr_isspace(str[1])) {
++str;
continue;
}
}
*str = '\0';
return 0;
}
static void *config_server_create(apr_pool_t *p, server_rec *s)
{
rewrite_server_conf *a;
a = (rewrite_server_conf *)apr_pcalloc(p, sizeof(rewrite_server_conf));
a->state = ENGINE_DISABLED;
a->options = OPTION_NONE;
a->rewritemaps = apr_hash_make(p);
a->rewriteconds = apr_array_make(p, 2, sizeof(rewritecond_entry));
a->rewriterules = apr_array_make(p, 2, sizeof(rewriterule_entry));
a->server = s;
return (void *)a;
}
static void *config_server_merge(apr_pool_t *p, void *basev, void *overridesv)
{
rewrite_server_conf *a, *base, *overrides;
a = (rewrite_server_conf *)apr_pcalloc(p,
sizeof(rewrite_server_conf));
base = (rewrite_server_conf *)basev;
overrides = (rewrite_server_conf *)overridesv;
a->state = (overrides->state_set == 0) ? base->state : overrides->state;
a->state_set = overrides->state_set || base->state_set;
a->options = (overrides->options_set == 0) ? base->options : overrides->options;
a->options_set = overrides->options_set || base->options_set;
a->server = overrides->server;
if (a->options & OPTION_INHERIT) {
/*
* local directives override
* and anything else is inherited
*/
a->rewritemaps = apr_hash_overlay(p, overrides->rewritemaps,
base->rewritemaps);
a->rewriteconds = apr_array_append(p, overrides->rewriteconds,
base->rewriteconds);
a->rewriterules = apr_array_append(p, overrides->rewriterules,
base->rewriterules);
}
else if (a->options & OPTION_INHERIT_BEFORE) {
/*
* local directives override
* and anything else is inherited (preserving order)
*/
a->rewritemaps = apr_hash_overlay(p, base->rewritemaps,
overrides->rewritemaps);
a->rewriteconds = apr_array_append(p, base->rewriteconds,
overrides->rewriteconds);
a->rewriterules = apr_array_append(p, base->rewriterules,
overrides->rewriterules);
}
else {
/*
* local directives override
* and anything else gets defaults
*/
a->rewritemaps = overrides->rewritemaps;
a->rewriteconds = overrides->rewriteconds;
a->rewriterules = overrides->rewriterules;
}
return (void *)a;
}
static void *config_perdir_create(apr_pool_t *p, char *path)
{
rewrite_perdir_conf *a;
a = (rewrite_perdir_conf *)apr_pcalloc(p, sizeof(rewrite_perdir_conf));
a->state = ENGINE_DISABLED;
a->options = OPTION_NONE;
a->baseurl = NULL;
a->rewriteconds = apr_array_make(p, 2, sizeof(rewritecond_entry));
a->rewriterules = apr_array_make(p, 2, sizeof(rewriterule_entry));
if (path == NULL) {
a->directory = NULL;
}
else {
/* make sure it has a trailing slash */
if (path[strlen(path)-1] == '/') {
a->directory = apr_pstrdup(p, path);
}
else {
a->directory = apr_pstrcat(p, path, "/", NULL);
}
}
return (void *)a;
}
static void *config_perdir_merge(apr_pool_t *p, void *basev, void *overridesv)
{
rewrite_perdir_conf *a, *base, *overrides;
a = (rewrite_perdir_conf *)apr_pcalloc(p,
sizeof(rewrite_perdir_conf));
base = (rewrite_perdir_conf *)basev;
overrides = (rewrite_perdir_conf *)overridesv;
a->state = (overrides->state_set == 0) ? base->state : overrides->state;
a->state_set = overrides->state_set || base->state_set;
a->options = (overrides->options_set == 0) ? base->options : overrides->options;
a->options_set = overrides->options_set || base->options_set;
a->baseurl = (overrides->baseurl_set == 0) ? base->baseurl : overrides->baseurl;
a->baseurl_set = overrides->baseurl_set || base->baseurl_set;
a->directory = overrides->directory;
if (a->options & OPTION_INHERIT) {
a->rewriteconds = apr_array_append(p, overrides->rewriteconds,
base->rewriteconds);
a->rewriterules = apr_array_append(p, overrides->rewriterules,
base->rewriterules);
}
else if (a->options & OPTION_INHERIT_BEFORE) {
a->rewriteconds = apr_array_append(p, base->rewriteconds,
overrides->rewriteconds);
a->rewriterules = apr_array_append(p, base->rewriterules,
overrides->rewriterules);
}
else {
a->rewriteconds = overrides->rewriteconds;
a->rewriterules = overrides->rewriterules;
}
return (void *)a;
}
static const char *cmd_rewriteengine(cmd_parms *cmd,
void *in_dconf, int flag)
{
rewrite_perdir_conf *dconf = in_dconf;
rewrite_server_conf *sconf;
sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
/* server command? set both global scope and base directory scope */
if (cmd->path == NULL) {
sconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED);
sconf->state_set = 1;
dconf->state = sconf->state;
dconf->state_set = 1;
}
/* directory command? set directory scope only */
else {
dconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED);
dconf->state_set = 1;
}
return NULL;
}
static const char *cmd_rewriteoptions(cmd_parms *cmd,
void *in_dconf, const char *option)
{
int options = 0;
while (*option) {
char *w = ap_getword_conf(cmd->temp_pool, &option);
if (!strcasecmp(w, "inherit")) {
options |= OPTION_INHERIT;
}
else if (!strcasecmp(w, "inheritbefore")) {
options |= OPTION_INHERIT_BEFORE;
}
else if (!strncasecmp(w, "MaxRedirects=", 13)) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
"RewriteOptions: MaxRedirects option has been "
"removed in favor of the global "
"LimitInternalRecursion directive and will be "
"ignored.");
}
else {
return apr_pstrcat(cmd->pool, "RewriteOptions: unknown option '",
w, "'", NULL);
}
}
/* server command? set both global scope and base directory scope */
if (cmd->path == NULL) { /* is server command */
rewrite_perdir_conf *dconf = in_dconf;
rewrite_server_conf *sconf =
ap_get_module_config(cmd->server->module_config,
&rewrite_module);
sconf->options |= options;
sconf->options_set = 1;
dconf->options |= options;
dconf->options_set = 1;
}
/* directory command? set directory scope only */
else { /* is per-directory command */
rewrite_perdir_conf *dconf = in_dconf;
dconf->options |= options;
dconf->options_set = 1;
}
return NULL;
}
static const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, const char *a1,
const char *a2)
{
rewrite_server_conf *sconf;
rewritemap_entry *newmap;
apr_finfo_t st;
const char *fname;
sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
newmap = apr_palloc(cmd->pool, sizeof(rewritemap_entry));
newmap->func = NULL;
if (strncasecmp(a2, "txt:", 4) == 0) {
if ((fname = ap_server_root_relative(cmd->pool, a2+4)) == NULL) {
return apr_pstrcat(cmd->pool, "RewriteMap: bad path to txt map: ",
a2+4, NULL);
}
newmap->type = MAPTYPE_TXT;
newmap->datafile = fname;
newmap->checkfile = fname;
newmap->checkfile2= NULL;
newmap->cachename = apr_psprintf(cmd->pool, "%pp:%s",
(void *)cmd->server, a1);
}
else if (strncasecmp(a2, "rnd:", 4) == 0) {
if ((fname = ap_server_root_relative(cmd->pool, a2+4)) == NULL) {
return apr_pstrcat(cmd->pool, "RewriteMap: bad path to rnd map: ",
a2+4, NULL);
}
newmap->type = MAPTYPE_RND;
newmap->datafile = fname;
newmap->checkfile = fname;
newmap->checkfile2= NULL;
newmap->cachename = apr_psprintf(cmd->pool, "%pp:%s",
(void *)cmd->server, a1);
}
else if (strncasecmp(a2, "dbm", 3) == 0) {
apr_status_t rv;
newmap->type = MAPTYPE_DBM;
fname = NULL;
newmap->cachename = apr_psprintf(cmd->pool, "%pp:%s",
(void *)cmd->server, a1);
if (a2[3] == ':') {
newmap->dbmtype = "default";
fname = a2+4;
}
else if (a2[3] == '=') {
const char *colon = ap_strchr_c(a2 + 4, ':');
if (colon) {
newmap->dbmtype = apr_pstrndup(cmd->pool, a2 + 4,
colon - (a2 + 3) - 1);
fname = colon + 1;
}
}
if (!fname) {
return apr_pstrcat(cmd->pool, "RewriteMap: bad map:",
a2, NULL);
}
if ((newmap->datafile = ap_server_root_relative(cmd->pool,
fname)) == NULL) {
return apr_pstrcat(cmd->pool, "RewriteMap: bad path to dbm map: ",
fname, NULL);
}
rv = apr_dbm_get_usednames_ex(cmd->pool, newmap->dbmtype,
newmap->datafile, &newmap->checkfile,
&newmap->checkfile2);
if (rv != APR_SUCCESS) {
return apr_pstrcat(cmd->pool, "RewriteMap: dbm type ",
newmap->dbmtype, " is invalid", NULL);
}
}
else if ((strncasecmp(a2, "dbd:", 4) == 0)
|| (strncasecmp(a2, "fastdbd:", 8) == 0)) {
if (dbd_prepare == NULL) {
return "RewriteMap types dbd and fastdbd require mod_dbd!";
}
if ((a2[0] == 'd') || (a2[0] == 'D')) {
newmap->type = MAPTYPE_DBD;
fname = a2+4;
}
else {
newmap->type = MAPTYPE_DBD_CACHE;
fname = a2+8;
newmap->cachename = apr_psprintf(cmd->pool, "%pp:%s",
(void *)cmd->server, a1);
}
newmap->dbdq = a1;
dbd_prepare(cmd->server, fname, newmap->dbdq);
}
else if (strncasecmp(a2, "prg:", 4) == 0) {
apr_tokenize_to_argv(a2 + 4, &newmap->argv, cmd->pool);
fname = newmap->argv[0];
if ((newmap->argv[0] = ap_server_root_relative(cmd->pool,
fname)) == NULL) {
return apr_pstrcat(cmd->pool, "RewriteMap: bad path to prg map: ",
fname, NULL);
}
newmap->type = MAPTYPE_PRG;
newmap->datafile = NULL;
newmap->checkfile = newmap->argv[0];
newmap->checkfile2= NULL;
newmap->cachename = NULL;
}
else if (strncasecmp(a2, "int:", 4) == 0) {
newmap->type = MAPTYPE_INT;
newmap->datafile = NULL;
newmap->checkfile = NULL;
newmap->checkfile2= NULL;
newmap->cachename = NULL;
newmap->func = (char *(*)(request_rec *,char *))
apr_hash_get(mapfunc_hash, a2+4, strlen(a2+4));
if ((sconf->state == ENGINE_ENABLED) && (newmap->func == NULL)) {
return apr_pstrcat(cmd->pool, "RewriteMap: internal map not found:",
a2+4, NULL);
}
}
else {
if ((fname = ap_server_root_relative(cmd->pool, a2)) == NULL) {
return apr_pstrcat(cmd->pool, "RewriteMap: bad path to txt map: ",
a2, NULL);
}
newmap->type = MAPTYPE_TXT;
newmap->datafile = fname;
newmap->checkfile = fname;
newmap->checkfile2= NULL;
newmap->cachename = apr_psprintf(cmd->pool, "%pp:%s",
(void *)cmd->server, a1);
}
newmap->fpin = NULL;
newmap->fpout = NULL;
if (newmap->checkfile && (sconf->state == ENGINE_ENABLED)
&& (apr_stat(&st, newmap->checkfile, APR_FINFO_MIN,
cmd->pool) != APR_SUCCESS)) {
return apr_pstrcat(cmd->pool,
"RewriteMap: file for map ", a1,
" not found:", newmap->checkfile, NULL);
}
apr_hash_set(sconf->rewritemaps, a1, APR_HASH_KEY_STRING, newmap);
return NULL;
}
static const char *cmd_rewritebase(cmd_parms *cmd, void *in_dconf,
const char *a1)
{
rewrite_perdir_conf *dconf = in_dconf;
if (cmd->path == NULL || dconf == NULL) {
return "RewriteBase: only valid in per-directory config files";
}
if (a1[0] == '\0') {
return "RewriteBase: empty URL not allowed";
}
if (a1[0] != '/') {
return "RewriteBase: argument is not a valid URL";
}
dconf->baseurl = a1;
dconf->baseurl_set = 1;
return NULL;
}
/*
* generic lexer for RewriteRule and RewriteCond flags.
* The parser will be passed in as a function pointer
* and called if a flag was found
*/
static const char *cmd_parseflagfield(apr_pool_t *p, void *cfg, char *key,
const char *(*parse)(apr_pool_t *,
void *,
char *, char *))
{
char *val, *nextp, *endp;
const char *err;
endp = key + strlen(key) - 1;
if (*key != '[' || *endp != ']') {
return "bad flag delimiters";
}
*endp = ','; /* for simpler parsing */
++key;
while (*key) {
/* skip leading spaces */
while (apr_isspace(*key)) {
++key;
}
if (!*key || (nextp = ap_strchr(key, ',')) == NULL) { /* NULL should not
* happen, but ...
*/
break;
}
/* strip trailing spaces */
endp = nextp - 1;
while (apr_isspace(*endp)) {
--endp;
}
*++endp = '\0';
/* split key and val */
val = ap_strchr(key, '=');
if (val) {
*val++ = '\0';
}
else {
val = endp;
}
err = parse(p, cfg, key, val);
if (err) {
return err;
}
key = nextp + 1;
}
return NULL;
}
static const char *cmd_rewritecond_setflag(apr_pool_t *p, void *_cfg,
char *key, char *val)
{
rewritecond_entry *cfg = _cfg;
if ( strcasecmp(key, "nocase") == 0
|| strcasecmp(key, "NC") == 0 ) {
cfg->flags |= CONDFLAG_NOCASE;
}
else if ( strcasecmp(key, "ornext") == 0
|| strcasecmp(key, "OR") == 0 ) {
cfg->flags |= CONDFLAG_ORNEXT;
}
else if ( strcasecmp(key, "novary") == 0
|| strcasecmp(key, "NV") == 0 ) {
cfg->flags |= CONDFLAG_NOVARY;
}
else {
return apr_pstrcat(p, "unknown flag '", key, "'", NULL);
}
return NULL;
}
static const char *cmd_rewritecond(cmd_parms *cmd, void *in_dconf,
const char *in_str)
{
rewrite_perdir_conf *dconf = in_dconf;
char *str = apr_pstrdup(cmd->pool, in_str);
rewrite_server_conf *sconf;
rewritecond_entry *newcond;
ap_regex_t *regexp;
char *a1;
char *a2;
char *a3;
const char *err;
sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
/* make a new entry in the internal temporary rewrite rule list */
if (cmd->path == NULL) { /* is server command */
newcond = apr_array_push(sconf->rewriteconds);
}
else { /* is per-directory command */
newcond = apr_array_push(dconf->rewriteconds);
}
/* parse the argument line ourself
* a1 .. a3 are substrings of str, which is a fresh copy
* of the argument line. So we can use a1 .. a3 without
* copying them again.
*/
if (parseargline(str, &a1, &a2, &a3)) {
return apr_pstrcat(cmd->pool, "RewriteCond: bad argument line '", str,
"'", NULL);
}
/* arg1: the input string */
newcond->input = a1;
/* arg3: optional flags field
* (this has to be parsed first, because we need to
* know if the regex should be compiled with ICASE!)
*/
newcond->flags = CONDFLAG_NONE;
if (a3 != NULL) {
if ((err = cmd_parseflagfield(cmd->pool, newcond, a3,
cmd_rewritecond_setflag)) != NULL) {
return apr_pstrcat(cmd->pool, "RewriteCond: ", err, NULL);
}
}
/* arg2: the pattern */
newcond->pattern = a2;
if (*a2 == '!') {
newcond->flags |= CONDFLAG_NOTMATCH;
++a2;
}
/* determine the pattern type */
newcond->ptype = CONDPAT_REGEX;
if (*a2 && a2[1]) {
if (!a2[2] && *a2 == '-') {
switch (a2[1]) {
case 'f': newcond->ptype = CONDPAT_FILE_EXISTS; break;
case 's': newcond->ptype = CONDPAT_FILE_SIZE; break;
case 'd': newcond->ptype = CONDPAT_FILE_DIR; break;
case 'x': newcond->ptype = CONDPAT_FILE_XBIT; break;
case 'h': newcond->ptype = CONDPAT_FILE_LINK; break;
case 'L': newcond->ptype = CONDPAT_FILE_LINK; break;
case 'U': newcond->ptype = CONDPAT_LU_URL; break;
case 'F': newcond->ptype = CONDPAT_LU_FILE; break;
case 'l': if (a2[2] == 't')
a2 += 3, newcond->ptype = CONDPAT_INT_LT;
else if (a2[2] == 'e')
a2 += 3, newcond->ptype = CONDPAT_INT_LE;
else /* Historical; prefer -L or -h instead */
newcond->ptype = CONDPAT_FILE_LINK;
break;
case 'g': if (a2[2] == 't')
a2 += 3, newcond->ptype = CONDPAT_INT_GT;
else if (a2[2] == 'e')
a2 += 3, newcond->ptype = CONDPAT_INT_GE;
break;
case 'e': if (a2[2] == 'q')
a2 += 3, newcond->ptype = CONDPAT_INT_EQ;
break;
case 'n': if (a2[2] == 'e') {
/* Inversion, ensure !-ne == -eq */
a2 += 3, newcond->ptype = CONDPAT_INT_EQ;
newcond->flags ^= CONDFLAG_NOTMATCH;
}
break;
}
}
else {
switch (*a2) {
case '>': if (*++a2 == '=')
++a2, newcond->ptype = CONDPAT_STR_GE;
else
newcond->ptype = CONDPAT_STR_GT;
break;
case '<': if (*++a2 == '=')
++a2, newcond->ptype = CONDPAT_STR_LE;
else
newcond->ptype = CONDPAT_STR_LT;
break;
case '=': newcond->ptype = CONDPAT_STR_EQ;
/* "" represents an empty string */
if (*++a2 == '"' && a2[1] == '"' && !a2[2])
a2 += 2;
break;
}
}
}
if ((newcond->ptype < CONDPAT_STR_LT || newcond->ptype > CONDPAT_STR_GE) &&
(newcond->flags & CONDFLAG_NOCASE)) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
"RewriteCond: NoCase option for non-regex pattern '%s' "
"is not supported and will be ignored.", a2);
newcond->flags &= ~CONDFLAG_NOCASE;
}
newcond->pskip = a2 - newcond->pattern;
newcond->pattern += newcond->pskip;
if (!newcond->ptype) {
regexp = ap_pregcomp(cmd->pool, a2,
AP_REG_EXTENDED | ((newcond->flags & CONDFLAG_NOCASE)
? AP_REG_ICASE : 0));
if (!regexp) {
return apr_pstrcat(cmd->pool, "RewriteCond: cannot compile regular "
"expression '", a2, "'", NULL);
}
newcond->regexp = regexp;
}
return NULL;
}
static const char *cmd_rewriterule_setflag(apr_pool_t *p, void *_cfg,
char *key, char *val)
{
rewriterule_entry *cfg = _cfg;
int error = 0;
switch (*key++) {
case 'b':
case 'B':
if (!*key || !strcasecmp(key, "ackrefescaping")) {
cfg->flags |= RULEFLAG_ESCAPEBACKREF;
}
else {
++error;
}
break;
case 'c':
case 'C':
if (!*key || !strcasecmp(key, "hain")) { /* chain */
cfg->flags |= RULEFLAG_CHAIN;
}
else if (((*key == 'O' || *key == 'o') && !key[1])
|| !strcasecmp(key, "ookie")) { /* cookie */
data_item *cp = cfg->cookie;
if (!cp) {
cp = cfg->cookie = apr_palloc(p, sizeof(*cp));
}
else {
while (cp->next) {
cp = cp->next;
}
cp->next = apr_palloc(p, sizeof(*cp));
cp = cp->next;
}
cp->next = NULL;
cp->data = val;
}
else {
++error;
}
break;
case 'd':
case 'D':
if (!*key || !strcasecmp(key, "PI") || !strcasecmp(key,"iscardpath")) {
cfg->flags |= (RULEFLAG_DISCARDPATHINFO);
}
break;
case 'e':
case 'E':
if (!*key || !strcasecmp(key, "nv")) { /* env */
data_item *cp = cfg->env;
if (!cp) {
cp = cfg->env = apr_palloc(p, sizeof(*cp));
}
else {
while (cp->next) {
cp = cp->next;
}
cp->next = apr_palloc(p, sizeof(*cp));
cp = cp->next;
}
cp->next = NULL;
cp->data = val;
}
else if (!strcasecmp(key, "nd")) { /* end */
cfg->flags |= RULEFLAG_END;
}
else {
++error;
}
break;
case 'f':
case 'F':
if (!*key || !strcasecmp(key, "orbidden")) { /* forbidden */
cfg->flags |= (RULEFLAG_STATUS | RULEFLAG_NOSUB);
cfg->forced_responsecode = HTTP_FORBIDDEN;
}
else {
++error;
}
break;
case 'g':
case 'G':
if (!*key || !strcasecmp(key, "one")) { /* gone */
cfg->flags |= (RULEFLAG_STATUS | RULEFLAG_NOSUB);
cfg->forced_responsecode = HTTP_GONE;
}
else {
++error;
}
break;
case 'h':
case 'H':
if (!*key || !strcasecmp(key, "andler")) { /* handler */
cfg->forced_handler = val;
}
else {
++error;
}
break;
case 'l':
case 'L':
if (!*key || !strcasecmp(key, "ast")) { /* last */
cfg->flags |= RULEFLAG_LASTRULE;
}
else {
++error;
}
break;
case 'n':
case 'N':
if (((*key == 'E' || *key == 'e') && !key[1])
|| !strcasecmp(key, "oescape")) { /* noescape */
cfg->flags |= RULEFLAG_NOESCAPE;
}
else if (!*key || !strcasecmp(key, "ext")) { /* next */
cfg->flags |= RULEFLAG_NEWROUND;
}
else if (((*key == 'S' || *key == 's') && !key[1])
|| !strcasecmp(key, "osubreq")) { /* nosubreq */
cfg->flags |= RULEFLAG_IGNOREONSUBREQ;
}
else if (((*key == 'C' || *key == 'c') && !key[1])
|| !strcasecmp(key, "ocase")) { /* nocase */
cfg->flags |= RULEFLAG_NOCASE;
}
else {
++error;
}
break;
case 'p':
case 'P':
if (!*key || !strcasecmp(key, "roxy")) { /* proxy */
cfg->flags |= RULEFLAG_PROXY;
}
else if (((*key == 'T' || *key == 't') && !key[1])
|| !strcasecmp(key, "assthrough")) { /* passthrough */
cfg->flags |= RULEFLAG_PASSTHROUGH;
}
else {
++error;
}
break;
case 'q':
case 'Q':
if ( !strcasecmp(key, "SA")
|| !strcasecmp(key, "sappend")) { /* qsappend */
cfg->flags |= RULEFLAG_QSAPPEND;
} else if ( !strcasecmp(key, "SD")
|| !strcasecmp(key, "sdiscard") ) { /* qsdiscard */
cfg->flags |= RULEFLAG_QSDISCARD;
}
else {
++error;
}
break;
case 'r':
case 'R':
if (!*key || !strcasecmp(key, "edirect")) { /* redirect */
int status = 0;
cfg->flags |= RULEFLAG_FORCEREDIRECT;
if (*val) {
if (strcasecmp(val, "permanent") == 0) {
status = HTTP_MOVED_PERMANENTLY;
}
else if (strcasecmp(val, "temp") == 0) {
status = HTTP_MOVED_TEMPORARILY;
}
else if (strcasecmp(val, "seeother") == 0) {
status = HTTP_SEE_OTHER;
}
else if (apr_isdigit(*val)) {
status = atoi(val);
if (status != HTTP_INTERNAL_SERVER_ERROR) {
int idx =
ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR);
if (ap_index_of_response(status) == idx) {
return apr_psprintf(p, "invalid HTTP "
"response code '%s' for "
"flag 'R'",
val);
}
}
if (!ap_is_HTTP_REDIRECT(status)) {
cfg->flags |= (RULEFLAG_STATUS | RULEFLAG_NOSUB);
}
}
cfg->forced_responsecode = status;
}
}
else {
++error;
}
break;
case 's':
case 'S':
if (!*key || !strcasecmp(key, "kip")) { /* skip */
cfg->skip = atoi(val);
}
else {
++error;
}
break;
case 't':
case 'T':
if (!*key || !strcasecmp(key, "ype")) { /* type */
cfg->forced_mimetype = val;
}
else {
++error;
}
break;
default:
++error;
break;
}
if (error) {
return apr_pstrcat(p, "unknown flag '", --key, "'", NULL);
}
return NULL;
}
static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
const char *in_str)
{
rewrite_perdir_conf *dconf = in_dconf;
char *str = apr_pstrdup(cmd->pool, in_str);
rewrite_server_conf *sconf;
rewriterule_entry *newrule;
ap_regex_t *regexp;
char *a1;
char *a2;
char *a3;
const char *err;
sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
/* make a new entry in the internal rewrite rule list */
if (cmd->path == NULL) { /* is server command */
newrule = apr_array_push(sconf->rewriterules);
}
else { /* is per-directory command */
newrule = apr_array_push(dconf->rewriterules);
}
/* parse the argument line ourself */
if (parseargline(str, &a1, &a2, &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;
newrule->flags = RULEFLAG_NONE;
newrule->env = NULL;
newrule->cookie = NULL;
newrule->skip = 0;
if (a3 != NULL) {
if ((err = cmd_parseflagfield(cmd->pool, newrule, a3,
cmd_rewriterule_setflag)) != NULL) {
return apr_pstrcat(cmd->pool, "RewriteRule: ", err, NULL);
}
}
/* arg1: the pattern
* try to compile the regexp to test if is ok
*/
if (*a1 == '!') {
newrule->flags |= RULEFLAG_NOTMATCH;
++a1;
}
regexp = ap_pregcomp(cmd->pool, a1, AP_REG_EXTENDED |
((newrule->flags & RULEFLAG_NOCASE)
? AP_REG_ICASE : 0));
if (!regexp) {
return apr_pstrcat(cmd->pool,
"RewriteRule: cannot compile regular expression '",
a1, "'", NULL);
}
newrule->pattern = a1;
newrule->regexp = regexp;
/* arg2: the output string */
newrule->output = a2;
if (*a2 == '-' && !a2[1]) {
newrule->flags |= RULEFLAG_NOSUB;
}
/* now, if the server or per-dir config holds an
* array of RewriteCond entries, we take it for us
* and clear the array
*/
if (cmd->path == NULL) { /* is server command */
newrule->rewriteconds = sconf->rewriteconds;
sconf->rewriteconds = apr_array_make(cmd->pool, 2,
sizeof(rewritecond_entry));
}
else { /* is per-directory command */
newrule->rewriteconds = dconf->rewriteconds;
dconf->rewriteconds = apr_array_make(cmd->pool, 2,
sizeof(rewritecond_entry));
}
return NULL;
}
/*
* +-------------------------------------------------------+
* | |
* | the rewriting engine
* | |
* +-------------------------------------------------------+
*/
/* Lexicographic Compare */
static APR_INLINE int compare_lexicography(char *a, char *b)
{
apr_size_t i, lena, lenb;
lena = strlen(a);
lenb = strlen(b);
if (lena == lenb) {
for (i = 0; i < lena; ++i) {
if (a[i] != b[i]) {
return ((unsigned char)a[i] > (unsigned char)b[i]) ? 1 : -1;
}
}
return 0;
}
return ((lena > lenb) ? 1 : -1);
}
/*
* Apply a single rewriteCond
*/
static int apply_rewrite_cond(rewritecond_entry *p, rewrite_ctx *ctx)
{
char *input = do_expand(p->input, ctx, NULL);
apr_finfo_t sb;
request_rec *rsub, *r = ctx->r;
ap_regmatch_t regmatch[AP_MAX_REG_MATCH];
int rc = 0;
int basis;
switch (p->ptype) {
case CONDPAT_FILE_EXISTS:
if ( apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
&& sb.filetype == APR_REG) {
rc = 1;
}
break;
case CONDPAT_FILE_SIZE:
if ( apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
&& sb.filetype == APR_REG && sb.size > 0) {
rc = 1;
}
break;
case CONDPAT_FILE_LINK:
#if !defined(OS2)
if ( apr_stat(&sb, input, APR_FINFO_MIN | APR_FINFO_LINK,
r->pool) == APR_SUCCESS
&& sb.filetype == APR_LNK) {
rc = 1;
}
#endif
break;
case CONDPAT_FILE_DIR:
if ( apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
&& sb.filetype == APR_DIR) {
rc = 1;
}
break;
case CONDPAT_FILE_XBIT:
if ( apr_stat(&sb, input, APR_FINFO_PROT, r->pool) == APR_SUCCESS
&& (sb.protection & (APR_UEXECUTE | APR_GEXECUTE | APR_WEXECUTE))) {
rc = 1;
}
break;
case CONDPAT_LU_URL:
if (*input && subreq_ok(r)) {
rsub = ap_sub_req_lookup_uri(input, r, NULL);
if (rsub->status < 400) {
rc = 1;
}
rewritelog((r, 5, NULL, "RewriteCond URI (-U) check: "
"path=%s -> status=%d", input, rsub->status));
ap_destroy_sub_req(rsub);
}
break;
case CONDPAT_LU_FILE:
if (*input && subreq_ok(r)) {
rsub = ap_sub_req_lookup_file(input, r, NULL);
if (rsub->status < 300 &&
/* double-check that file exists since default result is 200 */
apr_stat(&sb, rsub->filename, APR_FINFO_MIN,
r->pool) == APR_SUCCESS) {
rc = 1;
}
rewritelog((r, 5, NULL, "RewriteCond file (-F) check: path=%s "
"-> file=%s status=%d", input, rsub->filename,
rsub->status));
ap_destroy_sub_req(rsub);
}
break;
case CONDPAT_STR_GE:
basis = 0;
goto test_str_g;
case CONDPAT_STR_GT:
basis = 1;
test_str_g:
if (p->flags & CONDFLAG_NOCASE) {
rc = (strcasecmp(input, p->pattern) >= basis) ? 1 : 0;
}
else {
rc = (compare_lexicography(input, p->pattern) >= basis) ? 1 : 0;
}
break;
case CONDPAT_STR_LE:
basis = 0;
goto test_str_l;
case CONDPAT_STR_LT:
basis = -1;
test_str_l:
if (p->flags & CONDFLAG_NOCASE) {
rc = (strcasecmp(input, p->pattern) <= basis) ? 1 : 0;
}
else {
rc = (compare_lexicography(input, p->pattern) <= basis) ? 1 : 0;
}
break;
case CONDPAT_STR_EQ:
/* Note: the only type where the operator is dropped from p->pattern */
if (p->flags & CONDFLAG_NOCASE) {
rc = !strcasecmp(input, p->pattern);
}
else {
rc = !strcmp(input, p->pattern);
}
break;
case CONDPAT_INT_GE: rc = (atoi(input) >= atoi(p->pattern)); break;
case CONDPAT_INT_GT: rc = (atoi(input) > atoi(p->pattern)); break;
case CONDPAT_INT_LE: rc = (atoi(input) <= atoi(p->pattern)); break;
case CONDPAT_INT_LT: rc = (atoi(input) < atoi(p->pattern)); break;
case CONDPAT_INT_EQ: rc = (atoi(input) == atoi(p->pattern)); break;
default:
/* it is really a regexp pattern, so apply it */
rc = !ap_regexec(p->regexp, input, AP_MAX_REG_MATCH, regmatch, 0);
/* update briRC backref info */
if (rc && !(p->flags & CONDFLAG_NOTMATCH)) {
ctx->briRC.source = input;
ctx->briRC.nsub = p->regexp->re_nsub;
memcpy(ctx->briRC.regmatch, regmatch, sizeof(regmatch));
}
break;
}
if (p->flags & CONDFLAG_NOTMATCH) {
rc = !rc;
}
rewritelog((r, 4, ctx->perdir, "RewriteCond: input='%s' pattern='%s'%s "
"=> %s", input, p->pattern - p->pskip,
(p->flags & CONDFLAG_NOCASE) ? " [NC]" : "",
rc ? "matched" : "not-matched"));
return rc;
}
/* check for forced type and handler */
static APR_INLINE void force_type_handler(rewriterule_entry *p,
rewrite_ctx *ctx)
{
char *expanded;
if (p->forced_mimetype) {
expanded = do_expand(p->forced_mimetype, ctx, p);
if (*expanded) {
ap_str_tolower(expanded);
rewritelog((ctx->r, 2, ctx->perdir, "remember %s to have MIME-type "
"'%s'", ctx->r->filename, expanded));
apr_table_setn(ctx->r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR,
expanded);
}
}
if (p->forced_handler) {
expanded = do_expand(p->forced_handler, ctx, p);
if (*expanded) {
ap_str_tolower(expanded);
rewritelog((ctx->r, 2, ctx->perdir, "remember %s to have "
"Content-handler '%s'", ctx->r->filename, expanded));
apr_table_setn(ctx->r->notes, REWRITE_FORCED_HANDLER_NOTEVAR,
expanded);
}
}
}
/*
* Apply a single RewriteRule
*/
static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
{
ap_regmatch_t regmatch[AP_MAX_REG_MATCH];
apr_array_header_t *rewriteconds;
rewritecond_entry *conds;
int i, rc;
char *newuri = NULL;
request_rec *r = ctx->r;
int is_proxyreq = 0;
ctx->uri = r->filename;
if (ctx->perdir) {
apr_size_t dirlen = strlen(ctx->perdir);
/*
* Proxy request?
*/
is_proxyreq = ( r->proxyreq && r->filename
&& !strncmp(r->filename, "proxy:", 6));
/* Since we want to match against the (so called) full URL, we have
* to re-add the PATH_INFO postfix
*/
if (r->path_info && *r->path_info) {
rewritelog((r, 3, ctx->perdir, "add path info postfix: %s -> %s%s",
ctx->uri, ctx->uri, r->path_info));
ctx->uri = apr_pstrcat(r->pool, ctx->uri, r->path_info, NULL);
}
/* Additionally we strip the physical path from the url to match
* it independent from the underlaying filesystem.
*/
if (!is_proxyreq && strlen(ctx->uri) >= dirlen &&
!strncmp(ctx->uri, ctx->perdir, dirlen)) {
rewritelog((r, 3, ctx->perdir, "strip per-dir prefix: %s -> %s",
ctx->uri, ctx->uri + dirlen));
ctx->uri = ctx->uri + dirlen;
}
}
/* Try to match the URI against the RewriteRule pattern
* and exit immediately if it didn't apply.
*/
rewritelog((r, 3, ctx->perdir, "applying pattern '%s' to uri '%s'",
p->pattern, ctx->uri));
rc = !ap_regexec(p->regexp, ctx->uri, AP_MAX_REG_MATCH, regmatch, 0);
if (! (( rc && !(p->flags & RULEFLAG_NOTMATCH)) ||
(!rc && (p->flags & RULEFLAG_NOTMATCH)) ) ) {
return 0;
}
/* It matched, wow! Now it's time to prepare the context structure for
* further processing
*/
ctx->vary_this = NULL;
ctx->briRC.source = NULL;
if (p->flags & RULEFLAG_NOTMATCH) {
ctx->briRR.source = NULL;
}
else {
ctx->briRR.source = apr_pstrdup(r->pool, ctx->uri);
ctx->briRR.nsub = p->regexp->re_nsub;
memcpy(ctx->briRR.regmatch, regmatch, sizeof(regmatch));
}
/* Ok, we already know the pattern has matched, but we now
* additionally have to check for all existing preconditions
* (RewriteCond) which have to be also true. We do this at
* this very late stage to avoid unnessesary checks which
* would slow down the rewriting engine.
*/
rewriteconds = p->rewriteconds;
conds = (rewritecond_entry *)rewriteconds->elts;
for (i = 0; i < rewriteconds->nelts; ++i) {
rewritecond_entry *c = &conds[i];
rc = apply_rewrite_cond(c, ctx);
/*
* Reset vary_this if the novary flag is set for this condition.
*/
if (c->flags & CONDFLAG_NOVARY) {
ctx->vary_this = NULL;
}
if (c->flags & CONDFLAG_ORNEXT) {
if (!rc) {
/* One condition is false, but another can be still true. */
ctx->vary_this = NULL;
continue;
}
else {
/* skip the rest of the chained OR conditions */
while ( i < rewriteconds->nelts
&& c->flags & CONDFLAG_ORNEXT) {
c = &conds[++i];
}
}
}
else if (!rc) {
return 0;
}
/* If some HTTP header was involved in the condition, remember it
* for later use
*/
if (ctx->vary_this) {
ctx->vary = ctx->vary
? apr_pstrcat(r->pool, ctx->vary, ", ", ctx->vary_this,
NULL)
: ctx->vary_this;
ctx->vary_this = NULL;
}
}
/* expand the result */
if (!(p->flags & RULEFLAG_NOSUB)) {
newuri = do_expand(p->output, ctx, p);
rewritelog((r, 2, ctx->perdir, "rewrite '%s' -> '%s'", ctx->uri,
newuri));
}
/* expand [E=var:val] and [CO=<cookie>] */
do_expand_env(p->env, ctx);
do_expand_cookie(p->cookie, ctx);
/* non-substitution rules ('RewriteRule <pat> -') end here. */
if (p->flags & RULEFLAG_NOSUB) {
force_type_handler(p, ctx);
if (p->flags & RULEFLAG_STATUS) {
rewritelog((r, 2, ctx->perdir, "forcing responsecode %d for %s",
p->forced_responsecode, r->filename));
r->status = p->forced_responsecode;
}
return 2;
}
/* Now adjust API's knowledge about r->filename and r->args */
r->filename = newuri;
if (ctx->perdir && (p->flags & RULEFLAG_DISCARDPATHINFO)) {
r->path_info = NULL;
}
splitout_queryargs(r, p->flags & RULEFLAG_QSAPPEND, p->flags & RULEFLAG_QSDISCARD);
/* Add the previously stripped per-directory location prefix, unless
* (1) it's an absolute URL path and
* (2) it's a full qualified URL
*/
if ( ctx->perdir && !is_proxyreq && *r->filename != '/'
&& !is_absolute_uri(r->filename)) {
rewritelog((r, 3, ctx->perdir, "add per-dir prefix: %s -> %s%s",
r->filename, ctx->perdir, r->filename));
r->filename = apr_pstrcat(r->pool, ctx->perdir, r->filename, NULL);
}
/* If this rule is forced for proxy throughput
* (`RewriteRule ... ... [P]') then emulate mod_proxy's
* URL-to-filename handler to be sure mod_proxy is triggered
* for this URL later in the Apache API. But make sure it is
* a fully-qualified URL. (If not it is qualified with
* ourself).
*/
if (p->flags & RULEFLAG_PROXY) {
/* For rules evaluated in server context, the mod_proxy fixup
* hook can be relied upon to escape the URI as and when
* necessary, since it occurs later. If in directory context,
* the ordering of the fixup hooks is forced such that
* mod_proxy comes first, so the URI must be escaped here
* instead. See PR 39746, 46428, and other headaches. */
if (ctx->perdir && (p->flags & RULEFLAG_NOESCAPE) == 0) {
char *old_filename = r->filename;
r->filename = ap_escape_uri(r->pool, r->filename);
rewritelog((r, 2, ctx->perdir, "escaped URI in per-dir context "
"for proxy, %s -> %s", old_filename, r->filename));
}
fully_qualify_uri(r);
rewritelog((r, 2, ctx->perdir, "forcing proxy-throughput with %s",
r->filename));
r->filename = apr_pstrcat(r->pool, "proxy:", r->filename, NULL);
return 1;
}
/* If this rule is explicitly forced for HTTP redirection
* (`RewriteRule .. .. [R]') then force an external HTTP
* redirect. But make sure it is a fully-qualified URL. (If
* not it is qualified with ourself).
*/
if (p->flags & RULEFLAG_FORCEREDIRECT) {
fully_qualify_uri(r);
rewritelog((r, 2, ctx->perdir, "explicitly forcing redirect with %s",
r->filename));
r->status = p->forced_responsecode;
return 1;
}
/* Special Rewriting Feature: Self-Reduction
* We reduce the URL by stripping a possible
* http[s]://<ourhost>[:<port>] prefix, i.e. a prefix which
* corresponds to ourself. This is to simplify rewrite maps
* and to avoid recursion, etc. When this prefix is not a
* coincidence then the user has to use [R] explicitly (see
* above).
*/
reduce_uri(r);
/* If this rule is still implicitly forced for HTTP
* redirection (`RewriteRule .. <scheme>://...') then
* directly force an external HTTP redirect.
*/
if (is_absolute_uri(r->filename)) {
rewritelog((r, 2, ctx->perdir, "implicitly forcing redirect (rc=%d) "
"with %s", p->forced_responsecode, r->filename));
r->status = p->forced_responsecode;
return 1;
}
/* Finally remember the forced mime-type */
force_type_handler(p, ctx);
/* Puuhhhhhhhh... WHAT COMPLICATED STUFF ;_)
* But now we're done for this particular rule.
*/
return 1;
}
/*
* Apply a complete rule set,
* i.e. a list of rewrite rules
*/
static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules,
char *perdir)
{
rewriterule_entry *entries;
rewriterule_entry *p;
int i;
int changed;
int rc;
int s;
rewrite_ctx *ctx;
ctx = apr_palloc(r->pool, sizeof(*ctx));
ctx->perdir = perdir;
ctx->r = r;
/*
* Iterate over all existing rules
*/
entries = (rewriterule_entry *)rewriterules->elts;
changed = 0;
loop:
for (i = 0; i < rewriterules->nelts; i++) {
p = &entries[i];
/*
* Ignore this rule on subrequests if we are explicitly
* asked to do so or this is a proxy-throughput or a
* forced redirect rule.
*/
if (r->main != NULL &&
(p->flags & RULEFLAG_IGNOREONSUBREQ ||
p->flags & RULEFLAG_FORCEREDIRECT )) {
continue;
}
/*
* Apply the current rule.
*/
ctx->vary = NULL;
rc = apply_rewrite_rule(p, ctx);
if (rc) {
/* Regardless of what we do next, we've found a match. Check to see
* if any of the request header fields were involved, and add them
* to the Vary field of the response.
*/
if (ctx->vary) {
apr_table_merge(r->headers_out, "Vary", ctx->vary);
}
/*
* The rule sets the response code (implies match-only)
*/
if (p->flags & RULEFLAG_STATUS) {
return ACTION_STATUS;
}
/*
* Indicate a change if this was not a match-only rule.
*/
if (rc != 2) {
changed = ((p->flags & RULEFLAG_NOESCAPE)
? ACTION_NOESCAPE : ACTION_NORMAL);
}
/*
* Pass-Through Feature (`RewriteRule .. .. [PT]'):
* Because the Apache 1.x API is very limited we
* need this hack to pass the rewritten URL to other
* modules like mod_alias, mod_userdir, etc.
*/
if (p->flags & RULEFLAG_PASSTHROUGH) {
rewritelog((r, 2, perdir, "forcing '%s' to get passed through "
"to next API URI-to-filename handler", r->filename));
r->filename = apr_pstrcat(r->pool, "passthrough:",
r->filename, NULL);
changed = ACTION_NORMAL;
break;
}
if (p->flags & RULEFLAG_END) {
rewritelog((r, 8, perdir, "Rule has END flag, no further rewriting for this request"));
apr_pool_userdata_set("1", really_last_key, apr_pool_cleanup_null, r->pool);
break;
}
/*
* Stop processing also on proxy pass-through and
* last-rule and new-round flags.
*/
if (p->flags & (RULEFLAG_PROXY | RULEFLAG_LASTRULE)) {
break;
}
/*
* On "new-round" flag we just start from the top of
* the rewriting ruleset again.
*/
if (p->flags & RULEFLAG_NEWROUND) {
goto loop;
}
/*
* If we are forced to skip N next rules, do it now.
*/
if (p->skip > 0) {
s = p->skip;
while ( i < rewriterules->nelts
&& s > 0) {
i++;
p = &entries[i];
s--;
}
}
}
else {
/*
* If current rule is chained with next rule(s),
* skip all this next rule(s)
*/
while ( i < rewriterules->nelts
&& p->flags & RULEFLAG_CHAIN) {
i++;
p = &entries[i];
}
}
}
return changed;
}
/*
* +-------------------------------------------------------+
* | |
* | Module Initialization Hooks
* | |
* +-------------------------------------------------------+
*/
static int pre_config(apr_pool_t *pconf,
apr_pool_t *plog,
apr_pool_t *ptemp)
{
APR_OPTIONAL_FN_TYPE(ap_register_rewrite_mapfunc) *map_pfn_register;
ap_mutex_register(pconf, rewritemap_mutex_type, NULL, APR_LOCK_DEFAULT, 0);
/* register int: rewritemap handlers */
map_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_rewrite_mapfunc);
if (map_pfn_register) {
map_pfn_register("tolower", rewrite_mapfunc_tolower);
map_pfn_register("toupper", rewrite_mapfunc_toupper);
map_pfn_register("escape", rewrite_mapfunc_escape);
map_pfn_register("unescape", rewrite_mapfunc_unescape);
}
dbd_acquire = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_acquire);
dbd_prepare = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_prepare);
return OK;
}
static int post_config(apr_pool_t *p,
apr_pool_t *plog,
apr_pool_t *ptemp,
server_rec *s)
{
apr_status_t rv;
void *data;
int first_time = 0;
const char *userdata_key = "rewrite_init_module";
apr_pool_userdata_get(&data, userdata_key, s->process->pool);
if (!data) {
first_time = 1;
apr_pool_userdata_set((const void *)1, userdata_key,
apr_pool_cleanup_null, s->process->pool);
}
/* check if proxy module is available */
proxy_available = (ap_find_linked_module("mod_proxy.c") != NULL);
rv = rewritelock_create(s, p);
if (rv != APR_SUCCESS) {
return HTTP_INTERNAL_SERVER_ERROR;
}
apr_pool_cleanup_register(p, (void *)s, rewritelock_remove,
apr_pool_cleanup_null);
/* step through the servers and
* - open each rewriting logfile
* - open the RewriteMap prg:xxx programs
*/
for (; s; s = s->next) {
if (!first_time) {
if (run_rewritemap_programs(s, p) != APR_SUCCESS) {
return HTTP_INTERNAL_SERVER_ERROR;
}
}
}
rewrite_ssl_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
rewrite_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
return OK;
}
static void init_child(apr_pool_t *p, server_rec *s)
{
apr_status_t rv = 0; /* get a rid of gcc warning (REWRITELOG_DISABLED) */
if (rewrite_mapr_lock_acquire) {
rv = apr_global_mutex_child_init(&rewrite_mapr_lock_acquire,
apr_global_mutex_lockfile(rewrite_mapr_lock_acquire), p);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
"mod_rewrite: could not init rewrite_mapr_lock_acquire"
" in child");
}
}
/* create the lookup cache */
if (!init_cache(p)) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
"mod_rewrite: could not init map cache in child");
}
}
/*
* +-------------------------------------------------------+
* | |
* | runtime hooks
* | |
* +-------------------------------------------------------+
*/
/*
* URI-to-filename hook
* [deals with RewriteRules in server context]
*/
static int hook_uri2file(request_rec *r)
{
rewrite_perdir_conf *dconf;
rewrite_server_conf *conf;
const char *saved_rulestatus;
const char *var;
const char *thisserver;
char *thisport;
const char *thisurl;
unsigned int port;
int rulestatus;
void *skipdata;
/*
* retrieve the config structures
*/
conf = ap_get_module_config(r->server->module_config, &rewrite_module);
dconf = (rewrite_perdir_conf *)ap_get_module_config(r->per_dir_config,
&rewrite_module);
/*
* only do something under runtime if the engine is really enabled,
* else return immediately!
*/
if (!dconf || dconf->state == ENGINE_DISABLED) {
return DECLINED;
}
/*
* check for the ugly API case of a virtual host section where no
* mod_rewrite directives exists. In this situation we became no chance
* by the API to setup our default per-server config so we have to
* on-the-fly assume we have the default config. But because the default
* config has a disabled rewriting engine we are lucky because can
* just stop operating now.
*/
if (conf->server != r->server) {
return DECLINED;
}
/* END flag was used as a RewriteRule flag on this request */
apr_pool_userdata_get(&skipdata, really_last_key, r->pool);
if (skipdata != NULL) {
rewritelog((r, 8, NULL, "Declining, no further rewriting due to END flag"));
return DECLINED;
}
/*
* add the SCRIPT_URL variable to the env. this is a bit complicated
* due to the fact that apache uses subrequests and internal redirects
*/
if (r->main == NULL) {
var = apr_table_get(r->subprocess_env, REDIRECT_ENVVAR_SCRIPT_URL);
if (var == NULL) {
apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URL, r->uri);
}
else {
apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URL, var);
}
}
else {
var = apr_table_get(r->main->subprocess_env, ENVVAR_SCRIPT_URL);
apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URL, var);
}
/*
* create the SCRIPT_URI variable for the env
*/
/* add the canonical URI of this URL */
thisserver = ap_get_server_name_for_url(r);
port = ap_get_server_port(r);
if (ap_is_default_port(port, r)) {
thisport = "";
}
else {
thisport = apr_psprintf(r->pool, ":%u", port);
}
thisurl = apr_table_get(r->subprocess_env, ENVVAR_SCRIPT_URL);
/* set the variable */
var = apr_pstrcat(r->pool, ap_http_scheme(r), "://", thisserver, thisport,
thisurl, NULL);
apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URI, var);
if (!(saved_rulestatus = apr_table_get(r->notes,"mod_rewrite_rewritten"))) {
/* if filename was not initially set,
* we start with the requested URI
*/
if (r->filename == NULL) {
r->filename = apr_pstrdup(r->pool, r->uri);
rewritelog((r, 2, NULL, "init rewrite engine with requested uri %s",
r->filename));
}
else {
rewritelog((r, 2, NULL, "init rewrite engine with passed filename "
"%s. Original uri = %s", r->filename, r->uri));
}
/*
* now apply the rules ...
*/
rulestatus = apply_rewrite_list(r, conf->rewriterules, NULL);
apr_table_set(r->notes,"mod_rewrite_rewritten",
apr_psprintf(r->pool,"%d",rulestatus));
}
else {
rewritelog((r, 2, NULL, "uri already rewritten. Status %s, Uri %s, "
"r->filename %s", saved_rulestatus, r->uri, r->filename));
rulestatus = atoi(saved_rulestatus);
}
if (rulestatus) {
unsigned skip;
apr_size_t flen;
if (ACTION_STATUS == rulestatus) {
int n = r->status;
r->status = HTTP_OK;
return n;
}
flen = r->filename ? strlen(r->filename) : 0;
if (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0) {
/* it should be go on as an internal proxy request */
/* check if the proxy module is enabled, so
* we can actually use it!
*/
if (!proxy_available) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"attempt to make remote request from mod_rewrite "
"without proxy enabled: %s", r->filename);
return HTTP_FORBIDDEN;
}
if (rulestatus == ACTION_NOESCAPE) {
apr_table_setn(r->notes, "proxy-nocanon", "1");
}
/* make sure the QUERY_STRING and
* PATH_INFO parts get incorporated
*/
if (r->path_info != NULL) {
r->filename = apr_pstrcat(r->pool, r->filename,
r->path_info, NULL);
}
if ((r->args != NULL)
&& ((r->proxyreq == PROXYREQ_PROXY)
|| (rulestatus == ACTION_NOESCAPE))) {
/* see proxy_http:proxy_http_canon() */
r->filename = apr_pstrcat(r->pool, r->filename,
"?", r->args, NULL);
}
/* now make sure the request gets handled by the proxy handler */
if (PROXYREQ_NONE == r->proxyreq) {
r->proxyreq = PROXYREQ_REVERSE;
}
r->handler = "proxy-server";
rewritelog((r, 1, NULL, "go-ahead with proxy request %s [OK]",
r->filename));
return OK;
}
else if ((skip = is_absolute_uri(r->filename)) > 0) {
int n;
/* it was finally rewritten to a remote URL */
if (rulestatus != ACTION_NOESCAPE) {
rewritelog((r, 1, NULL, "escaping %s for redirect",
r->filename));
r->filename = escape_absolute_uri(r->pool, r->filename, skip);
}
/* append the QUERY_STRING part */
if (r->args) {
r->filename = apr_pstrcat(r->pool, r->filename, "?",
(rulestatus == ACTION_NOESCAPE)
? r->args
: ap_escape_uri(r->pool, r->args),
NULL);
}
/* determine HTTP redirect response code */
if (ap_is_HTTP_REDIRECT(r->status)) {
n = r->status;
r->status = HTTP_OK; /* make Apache kernel happy */
}
else {
n = HTTP_MOVED_TEMPORARILY;
}
/* now do the redirection */
apr_table_setn(r->headers_out, "Location", r->filename);
rewritelog((r, 1, NULL, "redirect to %s [REDIRECT/%d]", r->filename,
n));
return n;
}
else if (flen > 12 && strncmp(r->filename, "passthrough:", 12) == 0) {
/*
* Hack because of underpowered API: passing the current
* rewritten filename through to other URL-to-filename handlers
* just as it were the requested URL. This is to enable
* post-processing by mod_alias, etc. which always act on
* r->uri! The difference here is: We do not try to
* add the document root
*/
r->uri = apr_pstrdup(r->pool, r->filename+12);
return DECLINED;
}
else {
/* it was finally rewritten to a local path */
/* expand "/~user" prefix */
#if APR_HAS_USER
r->filename = expand_tildepaths(r, r->filename);
#endif
rewritelog((r, 2, NULL, "local path result: %s", r->filename));
/* the filename must be either an absolute local path or an
* absolute local URL.
*/
if ( *r->filename != '/'
&& !ap_os_is_path_absolute(r->pool, r->filename)) {
return HTTP_BAD_REQUEST;
}
/* if there is no valid prefix, we call
* the translator from the core and
* prefix the filename with document_root
*
* NOTICE:
* We cannot leave out the prefix_stat because
* - when we always prefix with document_root
* then no absolute path can be created, e.g. via
* emulating a ScriptAlias directive, etc.
* - when we always NOT prefix with document_root
* then the files under document_root have to
* be references directly and document_root
* gets never used and will be a dummy parameter -
* this is also bad
*
* BUT:
* Under real Unix systems this is no problem,
* because we only do stat() on the first directory
* and this gets cached by the kernel for along time!
*/
if (!prefix_stat(r->filename, r->pool)) {
int res;
char *tmp = r->uri;
r->uri = r->filename;
res = ap_core_translate(r);
r->uri = tmp;
if (res != OK) {
rewritelog((r, 1, NULL, "prefixing with document_root of %s"
" FAILED", r->filename));
return res;
}
rewritelog((r, 2, NULL, "prefixed with document_root to %s",
r->filename));
}
rewritelog((r, 1, NULL, "go-ahead with %s [OK]", r->filename));
return OK;
}
}
else {
rewritelog((r, 1, NULL, "pass through %s", r->filename));
return DECLINED;
}
}
/*
* Fixup hook
* [RewriteRules in directory context]
*/
static int hook_fixup(request_rec *r)
{
rewrite_perdir_conf *dconf;
char *cp;
char *cp2;
const char *ccp;
apr_size_t l;
int rulestatus;
int n;
char *ofilename;
int is_proxyreq;
void *skipdata;
dconf = (rewrite_perdir_conf *)ap_get_module_config(r->per_dir_config,
&rewrite_module);
/* if there is no per-dir config we return immediately */
if (dconf == NULL) {
return DECLINED;
}
/* if there are no real (i.e. no RewriteRule directives!)
per-dir config of us, we return also immediately */
if (dconf->directory == NULL) {
return DECLINED;
}
/*
* Proxy request?
*/
is_proxyreq = ( r->proxyreq && r->filename
&& !strncmp(r->filename, "proxy:", 6));
/*
* .htaccess file is called before really entering the directory, i.e.:
* URL: http://localhost/foo and .htaccess is located in foo directory
* Ignore such attempts, since they may lead to undefined behaviour.
*/
if (!is_proxyreq) {
l = strlen(dconf->directory) - 1;
if (r->filename && strlen(r->filename) == l &&
(dconf->directory)[l] == '/' &&
!strncmp(r->filename, dconf->directory, l)) {
return DECLINED;
}
}
/*
* only do something under runtime if the engine is really enabled,
* for this directory, else return immediately!
*/
if (!dconf || dconf->state == ENGINE_DISABLED) {
return DECLINED;
}
/* END flag was used as a RewriteRule flag on this request */
apr_pool_userdata_get(&skipdata, really_last_key, r->pool);
if (skipdata != NULL) {
rewritelog((r, 8, dconf->directory, "Declining, no further rewriting due to END flag"));
return DECLINED;
}
/*
* Do the Options check after engine check, so
* the user is able to explicitely turn RewriteEngine Off.
*/
if (!(ap_allow_options(r) & (OPT_SYM_LINKS | OPT_SYM_OWNER))) {
/* FollowSymLinks is mandatory! */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Options FollowSymLinks or SymLinksIfOwnerMatch is off "
"which implies that RewriteRule directive is forbidden: "
"%s", r->filename);
return HTTP_FORBIDDEN;
}
/*
* remember the current filename before rewriting for later check
* to prevent deadlooping because of internal redirects
* on final URL/filename which can be equal to the inital one.
* also, we'll restore original r->filename if we decline this
* request
*/
ofilename = r->filename;
if (r->filename == NULL) {
r->filename = apr_pstrdup(r->pool, r->uri);
rewritelog((r, 2, dconf->directory, "init rewrite engine with"
" requested uri %s", r->filename));
}
/*
* now apply the rules ...
*/
rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory);
if (rulestatus) {
unsigned skip;
if (ACTION_STATUS == rulestatus) {
int n = r->status;
r->status = HTTP_OK;
return n;
}
l = strlen(r->filename);
if (l > 6 && strncmp(r->filename, "proxy:", 6) == 0) {
/* it should go on as an internal proxy request */
/* make sure the QUERY_STRING and
* PATH_INFO parts get incorporated
* (r->path_info was already appended by the
* rewriting engine because of the per-dir context!)
*/
if (r->args != NULL) {
r->filename = apr_pstrcat(r->pool, r->filename,
"?", r->args, NULL);
}
/* now make sure the request gets handled by the proxy handler */
if (PROXYREQ_NONE == r->proxyreq) {
r->proxyreq = PROXYREQ_REVERSE;
}
r->handler = "proxy-server";
rewritelog((r, 1, dconf->directory, "go-ahead with proxy request "
"%s [OK]", r->filename));
return OK;
}
else if ((skip = is_absolute_uri(r->filename)) > 0) {
/* it was finally rewritten to a remote URL */
/* because we are in a per-dir context
* first try to replace the directory with its base-URL
* if there is a base-URL available
*/
if (dconf->baseurl != NULL) {
/* skip 'scheme://' */
cp = r->filename + skip;
if ((cp = ap_strchr(cp, '/')) != NULL && *(++cp)) {
rewritelog((r, 2, dconf->directory,
"trying to replace prefix %s with %s",
dconf->directory, dconf->baseurl));
/* I think, that hack needs an explanation:
* well, here is it:
* mod_rewrite was written for unix systems, were
* absolute file-system paths start with a slash.
* URL-paths _also_ start with slashes, so they
* can be easily compared with system paths.
*
* the following assumes, that the actual url-path
* may be prefixed by the current directory path and
* tries to replace the system path with the RewriteBase
* URL.
* That assumption is true if we use a RewriteRule like
*
* RewriteRule ^foo bar [R]
*
* (see apply_rewrite_rule function)
* However on systems that don't have a / as system
* root this will never match, so we skip the / after the
* hostname and compare/substitute only the stuff after it.
*
* (note that cp was already increased to the right value)
*/
cp2 = subst_prefix_path(r, cp, (*dconf->directory == '/')
? dconf->directory + 1
: dconf->directory,
dconf->baseurl + 1);
if (strcmp(cp2, cp) != 0) {
*cp = '\0';
r->filename = apr_pstrcat(r->pool, r->filename,
cp2, NULL);
}
}
}
/* now prepare the redirect... */
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);
}
/* append the QUERY_STRING part */
if (r->args) {
r->filename = apr_pstrcat(r->pool, r->filename, "?",
(rulestatus == ACTION_NOESCAPE)
? r->args
: ap_escape_uri(r->pool, r->args),
NULL);
}
/* determine HTTP redirect response code */
if (ap_is_HTTP_REDIRECT(r->status)) {
n = r->status;
r->status = HTTP_OK; /* make Apache kernel happy */
}
else {
n = HTTP_MOVED_TEMPORARILY;
}
/* now do the redirection */
apr_table_setn(r->headers_out, "Location", r->filename);
rewritelog((r, 1, dconf->directory, "redirect to %s [REDIRECT/%d]",
r->filename, n));
return n;
}
else {
/* it was finally rewritten to a local path */
/* if someone used the PASSTHROUGH flag in per-dir
* context we just ignore it. It is only useful
* in per-server context
*/
if (l > 12 && strncmp(r->filename, "passthrough:", 12) == 0) {
r->filename = apr_pstrdup(r->pool, r->filename+12);
}
/* the filename must be either an absolute local path or an
* absolute local URL.
*/
if ( *r->filename != '/'
&& !ap_os_is_path_absolute(r->pool, r->filename)) {
return HTTP_BAD_REQUEST;
}
/* Check for deadlooping:
* At this point we KNOW that at least one rewriting
* rule was applied, but when the resulting URL is
* the same as the initial URL, we are not allowed to
* use the following internal redirection stuff because
* this would lead to a deadloop.
*/
if (ofilename != NULL && strcmp(r->filename, ofilename) == 0) {
rewritelog((r, 1, dconf->directory, "initial URL equal rewritten"
" URL: %s [IGNORING REWRITE]", r->filename));
return OK;
}
/* if there is a valid base-URL then substitute
* the per-dir prefix with this base-URL if the
* current filename still is inside this per-dir
* context. If not then treat the result as a
* plain URL
*/
if (dconf->baseurl != NULL) {
rewritelog((r, 2, dconf->directory, "trying to replace prefix "
"%s with %s", dconf->directory, dconf->baseurl));
r->filename = subst_prefix_path(r, r->filename,
dconf->directory,
dconf->baseurl);
}
else {
/* if no explicit base-URL exists we assume
* that the directory prefix is also a valid URL
* for this webserver and only try to remove the
* document_root if it is prefix
*/
if ((ccp = ap_document_root(r)) != NULL) {
/* strip trailing slash */
l = strlen(ccp);
if (ccp[l-1] == '/') {
--l;
}
if (!strncmp(r->filename, ccp, l) &&
r->filename[l] == '/') {
rewritelog((r, 2,dconf->directory, "strip document_root"
" prefix: %s -> %s", r->filename,
r->filename+l));
r->filename = apr_pstrdup(r->pool, r->filename+l);
}
}
}
/* now initiate the internal redirect */
rewritelog((r, 1, dconf->directory, "internal redirect with %s "
"[INTERNAL REDIRECT]", r->filename));
r->filename = apr_pstrcat(r->pool, "redirect:", r->filename, NULL);
r->handler = "redirect-handler";
return OK;
}
}
else {
rewritelog((r, 1, dconf->directory, "pass through %s", r->filename));
r->filename = ofilename;
return DECLINED;
}
}
/*
* MIME-type hook
* [T=...,H=...] execution
*/
static int hook_mimetype(request_rec *r)
{
const char *t;
/* type */
t = apr_table_get(r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR);
if (t && *t) {
rewritelog((r, 1, NULL, "force filename %s to have MIME-type '%s'",
r->filename, t));
ap_set_content_type(r, t);
}
/* handler */
t = apr_table_get(r->notes, REWRITE_FORCED_HANDLER_NOTEVAR);
if (t && *t) {
rewritelog((r, 1, NULL, "force filename %s to have the "
"Content-handler '%s'", r->filename, t));
r->handler = t;
}
return OK;
}
/*
* "content" handler for internal redirects
*/
static int handler_redirect(request_rec *r)
{
if (strcmp(r->handler, "redirect-handler")) {
return DECLINED;
}
/* just make sure that we are really meant! */
if (strncmp(r->filename, "redirect:", 9) != 0) {
return DECLINED;
}
/* now do the internal redirect */
ap_internal_redirect(apr_pstrcat(r->pool, r->filename+9,
r->args ? "?" : NULL, r->args, NULL), r);
/* and return gracefully */
return OK;
}
/*
* +-------------------------------------------------------+
* | |
* | Module paraphernalia
* | |
* +-------------------------------------------------------+
*/
static const command_rec command_table[] = {
AP_INIT_FLAG( "RewriteEngine", cmd_rewriteengine, NULL, OR_FILEINFO,
"On or Off to enable or disable (default) the whole "
"rewriting engine"),
AP_INIT_ITERATE( "RewriteOptions", cmd_rewriteoptions, NULL, OR_FILEINFO,
"List of option strings to set"),
AP_INIT_TAKE1( "RewriteBase", cmd_rewritebase, NULL, OR_FILEINFO,
"the base URL of the per-directory context"),
AP_INIT_RAW_ARGS("RewriteCond", cmd_rewritecond, NULL, OR_FILEINFO,
"an input string and a to be applied regexp-pattern"),
AP_INIT_RAW_ARGS("RewriteRule", cmd_rewriterule, NULL, OR_FILEINFO,
"an URL-applied regexp-pattern and a substitution URL"),
AP_INIT_TAKE2( "RewriteMap", cmd_rewritemap, NULL, RSRC_CONF,
"a mapname and a filename"),
{ NULL }
};
static void ap_register_rewrite_mapfunc(char *name, rewrite_mapfunc_t *func)
{
apr_hash_set(mapfunc_hash, name, strlen(name), (const void *)func);
}
static void register_hooks(apr_pool_t *p)
{
/* fixup after mod_proxy, so that the proxied url will not
* escaped accidentally by mod_proxy's fixup.
*/
static const char * const aszPre[]={ "mod_proxy.c", NULL };
/* make the hashtable before registering the function, so that
* other modules are prevented from accessing uninitialized memory.
*/
mapfunc_hash = apr_hash_make(p);
APR_REGISTER_OPTIONAL_FN(ap_register_rewrite_mapfunc);
ap_hook_handler(handler_redirect, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_pre_config(pre_config, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_post_config(post_config, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_child_init(init_child, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_fixups(hook_fixup, aszPre, NULL, APR_HOOK_FIRST);
ap_hook_fixups(hook_mimetype, NULL, NULL, APR_HOOK_LAST);
ap_hook_translate_name(hook_uri2file, NULL, NULL, APR_HOOK_FIRST);
}
/* the main config structure */
AP_DECLARE_MODULE(rewrite) = {
STANDARD20_MODULE_STUFF,
config_perdir_create, /* create per-dir config structures */
config_perdir_merge, /* merge per-dir config structures */
config_server_create, /* create per-server config structures */
config_server_merge, /* merge per-server config structures */
command_table, /* table of config file commands */
register_hooks /* register hooks */
};
/*EOF*/