mod_rewrite.c revision b0c8eb40d588cf647a0bcbccfd51644a198faed9
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"
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#include "apr_global_mutex.h"
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#include "apr_dbm.h"
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#include "apr_dbd.h"
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#include "mod_dbd.h"
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#if APR_HAS_THREADS
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#include "apr_thread_mutex.h"
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#endif
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define APR_WANT_MEMFUNC
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe#define APR_WANT_STRFUNC
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe#define APR_WANT_IOVEC
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include "apr_want.h"
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe/* XXX: Do we really need these headers? */
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#if APR_HAVE_UNISTD_H
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include <unistd.h>
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem#endif
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem#if APR_HAVE_SYS_TYPES_H
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include <sys/types.h>
9f1a88897168c3f1e5009acb585daf01e38a0299jim#endif
9f1a88897168c3f1e5009acb585daf01e38a0299jim#if APR_HAVE_STDARG_H
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#include <stdarg.h>
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#endif
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#if APR_HAVE_STDLIB_H
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#include <stdlib.h>
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#endif
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#if APR_HAVE_CTYPE_H
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#include <ctype.h>
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#endif
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#include "ap_config.h"
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include "httpd.h"
f251b576aa9caeb8876ce9f78fb10bf65eddc97emturk#include "http_config.h"
f251b576aa9caeb8876ce9f78fb10bf65eddc97emturk#include "http_request.h"
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#include "http_core.h"
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#include "http_log.h"
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include "http_protocol.h"
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include "http_vhost.h"
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk
0c888b8088644f3a39dcf1998e0304c289532057jim#include "mod_ssl.h"
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#include "mod_rewrite.h"
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#ifdef AP_NEED_SET_MUTEX_PERMS
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#include "unixd.h"
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#endif
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturkstatic ap_dbd_t *(*dbd_acquire)(request_rec*) = NULL;
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturkstatic void (*dbd_prepare)(server_rec*, const char*, const char*) = NULL;
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe/*
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe * in order to improve performance on running production systems, you
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim * may strip all rewritelog code entirely from mod_rewrite by using the
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe * -DREWRITELOG_DISABLED compiler option.
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe *
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk * DO NOT USE THIS OPTION FOR PUBLIC BINARY RELEASES. Otherwise YOU are
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk * responsible for answering all the mod_rewrite questions out there.
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe */
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#ifndef REWRITELOG_DISABLED
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define rewritelog(x) do_rewritelog x
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#define REWRITELOG_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#define REWRITELOG_FLAGS ( APR_WRITE | APR_APPEND | APR_CREATE )
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#else /* !REWRITELOG_DISABLED */
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#define rewritelog(x)
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#endif /* REWRITELOG_DISABLED */
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim/* remembered mime-type for [T=...] */
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#define REWRITE_FORCED_MIMETYPE_NOTEVAR "rewrite-forced-mimetype"
9621e4c4056383e4a2b844b14687bae500b33a82wrowe#define REWRITE_FORCED_HANDLER_NOTEVAR "rewrite-forced-handler"
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#define ENVVAR_SCRIPT_URL "SCRIPT_URL"
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#define REDIRECT_ENVVAR_SCRIPT_URL "REDIRECT_" ENVVAR_SCRIPT_URL
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#define ENVVAR_SCRIPT_URI "SCRIPT_URI"
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem#define CONDFLAG_NONE 1<<0
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem#define CONDFLAG_NOCASE 1<<1
61d82a1991928d3fa5ee50dc57f2ae3f4b5c781ajim#define CONDFLAG_NOTMATCH 1<<2
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define CONDFLAG_ORNEXT 1<<3
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define CONDFLAG_NOVARY 1<<4
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe
4c67ef499845a08771e81254ce6eb2324a160bc7wrowe#define RULEFLAG_NONE 1<<0
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#define RULEFLAG_FORCEREDIRECT 1<<1
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#define RULEFLAG_LASTRULE 1<<2
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#define RULEFLAG_NEWROUND 1<<3
4c67ef499845a08771e81254ce6eb2324a160bc7wrowe#define RULEFLAG_CHAIN 1<<4
4c67ef499845a08771e81254ce6eb2324a160bc7wrowe#define RULEFLAG_IGNOREONSUBREQ 1<<5
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define RULEFLAG_NOTMATCH 1<<6
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define RULEFLAG_PROXY 1<<7
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define RULEFLAG_PASSTHROUGH 1<<8
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define RULEFLAG_QSAPPEND 1<<9
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define RULEFLAG_NOCASE 1<<10
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define RULEFLAG_NOESCAPE 1<<11
5eb56df4054a0bca4d740eedd7ef277355a2c0adjim#define RULEFLAG_NOSUB 1<<12
5eb56df4054a0bca4d740eedd7ef277355a2c0adjim#define RULEFLAG_STATUS 1<<13
5eb56df4054a0bca4d740eedd7ef277355a2c0adjim#define RULEFLAG_ESCAPEBACKREF 1<<14
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim/* return code of the rewrite rule
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe * the result may be escaped - or not
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe */
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define ACTION_NORMAL 1<<0
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define ACTION_NOESCAPE 1<<1
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define ACTION_STATUS 1<<2
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define MAPTYPE_TXT 1<<0
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe#define MAPTYPE_DBM 1<<1
41c38e78e8e5dc73544571cc2b749d40869e84fawrowe#define MAPTYPE_PRG 1<<2
41c38e78e8e5dc73544571cc2b749d40869e84fawrowe#define MAPTYPE_INT 1<<3
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define MAPTYPE_RND 1<<4
41c38e78e8e5dc73544571cc2b749d40869e84fawrowe#define MAPTYPE_DBD 1<<5
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define MAPTYPE_DBD_CACHE 1<<6
41c38e78e8e5dc73544571cc2b749d40869e84fawrowe
41c38e78e8e5dc73544571cc2b749d40869e84fawrowe#define ENGINE_DISABLED 1<<0
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define ENGINE_ENABLED 1<<1
e8f95a682820a599fe41b22977010636be5c2717jim
b842b65e0618c5535233b197f03dc917d184adb3jim#define OPTION_NONE 1<<0
b842b65e0618c5535233b197f03dc917d184adb3jim#define OPTION_INHERIT 1<<1
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim
b842b65e0618c5535233b197f03dc917d184adb3jim#ifndef RAND_MAX
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#define RAND_MAX 32767
b842b65e0618c5535233b197f03dc917d184adb3jim#endif
b842b65e0618c5535233b197f03dc917d184adb3jim
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim/* max cookie size in rfc 2109 */
b842b65e0618c5535233b197f03dc917d184adb3jim/* XXX: not used at all. We should do a check somewhere and/or cut the cookie */
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe#define MAX_COOKIE_LEN 4096
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk/* max line length (incl.\n) in text rewrite maps */
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#ifndef REWRITE_MAX_TXT_MAP_LINE
1d2ff7570139286b0f0d16f92187a16ed5932291mturk#define REWRITE_MAX_TXT_MAP_LINE 1024
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#endif
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe/* buffer length for prg rewrite maps */
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#ifndef REWRITE_PRG_MAP_BUF
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#define REWRITE_PRG_MAP_BUF 1024
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim#endif
1d2ff7570139286b0f0d16f92187a16ed5932291mturk
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim/* for better readbility */
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe#define LEFT_CURLY '{'
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk#define RIGHT_CURLY '}'
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk/*
4e0b7720fce1e872ea6afd2421b8b6addacf9bd0jim * expansion result items on the stack to save some cycles
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk *
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk * (5 == about 2 variables like "foo%{var}bar%{var}baz")
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk */
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk#define SMALL_EXPANSION 5
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk
e8f95a682820a599fe41b22977010636be5c2717jim/*
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk * check that a subrequest won't cause infinite recursion
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk *
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk * either not in a subrequest, or in a subrequest
e8f95a682820a599fe41b22977010636be5c2717jim * and URIs aren't NULL and sub/main URIs differ
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk */
e2b702094817c78498e6de567b9548ef794c33d3jim#define subreq_ok(r) (!r->main || \
4e0b7720fce1e872ea6afd2421b8b6addacf9bd0jim (r->main->uri && r->uri && strcmp(r->main->uri, r->uri)))
7ce17736e4802a923eed275812647a7c3e9ad76ejim
f73a8fabbdc4ec11c8b475e9f48539de0c4f82ebmturk
e8f95a682820a599fe41b22977010636be5c2717jim/*
07ac837c886b356dc96e83cf82fb348eb56406d9jim * +-------------------------------------------------------+
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim * | |
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim * | Types and Structures
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim * | |
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim * +-------------------------------------------------------+
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim */
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jimtypedef struct {
07ac837c886b356dc96e83cf82fb348eb56406d9jim const char *datafile; /* filename for map data files */
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim const char *dbmtype; /* dbm type for dbm map data files */
07ac837c886b356dc96e83cf82fb348eb56406d9jim const char *checkfile; /* filename to check for map existence */
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim const char *checkfile2; /* as above, NULL if only one file */
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim const char *cachename; /* for cached maps (txt/rnd/dbm) */
07ac837c886b356dc96e83cf82fb348eb56406d9jim int type; /* the type of the map */
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim apr_file_t *fpin; /* in file pointer for program maps */
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim apr_file_t *fpout; /* out file pointer for program maps */
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim apr_file_t *fperr; /* err file pointer for program maps */
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim char *(*func)(request_rec *, /* function pointer for internal maps */
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim char *);
5d392744e2077f71f34ce098ab49d2c0ddcf4ea3jim char **argv; /* argv of the external rewrite map */
188befd3a49e3a126bd801d7dc5a7f6e63ad4332mturk const char *dbdq; /* SQL SELECT statement for rewritemap */
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem} rewritemap_entry;
188befd3a49e3a126bd801d7dc5a7f6e63ad4332mturk
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem/* special pattern types for RewriteCond */
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluemtypedef enum {
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem CONDPAT_REGEX = 0,
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem CONDPAT_FILE_EXISTS,
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim CONDPAT_FILE_SIZE,
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim CONDPAT_FILE_LINK,
188befd3a49e3a126bd801d7dc5a7f6e63ad4332mturk CONDPAT_FILE_DIR,
f185ce14f5dd540ae54659f764989c017c619485jim CONDPAT_FILE_XBIT,
f185ce14f5dd540ae54659f764989c017c619485jim CONDPAT_LU_URL,
f185ce14f5dd540ae54659f764989c017c619485jim CONDPAT_LU_FILE,
f185ce14f5dd540ae54659f764989c017c619485jim CONDPAT_STR_GT,
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim CONDPAT_STR_LT,
f185ce14f5dd540ae54659f764989c017c619485jim CONDPAT_STR_EQ
f921cd430a2ea23fcaedfdfc7439163f63c8472arpluem} pattern_type;
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem
f921cd430a2ea23fcaedfdfc7439163f63c8472arpluemtypedef struct {
f921cd430a2ea23fcaedfdfc7439163f63c8472arpluem char *input; /* Input string of RewriteCond */
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem char *pattern; /* the RegExp pattern string */
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem ap_regex_t *regexp; /* the precompiled regexp */
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem int flags; /* Flags which control the match */
90f18725dbb9bdfba94da22aa60f94dfb759a8ferpluem pattern_type ptype; /* pattern type */
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim} rewritecond_entry;
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim
f921cd430a2ea23fcaedfdfc7439163f63c8472arpluem/* single linked list for env vars and cookies */
bf3f3b52289ee37f40842fc836ff92dd202742afpquernatypedef struct data_item {
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim struct data_item *next;
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim char *data;
2f1146e06a1bfa371573a3f3fb0379448e18aaedjim} data_item;
bf3f3b52289ee37f40842fc836ff92dd202742afpquerna
4415d997ac73262e513c0a571bd5be4f609040bawrowetypedef struct {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk apr_array_header_t *rewriteconds;/* the corresponding RewriteCond entries */
4415d997ac73262e513c0a571bd5be4f609040bawrowe char *pattern; /* the RegExp pattern string */
4415d997ac73262e513c0a571bd5be4f609040bawrowe ap_regex_t *regexp; /* the RegExp pattern compilation */
4415d997ac73262e513c0a571bd5be4f609040bawrowe char *output; /* the Substitution string */
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe int flags; /* Flags which control the substitution */
1febae173a82bc2a71c3c0ba4105cf674000791bjim char *forced_mimetype; /* forced MIME type of substitution */
1febae173a82bc2a71c3c0ba4105cf674000791bjim char *forced_handler; /* forced content handler of subst. */
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe int forced_responsecode; /* forced HTTP response status */
4415d997ac73262e513c0a571bd5be4f609040bawrowe data_item *env; /* added environment variables */
4415d997ac73262e513c0a571bd5be4f609040bawrowe data_item *cookie; /* added cookies */
4415d997ac73262e513c0a571bd5be4f609040bawrowe int skip; /* number of next rules to skip */
4415d997ac73262e513c0a571bd5be4f609040bawrowe} rewriterule_entry;
4415d997ac73262e513c0a571bd5be4f609040bawrowe
4415d997ac73262e513c0a571bd5be4f609040bawrowetypedef struct {
c3dc78855363fa6e8ecfc2bb8e2927efcd31d31djfclere int state; /* the RewriteEngine state */
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk int options; /* the RewriteOption state */
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#ifndef REWRITELOG_DISABLED
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk const char *rewritelogfile; /* the RewriteLog filename */
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk apr_file_t *rewritelogfp; /* the RewriteLog open filepointer */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim int rewriteloglevel; /* the RewriteLog level of verbosity */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim#endif
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim apr_hash_t *rewritemaps; /* the RewriteMap entries */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim apr_array_header_t *rewriteconds; /* the RewriteCond entries (temp.) */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim apr_array_header_t *rewriterules; /* the RewriteRule entries */
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim server_rec *server; /* the corresponding server indicator */
c3dc78855363fa6e8ecfc2bb8e2927efcd31d31djfclere} rewrite_server_conf;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim
c3dc78855363fa6e8ecfc2bb8e2927efcd31d31djfcleretypedef struct {
4415d997ac73262e513c0a571bd5be4f609040bawrowe int state; /* the RewriteEngine state */
4415d997ac73262e513c0a571bd5be4f609040bawrowe int options; /* the RewriteOption state */
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk apr_array_header_t *rewriteconds; /* the RewriteCond entries (temp.) */
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk apr_array_header_t *rewriterules; /* the RewriteRule entries */
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk char *directory; /* the directory where it applies */
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk const char *baseurl; /* the base-URL where it applies */
4415d997ac73262e513c0a571bd5be4f609040bawrowe} rewrite_perdir_conf;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim
4415d997ac73262e513c0a571bd5be4f609040bawrowe/* the (per-child) cache structures.
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim */
4415d997ac73262e513c0a571bd5be4f609040bawrowetypedef struct cache {
4415d997ac73262e513c0a571bd5be4f609040bawrowe apr_pool_t *pool;
4415d997ac73262e513c0a571bd5be4f609040bawrowe apr_hash_t *maps;
4415d997ac73262e513c0a571bd5be4f609040bawrowe#if APR_HAS_THREADS
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk apr_thread_mutex_t *lock;
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk#endif
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk} cache;
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk
01261c7d9578aadd1891f94c8ee03f32ba51db3dmturk/* cached maps contain an mtime for the whole map and live in a subpool
4415d997ac73262e513c0a571bd5be4f609040bawrowe * of the cachep->pool. That makes it easy to forget them if necessary.
4415d997ac73262e513c0a571bd5be4f609040bawrowe */
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowetypedef struct {
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim apr_time_t mtime;
4415d997ac73262e513c0a571bd5be4f609040bawrowe apr_pool_t *pool;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk apr_hash_t *entries;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk} cachedmap;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk/* the regex structure for the
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk * substitution of backreferences
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk */
00b70ae978854b5eb51722cbeda99c9067b5faf2mturktypedef struct backrefinfo {
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim char *source;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim int nsub;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk ap_regmatch_t regmatch[AP_MAX_REG_MATCH];
9e3209bc06ddf32f23e4b254faa45914bc323cc9jim} backrefinfo;
c332befc1519a1016d8de07608f0b859e6fab580jim
361051c5d96d51ff2f707777b8f629a56799ef02jorton/* single linked list used for
361051c5d96d51ff2f707777b8f629a56799ef02jorton * variable expansion
596716fb99c98e83ff7c2c3d78f9fc55ea116be6jim */
c332befc1519a1016d8de07608f0b859e6fab580jimtypedef struct result_list {
1febae173a82bc2a71c3c0ba4105cf674000791bjim struct result_list *next;
1febae173a82bc2a71c3c0ba4105cf674000791bjim apr_size_t len;
9e3209bc06ddf32f23e4b254faa45914bc323cc9jim const char *string;
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim} result_list;
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim/* context structure for variable lookup and expansion
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim */
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jimtypedef struct {
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim request_rec *r;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim const char *uri;
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim const char *vary_this;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim const char *vary;
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim char *perdir;
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim backrefinfo briRR;
ff4ec92f5bb8d43b3ba1979ccda94f07961bf323jim backrefinfo briRC;
b92a868b537899a51efd8c200c396fa51c63839dtrawick} rewrite_ctx;
9f22e9ea026e74271ddced44f6d54fa846ddc9bcwrowe
d46dfdce9351f52a971777948d9b02f8fc668ff8niq/*
d46dfdce9351f52a971777948d9b02f8fc668ff8niq * +-------------------------------------------------------+
d46dfdce9351f52a971777948d9b02f8fc668ff8niq * | |
9f22e9ea026e74271ddced44f6d54fa846ddc9bcwrowe * | static module data
9f22e9ea026e74271ddced44f6d54fa846ddc9bcwrowe * | |
d46dfdce9351f52a971777948d9b02f8fc668ff8niq * +-------------------------------------------------------+
d46dfdce9351f52a971777948d9b02f8fc668ff8niq */
9f22e9ea026e74271ddced44f6d54fa846ddc9bcwrowe
d46dfdce9351f52a971777948d9b02f8fc668ff8niq/* the global module structure */
d46dfdce9351f52a971777948d9b02f8fc668ff8niqmodule AP_MODULE_DECLARE_DATA rewrite_module;
d46dfdce9351f52a971777948d9b02f8fc668ff8niq
3a49a6c98ef80c71830e66e7f8f46083001b494ctrawick/* rewritemap int: handler function registry */
d46dfdce9351f52a971777948d9b02f8fc668ff8niqstatic apr_hash_t *mapfunc_hash;
d46dfdce9351f52a971777948d9b02f8fc668ff8niq
b92a868b537899a51efd8c200c396fa51c63839dtrawick/* the cache */
d46dfdce9351f52a971777948d9b02f8fc668ff8niqstatic cache *cachep;
d46dfdce9351f52a971777948d9b02f8fc668ff8niq
d46dfdce9351f52a971777948d9b02f8fc668ff8niq/* whether proxy module is available or not */
d46dfdce9351f52a971777948d9b02f8fc668ff8niqstatic int proxy_available;
d46dfdce9351f52a971777948d9b02f8fc668ff8niq
a652b68dea502131f70084ead7981d5fc754cd34jim/* whether random seed can be reaped */
a652b68dea502131f70084ead7981d5fc754cd34jimstatic int rewrite_rand_init_done = 0;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim
a652b68dea502131f70084ead7981d5fc754cd34jim/* Locks/Mutexes */
a652b68dea502131f70084ead7981d5fc754cd34jimstatic const char *lockname;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jimstatic apr_global_mutex_t *rewrite_mapr_lock_acquire = NULL;
a652b68dea502131f70084ead7981d5fc754cd34jim
a652b68dea502131f70084ead7981d5fc754cd34jim#ifndef REWRITELOG_DISABLED
a652b68dea502131f70084ead7981d5fc754cd34jimstatic apr_global_mutex_t *rewrite_log_lock = NULL;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim#endif
a652b68dea502131f70084ead7981d5fc754cd34jim
a652b68dea502131f70084ead7981d5fc754cd34jim/* Optional functions imported from mod_ssl when loaded: */
a652b68dea502131f70084ead7981d5fc754cd34jimstatic APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *rewrite_ssl_lookup = NULL;
a652b68dea502131f70084ead7981d5fc754cd34jimstatic APR_OPTIONAL_FN_TYPE(ssl_is_https) *rewrite_is_https = NULL;
a652b68dea502131f70084ead7981d5fc754cd34jim
a652b68dea502131f70084ead7981d5fc754cd34jim/*
a652b68dea502131f70084ead7981d5fc754cd34jim * +-------------------------------------------------------+
a652b68dea502131f70084ead7981d5fc754cd34jim * | |
a652b68dea502131f70084ead7981d5fc754cd34jim * | rewriting logfile support
4415d997ac73262e513c0a571bd5be4f609040bawrowe * | |
65efbf0826de766a90d745cc44427bfa4e2447b6mturk * +-------------------------------------------------------+
4415d997ac73262e513c0a571bd5be4f609040bawrowe */
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowe#ifndef REWRITELOG_DISABLED
38fd849bd99e2765ee633b6dc576b5f17acdc455wrowestatic char *current_logtime(request_rec *r)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_time_exp_t t;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding char tstr[80];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_size_t len;
00211b036b78699ace57a6d800a52e6c2d57652fnd
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_time_exp_lt(&t, apr_time_now());
00211b036b78699ace57a6d800a52e6c2d57652fnd
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard apr_strftime(tstr, &len, sizeof(tstr), "[%d/%b/%Y:%H:%M:%S ", &t);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard apr_snprintf(tstr+len, sizeof(tstr)-len, "%c%.2d%.2d]",
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard t.tm_gmtoff < 0 ? '-' : '+',
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard t.tm_gmtoff / (60*60), t.tm_gmtoff % (60*60));
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return apr_pstrdup(r->pool, tstr);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard}
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddardstatic int open_rewritelog(server_rec *s, apr_pool_t *p)
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard{
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard rewrite_server_conf *conf;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard const char *fname;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard conf = ap_get_module_config(s->module_config, &rewrite_module);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard /* - no logfile configured
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * - logfilename empty
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * - virtual log shared w/ main server
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
00211b036b78699ace57a6d800a52e6c2d57652fnd if (!conf->rewritelogfile || !*conf->rewritelogfile || conf->rewritelogfp) {
00211b036b78699ace57a6d800a52e6c2d57652fnd return 1;
00211b036b78699ace57a6d800a52e6c2d57652fnd }
00211b036b78699ace57a6d800a52e6c2d57652fnd
00211b036b78699ace57a6d800a52e6c2d57652fnd if (*conf->rewritelogfile == '|') {
00211b036b78699ace57a6d800a52e6c2d57652fnd piped_log *pl;
00211b036b78699ace57a6d800a52e6c2d57652fnd
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding fname = ap_server_root_relative(p, conf->rewritelogfile+1);
50b2d068ddf98cf75622a0020cd143d379d1b235jfclere if (!fname) {
50b2d068ddf98cf75622a0020cd143d379d1b235jfclere ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s,
50b2d068ddf98cf75622a0020cd143d379d1b235jfclere "mod_rewrite: Invalid RewriteLog "
35630e8756729a29273ef1a5c879b90df3594d66rjung "path %s", conf->rewritelogfile+1);
50b2d068ddf98cf75622a0020cd143d379d1b235jfclere return 0;
50b2d068ddf98cf75622a0020cd143d379d1b235jfclere }
50b2d068ddf98cf75622a0020cd143d379d1b235jfclere
00211b036b78699ace57a6d800a52e6c2d57652fnd if ((pl = ap_open_piped_log(p, fname)) == NULL) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard "mod_rewrite: could not open reliable pipe "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "to RewriteLog filter %s", fname);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding conf->rewritelogfp = ap_piped_log_write_fd(pl);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_status_t rc;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding fname = ap_server_root_relative(p, conf->rewritelogfile);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!fname) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "mod_rewrite: Invalid RewriteLog "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "path %s", conf->rewritelogfile);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ((rc = apr_file_open(&conf->rewritelogfp, fname,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding REWRITELOG_FLAGS, REWRITELOG_MODE, p))
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding != APR_SUCCESS) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_ERR, rc, s,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "mod_rewrite: could not open RewriteLog "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "file %s", fname);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return 0;
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq }
a812b025d139f465a31c76fc02ed162ed5271b03nd }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
16d38ac65d7e54cd44eeda7b23f84ee68b35094ewrowe return 1;
16d38ac65d7e54cd44eeda7b23f84ee68b35094ewrowe}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddardstatic void do_rewritelog(request_rec *r, int level, char *perdir,
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard const char *fmt, ...)
7b6ba9c468f26bdb3492d5e8cb79628a3b04e8c8wrowe{
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard rewrite_server_conf *conf;
e8f95a682820a599fe41b22977010636be5c2717jim char *logline, *text;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard const char *rhost, *rname;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard apr_size_t nbytes;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard int redir;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard apr_status_t rv;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard request_rec *req;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding va_list ap;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding conf = ap_get_module_config(r->server->module_config, &rewrite_module);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if (!conf->rewritelogfp || level > conf->rewriteloglevel) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard 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;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq }
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq va_start(ap, fmt);
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq text = apr_pvsprintf(r->pool, fmt, ap);
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq va_end(ap);
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq logline = apr_psprintf(r->pool, "%s %s %s %s [%s/sid#%pp][rid#%pp/%s%s%s] "
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq "(%d) %s%s%s%s" APR_EOL_STR,
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq rhost ? rhost : "UNKNOWN-HOST",
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq rname ? rname : "-",
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq r->user ? (*r->user ? r->user : "\"\"") : "-",
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq current_logtime(r),
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq ap_get_server_name(r),
188befd3a49e3a126bd801d7dc5a7f6e63ad4332mturk (void *)(r->server),
9df9016759ec9327e256d7fff1af56ddfadb721cniq (void *)r,
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq r->main ? "subreq" : "initial",
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq redir ? "/redir#" : "",
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq redir ? apr_itoa(r->pool, redir) : "",
9df9016759ec9327e256d7fff1af56ddfadb721cniq level,
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq perdir ? "[perdir " : "",
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq perdir ? perdir : "",
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq perdir ? "] ": "",
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq text);
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq rv = apr_global_mutex_lock(rewrite_log_lock);
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq if (rv != APR_SUCCESS) {
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq "apr_global_mutex_lock(rewrite_log_lock) failed");
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq /* XXX: Maybe this should be fatal? */
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq }
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq nbytes = strlen(logline);
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq apr_file_write(conf->rewritelogfp, logline, &nbytes);
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq rv = apr_global_mutex_unlock(rewrite_log_lock);
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq if (rv != APR_SUCCESS) {
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq "apr_global_mutex_unlock(rewrite_log_lock) failed");
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq /* XXX: Maybe this should be fatal? */
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq }
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq return;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq}
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq#endif /* !REWRITELOG_DISABLED */
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
997023faa943892aae20d092044aa983c2936982niq/*
997023faa943892aae20d092044aa983c2936982niq * +-------------------------------------------------------+
997023faa943892aae20d092044aa983c2936982niq * | |
997023faa943892aae20d092044aa983c2936982niq * | URI and path functions
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq * | |
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq * +-------------------------------------------------------+
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq */
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin/* return number of chars of the scheme (incl. '://')
df419be6d7d4b68823efa05722375552af49c2b6minfrin * if the URI is absolute (includes a scheme etc.)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * otherwise 0.
df419be6d7d4b68823efa05722375552af49c2b6minfrin *
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq * NOTE: If you add new schemes here, please have a
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq * look at escape_absolute_uri and splitout_queryargs.
dcda744296f197717c5105fd197e94ceba7880d7jim * Not every scheme takes query strings and some schemes
28fe44817329b1183f64e878c258962f90423a8dniq * may be handled in a special way.
dcda744296f197717c5105fd197e94ceba7880d7jim *
28fe44817329b1183f64e878c258962f90423a8dniq * XXX: we may consider a scheme registry, perhaps with
df419be6d7d4b68823efa05722375552af49c2b6minfrin * appropriate escape callbacks to allow other modules
df419be6d7d4b68823efa05722375552af49c2b6minfrin * to extend mod_rewrite at runtime.
df419be6d7d4b68823efa05722375552af49c2b6minfrin */
df419be6d7d4b68823efa05722375552af49c2b6minfrinstatic unsigned is_absolute_uri(char *uri)
df419be6d7d4b68823efa05722375552af49c2b6minfrin{
df419be6d7d4b68823efa05722375552af49c2b6minfrin /* fast exit */
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (*uri == '/' || strlen(uri) <= 5) {
df419be6d7d4b68823efa05722375552af49c2b6minfrin return 0;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin switch (*uri++) {
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'a':
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'A':
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (!strncasecmp(uri, "jp://", 5)) { /* ajp:// */
df419be6d7d4b68823efa05722375552af49c2b6minfrin return 6;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin break;
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'b':
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'B':
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (!strncasecmp(uri, "alancer://", 10)) { /* balancer:// */
df419be6d7d4b68823efa05722375552af49c2b6minfrin return 11;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin break;
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'f':
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'F':
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (!strncasecmp(uri, "tp://", 5)) { /* ftp:// */
df419be6d7d4b68823efa05722375552af49c2b6minfrin return 6;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (!strncasecmp(uri, "cgi://", 6)) { /* fcgi:// */
df419be6d7d4b68823efa05722375552af49c2b6minfrin return 7;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin break;
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'g':
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'G':
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (!strncasecmp(uri, "opher://", 8)) { /* gopher:// */
df419be6d7d4b68823efa05722375552af49c2b6minfrin return 9;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin break;
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'h':
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'H':
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (!strncasecmp(uri, "ttp://", 6)) { /* http:// */
df419be6d7d4b68823efa05722375552af49c2b6minfrin return 7;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin else if (!strncasecmp(uri, "ttps://", 7)) { /* https:// */
df419be6d7d4b68823efa05722375552af49c2b6minfrin return 8;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin break;
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'l':
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'L':
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (!strncasecmp(uri, "dap://", 6)) { /* ldap:// */
df419be6d7d4b68823efa05722375552af49c2b6minfrin return 7;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin break;
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'm':
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'M':
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (!strncasecmp(uri, "ailto:", 6)) { /* mailto: */
df419be6d7d4b68823efa05722375552af49c2b6minfrin return 7;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin break;
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin case 'n':
df419be6d7d4b68823efa05722375552af49c2b6minfrin 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
df419be6d7d4b68823efa05722375552af49c2b6minfrin return 0;
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;
a812b025d139f465a31c76fc02ed162ed5271b03nd
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* be safe.
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * NULL should indicate elsewhere, that something's wrong
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard */
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if (!scheme || strlen(uri) < scheme) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
a812b025d139f465a31c76fc02ed162ed5271b03nd
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding cp = uri + scheme;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* scheme with authority part? */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (cp[-1] == '/') {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* skip host part */
df419be6d7d4b68823efa05722375552af49c2b6minfrin while (*cp && *cp != '/') {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard ++cp;
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin /* nothing after the hostpart. ready! */
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (!*cp || !*++cp) {
df419be6d7d4b68823efa05722375552af49c2b6minfrin return apr_pstrdup(p, uri);
28fe44817329b1183f64e878c258962f90423a8dniq }
df419be6d7d4b68823efa05722375552af49c2b6minfrin
28fe44817329b1183f64e878c258962f90423a8dniq /* remember the hostname stuff */
df419be6d7d4b68823efa05722375552af49c2b6minfrin scheme = cp - uri;
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin /* special thing for ldap.
df419be6d7d4b68823efa05722375552af49c2b6minfrin * The parts are separated by question marks. From RFC 2255:
df419be6d7d4b68823efa05722375552af49c2b6minfrin * ldapurl = scheme "://" [hostport] ["/"
df419be6d7d4b68823efa05722375552af49c2b6minfrin * [dn ["?" [attributes] ["?" [scope]
df419be6d7d4b68823efa05722375552af49c2b6minfrin * ["?" [filter] ["?" extensions]]]]]]
df419be6d7d4b68823efa05722375552af49c2b6minfrin */
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (!strncasecmp(uri, "ldap", 4)) {
df419be6d7d4b68823efa05722375552af49c2b6minfrin char *token[5];
28fe44817329b1183f64e878c258962f90423a8dniq int c = 0;
dcda744296f197717c5105fd197e94ceba7880d7jim
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding token[0] = cp = apr_pstrdup(p, cp);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding while (*cp && c < 4) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (*cp == '?') {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding token[++c] = cp + 1;
9b3001f2097437c3c605d29e353fda5131b9952bminfrin *cp = '\0';
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe ++cp;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe return apr_pstrcat(p, apr_pstrndup(p, uri, scheme),
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe ap_escape_uri(p, token[0]),
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe (c >= 1) ? "?" : NULL,
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe (c >= 1) ? ap_escape_uri(p, token[1]) : NULL,
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard (c >= 2) ? "?" : NULL,
e8f95a682820a599fe41b22977010636be5c2717jim (c >= 2) ? ap_escape_uri(p, token[2]) : NULL,
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard (c >= 3) ? "?" : NULL,
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe (c >= 3) ? ap_escape_uri(p, token[3]) : NULL,
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe (c >= 4) ? "?" : NULL,
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe (c >= 4) ? ap_escape_uri(p, token[4]) : NULL,
e8f95a682820a599fe41b22977010636be5c2717jim NULL);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
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);
e8f95a682820a599fe41b22977010636be5c2717jim}
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
e8f95a682820a599fe41b22977010636be5c2717jim/*
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * split out a QUERY_STRING part from
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * the current URI string
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe */
e8f95a682820a599fe41b22977010636be5c2717jimstatic void splitout_queryargs(request_rec *r, int qsappend)
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe{
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe char *q;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe /* 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)
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe && strncasecmp(r->filename, "mailto", 6)) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe r->args = NULL; /* forget the query that's still flying around */
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe return;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe q = ap_strchr(r->filename, '?');
8632261c895a84c88ae6ade6ea4c62b27bd22b3ebrianp 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 }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq len = strlen(r->args);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!len) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->args = NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else if (r->args[len-1] == '&') {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->args[len-1] = '\0';
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 3, NULL, "split uri=%s -> uri=%s, args=%s", olduri,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->filename, r->args ? r->args : "<none>"));
68ce856106f153813339db8670f6cd0ab8dea484minfrin }
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq return;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
45dac0729754e413ff7c673481b219e9ab1a11f1bnicholes
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard/*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * strip 'http[s]://ourhost/' from URI
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic void reduce_uri(request_rec *r)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq char *cp;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq apr_size_t l;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq cp = (char *)ap_http_scheme(r);
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq l = strlen(cp);
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq if ( strlen(r->filename) > l+3
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq && strncasecmp(r->filename, cp, l) == 0
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq && r->filename[l] == ':'
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq && r->filename[l+1] == '/'
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq && r->filename[l+2] == '/' ) {
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
68ce856106f153813339db8670f6cd0ab8dea484minfrin unsigned short port;
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin char *portp, *host, *url, *scratch;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
68ce856106f153813339db8670f6cd0ab8dea484minfrin scratch = apr_pstrdup(r->pool, r->filename); /* our scratchpad */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* cut the hostname and port out of the URI */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding cp = host = scratch + l + 3; /* 3 == strlen("://") */
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard while (*cp && *cp != '/' && *cp != ':') {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ++cp;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
11c3b5180e1de6776035320b012a28bb146e7b46chuck if (*cp == ':') { /* additional port given */
11c3b5180e1de6776035320b012a28bb146e7b46chuck *cp++ = '\0';
11c3b5180e1de6776035320b012a28bb146e7b46chuck portp = cp;
11c3b5180e1de6776035320b012a28bb146e7b46chuck while (*cp && *cp != '/') {
11c3b5180e1de6776035320b012a28bb146e7b46chuck ++cp;
11c3b5180e1de6776035320b012a28bb146e7b46chuck }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *cp = '\0';
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding port = atoi(portp);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding url = r->filename + (cp - scratch);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!*url) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding url = "/";
d7387fcd4969206172e3a2a8bbcd25a3d7011ac5rbb }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else if (*cp == '/') { /* default port */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *cp = '\0';
d4a7ca64aa12da0c1b44b0281e93973a89cefeedmartin
d4a7ca64aa12da0c1b44b0281e93973a89cefeedmartin port = ap_default_port(r);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding url = r->filename + (cp - scratch);
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else {
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm port = ap_default_port(r);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding url = "/";
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm /* now check whether we could reduce it to a local path... */
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if (ap_matches_request_vhost(r, host, port)) {
b999f6ba2a266bf9a92687f31bb7e76021ac5891ianh rewritelog((r, 3, NULL, "reduce %s -> %s", r->filename, url));
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard r->filename = apr_pstrdup(r->pool, url);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
1cde33c7e2019830f8fb3224e01649305583916etrawick return;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard}
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard/*
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard * add 'http[s]://ourhost[:ourport]/' to URI
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * if URI is still not fully qualified
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic void fully_qualify_uri(request_rec *r)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!is_absolute_uri(r->filename)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *thisserver;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding char *thisport;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding int port;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
a8523e2451f03f4a30030b7bda643a23a75d91demturk thisserver = ap_get_server_name(r);
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb port = ap_get_server_port(r);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding thisport = ap_is_default_port(port, r)
5babe00918c88eda487771fa6d6d4a1a19c0ced0chuck ? ""
5babe00918c88eda487771fa6d6d4a1a19c0ced0chuck : apr_psprintf(r->pool, ":%u", port);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->filename = apr_psprintf(r->pool, "%s://%s%s%s%s",
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin ap_http_scheme(r), thisserver, thisport,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding (*r->filename == '/') ? "" : "/",
35c9e4d2c0a6465746a98958ef756114834461e6minfrin r->filename);
35c9e4d2c0a6465746a98958ef756114834461e6minfrin }
5a5a6c22260854843c973e2ea9a14bec64362ab5wrowe
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe return;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk}
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk
11c3b5180e1de6776035320b012a28bb146e7b46chuck/*
35c9e4d2c0a6465746a98958ef756114834461e6minfrin * stat() only the first segment of a path
45dac0729754e413ff7c673481b219e9ab1a11f1bnicholes */
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddardstatic int prefix_stat(const char *path, apr_pool_t *pool)
11c3b5180e1de6776035320b012a28bb146e7b46chuck{
35c9e4d2c0a6465746a98958ef756114834461e6minfrin const char *curpath = path;
35c9e4d2c0a6465746a98958ef756114834461e6minfrin const char *root;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard const char *slash;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard char *statpath;
e2b2e15108eb7cb566b1d70ce4e479276d951de5minfrin apr_status_t rv;
e2b2e15108eb7cb566b1d70ce4e479276d951de5minfrin
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard rv = apr_filepath_root(&root, &curpath, APR_FILEPATH_TRUENAME, pool);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if (rv != APR_SUCCESS) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return 0;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
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 {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard rv = apr_filepath_merge(&statpath, root, curpath,
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard APR_FILEPATH_NOTABOVEROOT |
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard APR_FILEPATH_NOTRELATIVE, pool);
e2b2e15108eb7cb566b1d70ce4e479276d951de5minfrin }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if (rv == APR_SUCCESS) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard apr_finfo_t sb;
35c9e4d2c0a6465746a98958ef756114834461e6minfrin
35c9e4d2c0a6465746a98958ef756114834461e6minfrin if (apr_stat(&sb, statpath, APR_FINFO_MIN, pool) == APR_SUCCESS) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return 1;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
3d81c6f18deabacd15101eda69f7d16bf466d22dniq
3d81c6f18deabacd15101eda69f7d16bf466d22dniq return 0;
3d81c6f18deabacd15101eda69f7d16bf466d22dniq}
3d81c6f18deabacd15101eda69f7d16bf466d22dniq
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/*
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe * substitute the prefix path 'match' in 'input' with 'subst' (RewriteBase)
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe */
d1b3d9a6f29078146ee970791123a8720bf38c39wrowestatic char *subst_prefix_path(request_rec *r, char *input, char *match,
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe const char *subst)
e8f95a682820a599fe41b22977010636be5c2717jim{
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe apr_size_t len = strlen(match);
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe if (len && match[len - 1] == '/') {
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe --len;
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe }
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe if (!strncmp(input, match, len) && input[len++] == '/') {
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe apr_size_t slen, outlen;
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe char *output;
b5983a3623a081981a69c201fb66f765586aaa9eniq
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;
e8f95a682820a599fe41b22977010636be5c2717jim }
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe 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 }
d1b3d9a6f29078146ee970791123a8720bf38c39wrowe 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
a8523e2451f03f4a30030b7bda643a23a75d91demturk return output;
a8523e2451f03f4a30030b7bda643a23a75d91demturk }
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk /* prefix didn't match */
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk return input;
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk}
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk/*
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk * +-------------------------------------------------------+
a8523e2451f03f4a30030b7bda643a23a75d91demturk * | |
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk * | caching support
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk * | |
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk * +-------------------------------------------------------+
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk */
a8523e2451f03f4a30030b7bda643a23a75d91demturk
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturkstatic void set_cache_value(const char *name, apr_time_t t, char *key,
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk char *val)
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk{
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk cachedmap *map;
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk if (cachep) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#if APR_HAS_THREADS
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk apr_thread_mutex_lock(cachep->lock);
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk#endif
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk map = apr_hash_get(cachep->maps, name, APR_HASH_KEY_STRING);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk if (!map) {
e2458a81ee951feeff648c2ca5cad2c5a744d8e5mturk apr_pool_t *p;
a8523e2451f03f4a30030b7bda643a23a75d91demturk
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk if (apr_pool_create(&p, cachep->pool) != APR_SUCCESS) {
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk#if APR_HAS_THREADS
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem apr_thread_mutex_unlock(cachep->lock);
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem#endif
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem return;
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem }
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem map = apr_palloc(cachep->pool, sizeof(cachedmap));
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem map->pool = p;
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem map->entries = apr_hash_make(map->pool);
8cdc2e8b6f46a3f239a70184e9f785fc25463487rpluem 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;
6a4043fd04bbd44ca0d084c096318df035abc46djfclere }
6a4043fd04bbd44ca0d084c096318df035abc46djfclere
6a4043fd04bbd44ca0d084c096318df035abc46djfclere /* Now we should have a valid map->entries hash, where we
14c8c18e6caab1bdeb0f26b2b031e000fef58ef9jim * can store our value.
6a4043fd04bbd44ca0d084c096318df035abc46djfclere *
6a4043fd04bbd44ca0d084c096318df035abc46djfclere * We need to copy the key and the value into OUR pool,
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim * so that we don't leave it during the r->pool cleanup.
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim */
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk apr_hash_set(map->entries,
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk apr_pstrdup(map->pool, key), APR_HASH_KEY_STRING,
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk apr_pstrdup(map->pool, val));
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk#if APR_HAS_THREADS
b1306729566b49fb30aed5c46adaf07a637115afjerenkrantz apr_thread_mutex_unlock(cachep->lock);
b1306729566b49fb30aed5c46adaf07a637115afjerenkrantz#endif
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk }
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk return;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk}
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk
00b70ae978854b5eb51722cbeda99c9067b5faf2mturkstatic char *get_cache_value(const char *name, apr_time_t t, char *key,
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk apr_pool_t *p)
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk{
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk cachedmap *map;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk char *val = NULL;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk if (cachep) {
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk#if APR_HAS_THREADS
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem apr_thread_mutex_lock(cachep->lock);
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem#endif
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem map = apr_hash_get(cachep->maps, name, APR_HASH_KEY_STRING);
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem if (map) {
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem /* if this map is outdated, forget it. */
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem if (map->mtime != t) {
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem apr_pool_clear(map->pool);
5fbd1e97905738791e7359ccbc9b02e913948d2erpluem 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) {
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk cachep = NULL; /* turns off cache */
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return 0;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin cachep->maps = apr_hash_make(cachep->pool);
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk#if APR_HAS_THREADS
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk (void)apr_thread_mutex_create(&(cachep->lock), APR_THREAD_MUTEX_DEFAULT, p);
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk#endif
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk return 1;
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk}
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk/*
a42b70fa75429d73ef00d6ae212676f8a652f51cpquerna * +-------------------------------------------------------+
a8523e2451f03f4a30030b7bda643a23a75d91demturk * | |
a8523e2451f03f4a30030b7bda643a23a75d91demturk * | Map Functions
a8523e2451f03f4a30030b7bda643a23a75d91demturk * | |
a8523e2451f03f4a30030b7bda643a23a75d91demturk * +-------------------------------------------------------+
a8523e2451f03f4a30030b7bda643a23a75d91demturk */
a8523e2451f03f4a30030b7bda643a23a75d91demturk
a8523e2451f03f4a30030b7bda643a23a75d91demturk/*
a8523e2451f03f4a30030b7bda643a23a75d91demturk * General Note: key is already a fresh string, created (expanded) just
a8523e2451f03f4a30030b7bda643a23a75d91demturk * for the purpose to be passed in here. So one can modify key itself.
12d1342bd29aa7b15080f28cd8ed65d33ce00328rpluem */
a8523e2451f03f4a30030b7bda643a23a75d91demturk
12d1342bd29aa7b15080f28cd8ed65d33ce00328rpluemstatic char *rewrite_mapfunc_toupper(request_rec *r, char *key)
12d1342bd29aa7b15080f28cd8ed65d33ce00328rpluem{
00b70ae978854b5eb51722cbeda99c9067b5faf2mturk char *p;
a8523e2451f03f4a30030b7bda643a23a75d91demturk
a8523e2451f03f4a30030b7bda643a23a75d91demturk for (p = key; *p; ++p) {
a8523e2451f03f4a30030b7bda643a23a75d91demturk *p = apr_toupper(*p);
e8f95a682820a599fe41b22977010636be5c2717jim }
a8523e2451f03f4a30030b7bda643a23a75d91demturk
a8523e2451f03f4a30030b7bda643a23a75d91demturk return key;
a8523e2451f03f4a30030b7bda643a23a75d91demturk}
a8523e2451f03f4a30030b7bda643a23a75d91demturk
12d1342bd29aa7b15080f28cd8ed65d33ce00328rpluemstatic char *rewrite_mapfunc_tolower(request_rec *r, char *key)
a8523e2451f03f4a30030b7bda643a23a75d91demturk{
a8523e2451f03f4a30030b7bda643a23a75d91demturk ap_str_tolower(key);
a8523e2451f03f4a30030b7bda643a23a75d91demturk
a8523e2451f03f4a30030b7bda643a23a75d91demturk return key;
a8523e2451f03f4a30030b7bda643a23a75d91demturk}
a8523e2451f03f4a30030b7bda643a23a75d91demturk
a8523e2451f03f4a30030b7bda643a23a75d91demturkstatic char *rewrite_mapfunc_escape(request_rec *r, char *key)
a8523e2451f03f4a30030b7bda643a23a75d91demturk{
a8523e2451f03f4a30030b7bda643a23a75d91demturk return ap_escape_uri(r->pool, key);
a8523e2451f03f4a30030b7bda643a23a75d91demturk}
a8523e2451f03f4a30030b7bda643a23a75d91demturk
e8f95a682820a599fe41b22977010636be5c2717jimstatic char *rewrite_mapfunc_unescape(request_rec *r, char *key)
67d13599fd4a5f73a2d3fc2b566a9aad60b1c892mturk{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_unescape_url(key);
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin
1cde33c7e2019830f8fb3224e01649305583916etrawick return key;
6bdb2c094666367615890147775bb18761216c8dminfrin}
6bdb2c094666367615890147775bb18761216c8dminfrin
6bdb2c094666367615890147775bb18761216c8dminfrinstatic char *select_random_value_part(request_rec *r, char *value)
6bdb2c094666367615890147775bb18761216c8dminfrin{
0280926d9c3e5deb48961117a60a817d6905dd3dniq char *p = value;
c1c0628ca9788908a5fc7502d04a89c348b75ee6wrowe unsigned n = 1;
9865751743e928ea0a9ad83faa04a738001932deminfrin
c1c0628ca9788908a5fc7502d04a89c348b75ee6wrowe /* count number of distinct values */
d9efe39afed3db4bbdc32e40ddb67075c56e689djim while ((p = ap_strchr(p, '|')) != NULL) {
bda7a7d57377f45932c237d5aba00b189d85c2a9ianh ++n;
bda7a7d57377f45932c237d5aba00b189d85c2a9ianh ++p;
a42b70fa75429d73ef00d6ae212676f8a652f51cpquerna }
bda7a7d57377f45932c237d5aba00b189d85c2a9ianh
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin if (n > 1) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* initialize random generator
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * XXX: Probably this should be wrapped into a thread mutex,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * shouldn't it? Is it worth the effort?
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
11c3b5180e1de6776035320b012a28bb146e7b46chuck if (!rewrite_rand_init_done) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding srand((unsigned)(getpid()));
fd61dbd57eb4ee63c3c647c178979ed817d13be3jim rewrite_rand_init_done = 1;
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe }
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe /* select a random subvalue */
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe n = (int)(((double)(rand() % RAND_MAX) / RAND_MAX) * n + 1);
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe /* extract it from the whole string */
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe while (--n && (value = ap_strchr(value, '|')) != NULL) {
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe ++value;
5a5a6c22260854843c973e2ea9a14bec64362ab5wrowe }
609ecc54ccbd06a9286e1aaf891f80f62450b1aamturk
a865e849a3b00dc8524ecdda09a1699452876219mturk if (value) { /* should not be NULL, but ... */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding p = ap_strchr(value, '|');
fd61dbd57eb4ee63c3c647c178979ed817d13be3jim if (p) {
d993198d8a18c11aa4e80bc647587df10e663f88jim *p = '\0';
fd61dbd57eb4ee63c3c647c178979ed817d13be3jim }
d993198d8a18c11aa4e80bc647587df10e663f88jim }
fd61dbd57eb4ee63c3c647c178979ed817d13be3jim }
d993198d8a18c11aa4e80bc647587df10e663f88jim
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return value;
af952917c05e56874069e1e5f64e6473bb478b68minfrin}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
af952917c05e56874069e1e5f64e6473bb478b68minfrin/* child process code */
af952917c05e56874069e1e5f64e6473bb478b68minfrinstatic void rewrite_child_errfn(apr_pool_t *p, apr_status_t err,
af952917c05e56874069e1e5f64e6473bb478b68minfrin const char *desc)
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin{
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin ap_log_error(APLOG_MARK, APLOG_ERR, err, NULL, "%s", desc);
35c9e4d2c0a6465746a98958ef756114834461e6minfrin}
35c9e4d2c0a6465746a98958ef756114834461e6minfrin
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jimstatic apr_status_t rewritemap_program_child(apr_pool_t *p,
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim const char *progname, char **argv,
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim apr_file_t **fpout,
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim apr_file_t **fpin)
b2b9b7f0644773b50aee41956a841ac884086250niq{
b2b9b7f0644773b50aee41956a841ac884086250niq apr_status_t rc;
c4d7b5c09544149ad4585a13b7e6a4b943d135c8mturk apr_procattr_t *procattr;
e8f95a682820a599fe41b22977010636be5c2717jim apr_proc_t *procnew;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ( APR_SUCCESS == (rc=apr_procattr_create(&procattr, p))
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding && APR_SUCCESS == (rc=apr_procattr_io_set(procattr, APR_FULL_BLOCK,
af952917c05e56874069e1e5f64e6473bb478b68minfrin APR_FULL_BLOCK, APR_NO_PIPE))
af952917c05e56874069e1e5f64e6473bb478b68minfrin && APR_SUCCESS == (rc=apr_procattr_dir_set(procattr,
9b4c60b689b8a3f2d48d19c55d857b276d405f85wrowe ap_make_dirstr_parent(p, argv[0])))
af952917c05e56874069e1e5f64e6473bb478b68minfrin && APR_SUCCESS == (rc=apr_procattr_cmdtype_set(procattr, APR_PROGRAM))
af952917c05e56874069e1e5f64e6473bb478b68minfrin && APR_SUCCESS == (rc=apr_procattr_child_errfn_set(procattr,
af952917c05e56874069e1e5f64e6473bb478b68minfrin rewrite_child_errfn))
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe && APR_SUCCESS == (rc=apr_procattr_error_check_set(procattr, 1))) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe procnew = apr_pcalloc(p, sizeof(*procnew));
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe rc = apr_proc_create(procnew, argv[0], (const char **)argv, NULL,
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe procattr, p);
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe if (rc == APR_SUCCESS) {
609ecc54ccbd06a9286e1aaf891f80f62450b1aamturk apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
a865e849a3b00dc8524ecdda09a1699452876219mturk
af952917c05e56874069e1e5f64e6473bb478b68minfrin if (fpin) {
af952917c05e56874069e1e5f64e6473bb478b68minfrin (*fpin) = procnew->in;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim }
af952917c05e56874069e1e5f64e6473bb478b68minfrin
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq if (fpout) {
af952917c05e56874069e1e5f64e6473bb478b68minfrin (*fpout) = procnew->out;
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq }
af952917c05e56874069e1e5f64e6473bb478b68minfrin }
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq }
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq return (rc);
35c9e4d2c0a6465746a98958ef756114834461e6minfrin}
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq
35630e8756729a29273ef1a5c879b90df3594d66rjungstatic apr_status_t run_rewritemap_programs(server_rec *s, apr_pool_t *p)
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq{
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim rewrite_server_conf *conf;
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq apr_hash_index_t *hi;
00dd9a5a2b0c1f507c332b918ea390f9c1fa991cmturk apr_status_t rc;
82b8e88fd2a266002f6504d8fc4313ec7b5630c0niq int lock_warning_issued = 0;
b2b9b7f0644773b50aee41956a841ac884086250niq
b2b9b7f0644773b50aee41956a841ac884086250niq conf = ap_get_module_config(s->module_config, &rewrite_module);
c4d7b5c09544149ad4585a13b7e6a4b943d135c8mturk
af952917c05e56874069e1e5f64e6473bb478b68minfrin /* If the engine isn't turned on,
af952917c05e56874069e1e5f64e6473bb478b68minfrin * don't even try to do anything.
b2b9b7f0644773b50aee41956a841ac884086250niq */
b2b9b7f0644773b50aee41956a841ac884086250niq if (conf->state == ENGINE_DISABLED) {
b2b9b7f0644773b50aee41956a841ac884086250niq return APR_SUCCESS;
b2b9b7f0644773b50aee41956a841ac884086250niq }
b2b9b7f0644773b50aee41956a841ac884086250niq
b2b9b7f0644773b50aee41956a841ac884086250niq for (hi = apr_hash_first(p, conf->rewritemaps); hi; hi = apr_hash_next(hi)){
b2b9b7f0644773b50aee41956a841ac884086250niq apr_file_t *fpin = NULL;
b2b9b7f0644773b50aee41956a841ac884086250niq apr_file_t *fpout = NULL;
b2b9b7f0644773b50aee41956a841ac884086250niq rewritemap_entry *map;
b2b9b7f0644773b50aee41956a841ac884086250niq void *val;
b2b9b7f0644773b50aee41956a841ac884086250niq
b2b9b7f0644773b50aee41956a841ac884086250niq apr_hash_this(hi, NULL, NULL, &val);
b2b9b7f0644773b50aee41956a841ac884086250niq map = val;
b2b9b7f0644773b50aee41956a841ac884086250niq
b2b9b7f0644773b50aee41956a841ac884086250niq if (map->type != MAPTYPE_PRG) {
b2b9b7f0644773b50aee41956a841ac884086250niq continue;
b2b9b7f0644773b50aee41956a841ac884086250niq }
b2b9b7f0644773b50aee41956a841ac884086250niq if (!(map->argv[0]) || !*(map->argv[0]) || map->fpin || map->fpout) {
af952917c05e56874069e1e5f64e6473bb478b68minfrin continue;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (!lock_warning_issued && (!lockname || !*lockname)) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe "mod_rewrite: Running external rewrite maps "
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe "without defining a RewriteLock is DANGEROUS!");
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe ++lock_warning_issued;
f86b4df17588d404f3da535a8054f43b0642f92aniq }
f86b4df17588d404f3da535a8054f43b0642f92aniq
f86b4df17588d404f3da535a8054f43b0642f92aniq rc = rewritemap_program_child(p, map->argv[0], map->argv,
f86b4df17588d404f3da535a8054f43b0642f92aniq &fpout, &fpin);
f86b4df17588d404f3da535a8054f43b0642f92aniq if (rc != APR_SUCCESS || fpin == NULL || fpout == NULL) {
f86b4df17588d404f3da535a8054f43b0642f92aniq ap_log_error(APLOG_MARK, APLOG_ERR, rc, s,
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf "mod_rewrite: could not start RewriteMap "
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf "program %s", map->checkfile);
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq return rc;
40b22d3b20454959fe51fdc89907908d77701078minfrin }
40b22d3b20454959fe51fdc89907908d77701078minfrin map->fpin = fpin;
93cf7fc650197b941ae31a7c7e51e901b129e954igalic map->fpout = fpout;
f86b4df17588d404f3da535a8054f43b0642f92aniq }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe return APR_SUCCESS;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe}
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe/*
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * +-------------------------------------------------------+
0b4d5285b176f443fd6c0fb07bef76f6b5eb81c7niq * | |
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * | Lookup functions
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * | |
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * +-------------------------------------------------------+
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe */
f86b4df17588d404f3da535a8054f43b0642f92aniq
f86b4df17588d404f3da535a8054f43b0642f92aniqstatic char *lookup_map_txtfile(request_rec *r, const char *file, char *key)
0b4d5285b176f443fd6c0fb07bef76f6b5eb81c7niq{
f86b4df17588d404f3da535a8054f43b0642f92aniq apr_file_t *fp = NULL;
0b4d5285b176f443fd6c0fb07bef76f6b5eb81c7niq char line[REWRITE_MAX_TXT_MAP_LINE + 1]; /* +1 for \0 */
f86b4df17588d404f3da535a8054f43b0642f92aniq char *value, *keylast;
0b4d5285b176f443fd6c0fb07bef76f6b5eb81c7niq
f86b4df17588d404f3da535a8054f43b0642f92aniq if (apr_file_open(&fp, file, APR_READ|APR_BUFFERED, APR_OS_DEFAULT,
f86b4df17588d404f3da535a8054f43b0642f92aniq r->pool) != APR_SUCCESS) {
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq return NULL;
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq }
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf keylast = key + strlen(key);
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf value = NULL;
40b22d3b20454959fe51fdc89907908d77701078minfrin while (apr_file_gets(line, sizeof(line), fp) == APR_SUCCESS) {
40b22d3b20454959fe51fdc89907908d77701078minfrin char *p, *c;
40b22d3b20454959fe51fdc89907908d77701078minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin /* ignore comments and lines starting with whitespaces */
df419be6d7d4b68823efa05722375552af49c2b6minfrin if (*line == '#' || apr_isspace(*line)) {
93cf7fc650197b941ae31a7c7e51e901b129e954igalic continue;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe p = line;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe c = key;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding while (c < keylast && *p == *c && !apr_isspace(*p)) {
9379749d811388a7d0e3410940ddd6743a33d330jim ++p;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ++c;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* key doesn't match - ignore. */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (c != keylast || !apr_isspace(*p)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding continue;
3c59b18ce62f97468aaa5951d4e21a5478ef36ecminfrin }
ef5650b61a8e35f3cc93ec07e73efc17ea329894jorton
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* jump to the value */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding while (*p && apr_isspace(*p)) {
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb ++p;
3c59b18ce62f97468aaa5951d4e21a5478ef36ecminfrin }
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* no value? ignore */
3c59b18ce62f97468aaa5951d4e21a5478ef36ecminfrin if (!*p) {
9379749d811388a7d0e3410940ddd6743a33d330jim continue;
9379749d811388a7d0e3410940ddd6743a33d330jim }
9379749d811388a7d0e3410940ddd6743a33d330jim
9379749d811388a7d0e3410940ddd6743a33d330jim /* extract the value and return. */
3c59b18ce62f97468aaa5951d4e21a5478ef36ecminfrin c = p;
3c59b18ce62f97468aaa5951d4e21a5478ef36ecminfrin while (*p && !apr_isspace(*p)) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard ++p;
3c59b18ce62f97468aaa5951d4e21a5478ef36ecminfrin }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding value = apr_pstrmemdup(r->pool, c, p - c);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding break;
9379749d811388a7d0e3410940ddd6743a33d330jim }
9379749d811388a7d0e3410940ddd6743a33d330jim apr_file_close(fp);
9379749d811388a7d0e3410940ddd6743a33d330jim
9379749d811388a7d0e3410940ddd6743a33d330jim return value;
9379749d811388a7d0e3410940ddd6743a33d330jim}
9379749d811388a7d0e3410940ddd6743a33d330jim
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddardstatic char *lookup_map_dbmfile(request_rec *r, const char *file,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *dbmtype, char *key)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard apr_dbm_t *dbmfp = NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_datum_t dbmkey;
9379749d811388a7d0e3410940ddd6743a33d330jim apr_datum_t dbmval;
ef5650b61a8e35f3cc93ec07e73efc17ea329894jorton char *value;
9379749d811388a7d0e3410940ddd6743a33d330jim
9379749d811388a7d0e3410940ddd6743a33d330jim if (apr_dbm_open_ex(&dbmfp, dbmtype, file, APR_DBM_READONLY, APR_OS_DEFAULT,
9379749d811388a7d0e3410940ddd6743a33d330jim r->pool) != APR_SUCCESS) {
9379749d811388a7d0e3410940ddd6743a33d330jim return NULL;
9379749d811388a7d0e3410940ddd6743a33d330jim }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
65efbf0826de766a90d745cc44427bfa4e2447b6mturk dbmkey.dptr = key;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding dbmkey.dsize = strlen(key);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
24efed0910118b762a4eb84830875d4714b8d315ianh if (apr_dbm_fetch(dbmfp, dbmkey, &dbmval) == APR_SUCCESS && dbmval.dptr) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding value = apr_pstrmemdup(r->pool, dbmval.dptr, dbmval.dsize);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
066877f1a045103acfdd376d48cdd473c33f409bdougm else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding value = NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_dbm_close(dbmfp);
9379749d811388a7d0e3410940ddd6743a33d330jim
9379749d811388a7d0e3410940ddd6743a33d330jim return value;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic char *lookup_map_dbd(request_rec *r, char *key, const char *label)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
9379749d811388a7d0e3410940ddd6743a33d330jim apr_status_t rv;
9379749d811388a7d0e3410940ddd6743a33d330jim apr_dbd_prepared_t *stmt;
9379749d811388a7d0e3410940ddd6743a33d330jim const char *errmsg;
9379749d811388a7d0e3410940ddd6743a33d330jim apr_dbd_results_t *res = NULL;
9379749d811388a7d0e3410940ddd6743a33d330jim apr_dbd_row_t *row = NULL;
9379749d811388a7d0e3410940ddd6743a33d330jim const char *ret = NULL;
9379749d811388a7d0e3410940ddd6743a33d330jim int n = 0;
9379749d811388a7d0e3410940ddd6743a33d330jim ap_dbd_t *db = dbd_acquire(r);
9379749d811388a7d0e3410940ddd6743a33d330jim
9379749d811388a7d0e3410940ddd6743a33d330jim 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);
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim if (rv != 0) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding errmsg = apr_dbd_error(db->driver, db->handle, rv);
df419be6d7d4b68823efa05722375552af49c2b6minfrin ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "rewritemap: error %s querying for %s", errmsg, key);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding while (rv = apr_dbd_get_row(db->driver, r->pool, res, &row, -1), rv == 0) {
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe ++n;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe if (ret == NULL) {
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe ret = apr_dbd_get_entry(db->driver, row, 0);
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe }
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe else {
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe /* randomise crudely amongst multiple results */
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe if ((double)rand() < (double)RAND_MAX/(double)n) {
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim ret = apr_dbd_get_entry(db->driver, row, 0);
28fe44817329b1183f64e878c258962f90423a8dniq }
b588214d6e6fe09abe709e83e894921fbc7e25c8covener }
b588214d6e6fe09abe709e83e894921fbc7e25c8covener }
b588214d6e6fe09abe709e83e894921fbc7e25c8covener if (rv != -1) {
14c8c18e6caab1bdeb0f26b2b031e000fef58ef9jim errmsg = apr_dbd_error(db->driver, db->handle, rv);
b588214d6e6fe09abe709e83e894921fbc7e25c8covener ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
b588214d6e6fe09abe709e83e894921fbc7e25c8covener "rewritemap: error %s looking up %s", errmsg, key);
e8f95a682820a599fe41b22977010636be5c2717jim }
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe switch (n) {
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe case 0:
dcda744296f197717c5105fd197e94ceba7880d7jim return NULL;
dcda744296f197717c5105fd197e94ceba7880d7jim case 1:
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim return apr_pstrdup(r->pool, ret);
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim default:
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim /* what's a fair rewritelog level for this? */
dcda744296f197717c5105fd197e94ceba7880d7jim rewritelog((r, 3, NULL, "Multiple values found for %s", key));
dcda744296f197717c5105fd197e94ceba7880d7jim return apr_pstrdup(r->pool, ret);
dcda744296f197717c5105fd197e94ceba7880d7jim }
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe}
dcda744296f197717c5105fd197e94ceba7880d7jim
28fe44817329b1183f64e878c258962f90423a8dniqstatic char *lookup_map_program(request_rec *r, apr_file_t *fpin,
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe apr_file_t *fpout, char *key)
28fe44817329b1183f64e878c258962f90423a8dniq{
28fe44817329b1183f64e878c258962f90423a8dniq char *buf;
28fe44817329b1183f64e878c258962f90423a8dniq char c;
28fe44817329b1183f64e878c258962f90423a8dniq apr_size_t i, nbytes, combined_len = 0;
997023faa943892aae20d092044aa983c2936982niq apr_status_t rv;
997023faa943892aae20d092044aa983c2936982niq const char *eol = APR_EOL_STR;
997023faa943892aae20d092044aa983c2936982niq apr_size_t eolc = 0;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe int found_nl = 0;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe result_list *buflist = NULL, *curbuf = NULL;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem#ifndef NO_WRITEV
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem struct iovec iova[2];
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim apr_size_t niov;
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem#endif
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem /* when `RewriteEngine off' was used in the per-server
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim * context then the rewritemap-programs were not spawned.
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem * In this case using such a map (usually in per-dir context)
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem * is useless because it is not available.
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem *
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem * newlines in the key leave bytes in the pipe and cause
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim * bad things to happen (next map lookup will use the chars
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem * after the \n instead of the new key etc etc - in other words,
c7eeb0a294d58c75aee6ed86f73c6e1e8cf600a3rpluem * the Rewritemap falls out of sync with the requests).
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe */
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe if (fpin == NULL || fpout == NULL || ap_strchr(key, '\n')) {
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe return NULL;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe }
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe /* take the lock */
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe if (rewrite_mapr_lock_acquire) {
df419be6d7d4b68823efa05722375552af49c2b6minfrin rv = apr_global_mutex_lock(rewrite_mapr_lock_acquire);
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim if (rv != APR_SUCCESS) {
df419be6d7d4b68823efa05722375552af49c2b6minfrin ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
df419be6d7d4b68823efa05722375552af49c2b6minfrin "apr_global_mutex_lock(rewrite_mapr_lock_acquire) "
df419be6d7d4b68823efa05722375552af49c2b6minfrin "failed");
df419be6d7d4b68823efa05722375552af49c2b6minfrin return NULL; /* Maybe this should be fatal? */
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin }
df419be6d7d4b68823efa05722375552af49c2b6minfrin
df419be6d7d4b68823efa05722375552af49c2b6minfrin /* write out the request key */
df419be6d7d4b68823efa05722375552af49c2b6minfrin#ifdef NO_WRITEV
df419be6d7d4b68823efa05722375552af49c2b6minfrin nbytes = strlen(key);
df419be6d7d4b68823efa05722375552af49c2b6minfrin apr_file_write(fpin, key, &nbytes);
df419be6d7d4b68823efa05722375552af49c2b6minfrin nbytes = 1;
df419be6d7d4b68823efa05722375552af49c2b6minfrin apr_file_write(fpin, "\n", &nbytes);
df419be6d7d4b68823efa05722375552af49c2b6minfrin#else
df419be6d7d4b68823efa05722375552af49c2b6minfrin iova[0].iov_base = key;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe iova[0].iov_len = strlen(key);
75b0a6a06ca1f4de80e3dd2a09c9f0c7d0a56089wrowe iova[1].iov_base = "\n";
75b0a6a06ca1f4de80e3dd2a09c9f0c7d0a56089wrowe iova[1].iov_len = 1;
28fe44817329b1183f64e878c258962f90423a8dniq
dcda744296f197717c5105fd197e94ceba7880d7jim niov = 2;
dcda744296f197717c5105fd197e94ceba7880d7jim apr_file_writev(fpin, iova, niov, &nbytes);
dcda744296f197717c5105fd197e94ceba7880d7jim#endif
dcda744296f197717c5105fd197e94ceba7880d7jim
dcda744296f197717c5105fd197e94ceba7880d7jim buf = apr_palloc(r->pool, REWRITE_PRG_MAP_BUF + 1);
dcda744296f197717c5105fd197e94ceba7880d7jim
dcda744296f197717c5105fd197e94ceba7880d7jim /* read in the response value */
dcda744296f197717c5105fd197e94ceba7880d7jim nbytes = 1;
dcda744296f197717c5105fd197e94ceba7880d7jim apr_file_read(fpout, &c, &nbytes);
efddae96ddb58b8604704137a9221d7dc61868b0mturk do {
efddae96ddb58b8604704137a9221d7dc61868b0mturk i = 0;
e8f95a682820a599fe41b22977010636be5c2717jim while (nbytes == 1 && (i < REWRITE_PRG_MAP_BUF)) {
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe if (c == eol[eolc]) {
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe if (!eol[++eolc]) {
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq /* remove eol from the buffer */
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim --eolc;
5a5a6c22260854843c973e2ea9a14bec64362ab5wrowe if (i < eolc) {
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe curbuf->len -= eolc-i;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim i = 0;
4415d997ac73262e513c0a571bd5be4f609040bawrowe }
de274dca1be855ebb66bb7857951aae26fcb54c7wrowe else {
e8f95a682820a599fe41b22977010636be5c2717jim i -= eolc;
4415d997ac73262e513c0a571bd5be4f609040bawrowe }
1febae173a82bc2a71c3c0ba4105cf674000791bjim ++found_nl;
eee895b02dd7867622afd0a8a94f2efc7de9c618wrowe break;
4415d997ac73262e513c0a571bd5be4f609040bawrowe }
de274dca1be855ebb66bb7857951aae26fcb54c7wrowe }
4415d997ac73262e513c0a571bd5be4f609040bawrowe
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe /* only partial (invalid) eol sequence -> reset the counter */
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe else if (eolc) {
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim eolc = 0;
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung }
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim /* catch binary mode, e.g. on Win32 */
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe else if (c == '\n') {
de274dca1be855ebb66bb7857951aae26fcb54c7wrowe ++found_nl;
0c4b0ffd3db7ae8e34662826098b5e46dadc1e88jim break;
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung }
7ba381d8371d632d25ba1256a9047fe601cb984djfclere
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung buf[i++] = c;
acfed915e00d4d0ca436b388b93610ceccd58a64minfrin apr_file_read(fpout, &c, &nbytes);
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung }
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe /* well, if there wasn't a newline yet, we need to read further */
1dac466bcc84f8ebf410016dcf2a4cd4312e8611wrowe if (buflist || (nbytes == 1 && !found_nl)) {
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe if (!buflist) {
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung curbuf = buflist = apr_palloc(r->pool, sizeof(*buflist));
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung }
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung else if (i) {
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim curbuf->next = apr_palloc(r->pool, sizeof(*buflist));
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung curbuf = curbuf->next;
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung }
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung curbuf->next = NULL;
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung if (i) {
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe curbuf->string = buf;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe curbuf->len = i;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe combined_len += i;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding buf = apr_palloc(r->pool, REWRITE_PRG_MAP_BUF);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim if (nbytes == 1 && !found_nl) {
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim i = 0;
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim continue;
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim }
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim }
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim break;
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim } while (1);
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim /* concat the stuff */
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim if (buflist) {
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim char *p;
997023faa943892aae20d092044aa983c2936982niq
997023faa943892aae20d092044aa983c2936982niq p = buf = apr_palloc(r->pool, combined_len + 1); /* \0 */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding while (buflist) {
f86b4df17588d404f3da535a8054f43b0642f92aniq if (buflist->len) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding memcpy(p, buflist->string, buflist->len);
997023faa943892aae20d092044aa983c2936982niq p += buflist->len;
997023faa943892aae20d092044aa983c2936982niq }
997023faa943892aae20d092044aa983c2936982niq buflist = buflist->next;
b588214d6e6fe09abe709e83e894921fbc7e25c8covener }
b588214d6e6fe09abe709e83e894921fbc7e25c8covener *p = '\0';
b588214d6e6fe09abe709e83e894921fbc7e25c8covener i = combined_len;
14c8c18e6caab1bdeb0f26b2b031e000fef58ef9jim }
b588214d6e6fe09abe709e83e894921fbc7e25c8covener else {
b588214d6e6fe09abe709e83e894921fbc7e25c8covener buf[i] = '\0';
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
997023faa943892aae20d092044aa983c2936982niq
997023faa943892aae20d092044aa983c2936982niq /* give the lock back */
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if (rewrite_mapr_lock_acquire) {
997023faa943892aae20d092044aa983c2936982niq rv = apr_global_mutex_unlock(rewrite_mapr_lock_acquire);
ea64665b1de60d55641104e018f696c4a310d2f1jim if (rv != APR_SUCCESS) {
ea64665b1de60d55641104e018f696c4a310d2f1jim ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
ea64665b1de60d55641104e018f696c4a310d2f1jim "apr_global_mutex_unlock(rewrite_mapr_lock_acquire) "
997023faa943892aae20d092044aa983c2936982niq "failed");
997023faa943892aae20d092044aa983c2936982niq return NULL; /* Maybe this should be fatal? */
997023faa943892aae20d092044aa983c2936982niq }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
997023faa943892aae20d092044aa983c2936982niq
ea64665b1de60d55641104e018f696c4a310d2f1jim /* catch the "failed" case */
ea64665b1de60d55641104e018f696c4a310d2f1jim if (i == 4 && !strcasecmp(buf, "NULL")) {
997023faa943892aae20d092044aa983c2936982niq return NULL;
529005244758297d4415aa912c67a67f805349bcianh }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
997023faa943892aae20d092044aa983c2936982niq return buf;
997023faa943892aae20d092044aa983c2936982niq}
997023faa943892aae20d092044aa983c2936982niq
997023faa943892aae20d092044aa983c2936982niq/*
997023faa943892aae20d092044aa983c2936982niq * generic map lookup
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic char *lookup_map(request_rec *r, char *name, char *key)
997023faa943892aae20d092044aa983c2936982niq{
997023faa943892aae20d092044aa983c2936982niq rewrite_server_conf *conf;
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq rewritemap_entry *s;
f86b4df17588d404f3da535a8054f43b0642f92aniq char *value;
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq apr_finfo_t st;
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq apr_status_t rv;
a812b025d139f465a31c76fc02ed162ed5271b03nd
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq /* get map configuration */
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq conf = ap_get_module_config(r->server->module_config, &rewrite_module);
997023faa943892aae20d092044aa983c2936982niq s = apr_hash_get(conf->rewritemaps, name, APR_HASH_KEY_STRING);
a812b025d139f465a31c76fc02ed162ed5271b03nd
a812b025d139f465a31c76fc02ed162ed5271b03nd /* map doesn't exist */
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq if (!s) {
997023faa943892aae20d092044aa983c2936982niq return NULL;
997023faa943892aae20d092044aa983c2936982niq }
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq
f86b4df17588d404f3da535a8054f43b0642f92aniq switch (s->type) {
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq /*
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq * Text file map (perhaps random)
a812b025d139f465a31c76fc02ed162ed5271b03nd */
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq case MAPTYPE_RND:
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq case MAPTYPE_TXT:
997023faa943892aae20d092044aa983c2936982niq rv = apr_stat(&st, s->checkfile, APR_FINFO_MIN, r->pool);
a812b025d139f465a31c76fc02ed162ed5271b03nd if (rv != APR_SUCCESS) {
33cb45dc8c5106018b7c2f6ae42478b109423e0eniq ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "mod_rewrite: can't access text RewriteMap file %s",
11c3b5180e1de6776035320b012a28bb146e7b46chuck s->checkfile);
11c3b5180e1de6776035320b012a28bb146e7b46chuck rewritelog((r, 1, NULL,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "can't open RewriteMap file, see error log"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding value = get_cache_value(s->cachename, st.mtime, key, r->pool);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!value) {
a6314dfa8dd8a0d69db16288581e4950a2dd3955minfrin rewritelog((r, 6, NULL,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "cache lookup FAILED, forcing new map lookup"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding value = lookup_map_txtfile(r, s->datafile, key);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!value) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 5, NULL, "map lookup FAILED: map=%s[txt] key=%s",
edc346c3223efd41e6a2057c37cea69744b73dccwrowe name, key));
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard set_cache_value(s->cachename, st.mtime, key, "");
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 5, NULL,"map lookup OK: map=%s[txt] key=%s -> val=%s",
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard name, key, value));
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard set_cache_value(s->cachename, st.mtime, key, value);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard else {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard rewritelog((r,5,NULL,"cache lookup OK: map=%s[txt] key=%s -> val=%s",
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard name, key, value));
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
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));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return *value ? value : NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * DBM file map
11c3b5180e1de6776035320b012a28bb146e7b46chuck */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding case MAPTYPE_DBM:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rv = apr_stat(&st, s->checkfile, 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 file %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding s->checkfile);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else if(s->checkfile2 != NULL) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_finfo_t st2;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rv = apr_stat(&st2, s->checkfile2, APR_FINFO_MIN, r->pool);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if (rv != APR_SUCCESS) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "mod_rewrite: can't access DBM RewriteMap "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "file %s", s->checkfile2);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard else if(st2.mtime > st.mtime) {
11c3b5180e1de6776035320b012a28bb146e7b46chuck st.mtime = st2.mtime;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if(rv != APR_SUCCESS) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 1, NULL,
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk "can't open DBM RewriteMap file, see error log"));
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk return NULL;
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk }
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding value = get_cache_value(s->cachename, st.mtime, key, r->pool);
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (!value) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk rewritelog((r, 6, NULL,
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk "cache lookup FAILED, forcing new map lookup"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk value = lookup_map_dbmfile(r, s->datafile, s->dbmtype, key);
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk if (!value) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 5, NULL, "map lookup FAILED: map=%s[dbm] key=%s",
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard name, key));
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard set_cache_value(s->cachename, st.mtime, key, "");
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
1cde33c7e2019830f8fb3224e01649305583916etrawick
407cde44becba3694e7c3d81ac99b5d86f4b03a9rbb rewritelog((r, 5, NULL, "map lookup OK: map=%s[dbm] key=%s -> "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "val=%s", name, key, value));
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard set_cache_value(s->cachename, st.mtime, key, value);
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return value;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 5, NULL, "cache lookup OK: map=%s[dbm] key=%s -> val=%s",
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard name, key, value));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return *value ? value : NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * SQL map without cache
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
11c3b5180e1de6776035320b012a28bb146e7b46chuck case MAPTYPE_DBD:
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",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding name, key));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return NULL;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 5, NULL, "SQL map lookup OK: map %s key=%s, val=%s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding name, key, value));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return value;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
11c3b5180e1de6776035320b012a28bb146e7b46chuck /*
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) {
af952917c05e56874069e1e5f64e6473bb478b68minfrin rewritelog((r, 6, NULL,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "cache lookup FAILED, forcing new map lookup"));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
609ecc54ccbd06a9286e1aaf891f80f62450b1aamturk value = lookup_map_dbd(r, key, s->dbdq);
ff1234e45aca1b8171d711ecb87f58b9d9100a99ianh if (!value) {
40b22d3b20454959fe51fdc89907908d77701078minfrin rewritelog((r, 5, NULL, "SQL map lookup FAILED: map %s key=%s",
ff1234e45aca1b8171d711ecb87f58b9d9100a99ianh name, key));
40b22d3b20454959fe51fdc89907908d77701078minfrin set_cache_value(s->cachename, 0, key, "");
ff1234e45aca1b8171d711ecb87f58b9d9100a99ianh return NULL;
40b22d3b20454959fe51fdc89907908d77701078minfrin }
40b22d3b20454959fe51fdc89907908d77701078minfrin
ff1234e45aca1b8171d711ecb87f58b9d9100a99ianh rewritelog((r, 5, NULL, "SQL map lookup OK: map %s key=%s, val=%s",
ff1234e45aca1b8171d711ecb87f58b9d9100a99ianh name, key, value));
93cf7fc650197b941ae31a7c7e51e901b129e954igalic
93cf7fc650197b941ae31a7c7e51e901b129e954igalic set_cache_value(s->cachename, 0, key, value);
93cf7fc650197b941ae31a7c7e51e901b129e954igalic return value;
93cf7fc650197b941ae31a7c7e51e901b129e954igalic }
93cf7fc650197b941ae31a7c7e51e901b129e954igalic
93cf7fc650197b941ae31a7c7e51e901b129e954igalic rewritelog((r, 5, NULL, "cache lookup OK: map=%s[SQL] key=%s, val=%s",
93cf7fc650197b941ae31a7c7e51e901b129e954igalic name, key, value));
fd3fa792f04fc9c4e8f5f83dceb0fc34e71f8570ianh return *value ? value : NULL;
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf
fd3fa792f04fc9c4e8f5f83dceb0fc34e71f8570ianh /*
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf * Program file map
fd3fa792f04fc9c4e8f5f83dceb0fc34e71f8570ianh */
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf case MAPTYPE_PRG:
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf value = lookup_map_program(r, s->fpin, s->fpout, key);
fd3fa792f04fc9c4e8f5f83dceb0fc34e71f8570ianh if (!value) {
fd3fa792f04fc9c4e8f5f83dceb0fc34e71f8570ianh rewritelog((r, 5,NULL,"map lookup FAILED: map=%s key=%s", name,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding key));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return NULL;
11c3b5180e1de6776035320b012a28bb146e7b46chuck }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 5, NULL, "map lookup OK: map=%s key=%s -> val=%s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding name, key, value));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return value;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard /*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Internal Map
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding case MAPTYPE_INT:
af952917c05e56874069e1e5f64e6473bb478b68minfrin value = s->func(r, key);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!value) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding rewritelog((r, 5,NULL,"map lookup FAILED: map=%s key=%s", name,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding key));
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin return NULL;
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin }
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin rewritelog((r, 5, NULL, "map lookup OK: map=%s key=%s -> val=%s",
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin name, key, value));
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin return value;
5eb56df4054a0bca4d740eedd7ef277355a2c0adjim }
5eb56df4054a0bca4d740eedd7ef277355a2c0adjim
5eb56df4054a0bca4d740eedd7ef277355a2c0adjim return NULL;
5eb56df4054a0bca4d740eedd7ef277355a2c0adjim}
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin/*
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin * lookup a HTTP header and set VARY note
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin */
35c9e4d2c0a6465746a98958ef756114834461e6minfrinstatic const char *lookup_header(const char *name, rewrite_ctx *ctx)
35c9e4d2c0a6465746a98958ef756114834461e6minfrin{
35c9e4d2c0a6465746a98958ef756114834461e6minfrin const char *val = apr_table_get(ctx->r->headers_in, name);
35c9e4d2c0a6465746a98958ef756114834461e6minfrin
35c9e4d2c0a6465746a98958ef756114834461e6minfrin if (val) {
35c9e4d2c0a6465746a98958ef756114834461e6minfrin ctx->vary_this = ctx->vary_this
35c9e4d2c0a6465746a98958ef756114834461e6minfrin ? apr_pstrcat(ctx->r->pool, ctx->vary_this, ", ",
35c9e4d2c0a6465746a98958ef756114834461e6minfrin name, NULL)
35c9e4d2c0a6465746a98958ef756114834461e6minfrin : apr_pstrdup(ctx->r->pool, name);
35c9e4d2c0a6465746a98958ef756114834461e6minfrin }
35c9e4d2c0a6465746a98958ef756114834461e6minfrin
4224d5789080ea5586d49420da1e1996f5653bb5ianh return val;
4224d5789080ea5586d49420da1e1996f5653bb5ianh}
4224d5789080ea5586d49420da1e1996f5653bb5ianh
4224d5789080ea5586d49420da1e1996f5653bb5ianh/*
4224d5789080ea5586d49420da1e1996f5653bb5ianh * lookahead helper function
4224d5789080ea5586d49420da1e1996f5653bb5ianh * Determine the correct URI path in perdir context
4224d5789080ea5586d49420da1e1996f5653bb5ianh */
35630e8756729a29273ef1a5c879b90df3594d66rjungstatic APR_INLINE const char *la_u(rewrite_ctx *ctx)
4224d5789080ea5586d49420da1e1996f5653bb5ianh{
4224d5789080ea5586d49420da1e1996f5653bb5ianh rewrite_perdir_conf *conf;
4224d5789080ea5586d49420da1e1996f5653bb5ianh
35630e8756729a29273ef1a5c879b90df3594d66rjung if (*ctx->uri == '/') {
35630e8756729a29273ef1a5c879b90df3594d66rjung return ctx->uri;
4224d5789080ea5586d49420da1e1996f5653bb5ianh }
e8f95a682820a599fe41b22977010636be5c2717jim
4224d5789080ea5586d49420da1e1996f5653bb5ianh conf = ap_get_module_config(ctx->r->per_dir_config, &rewrite_module);
35c9e4d2c0a6465746a98958ef756114834461e6minfrin
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return apr_pstrcat(ctx->r->pool, conf->baseurl
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb ? conf->baseurl : conf->directory,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ctx->uri, NULL);
11c3b5180e1de6776035320b012a28bb146e7b46chuck}
11c3b5180e1de6776035320b012a28bb146e7b46chuck
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * generic variable lookup
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic char *lookup_variable(char *var, rewrite_ctx *ctx)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *result;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding request_rec *r = ctx->r;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_size_t varlen = strlen(var);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* fast exit */
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard if (varlen < 4) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard return apr_pstrdup(r->pool, "");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
af952917c05e56874069e1e5f64e6473bb478b68minfrin result = NULL;
e8f95a682820a599fe41b22977010636be5c2717jim
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* fast tests for variable length variables (sic) first */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (var[3] == ':') {
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim if (var[4] && !strncasecmp(var, "ENV", 3)) {
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim var += 4;
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim result = apr_table_get(r->notes, var);
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim if (!result) {
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim result = apr_table_get(r->subprocess_env, var);
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim }
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim if (!result) {
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim result = getenv(var);
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim }
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim }
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim else if (var[4] && !strncasecmp(var, "SSL", 3) && rewrite_ssl_lookup) {
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim result = rewrite_ssl_lookup(r->pool, r->server, r->connection, r,
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim var + 4);
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim }
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim }
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim else if (var[4] == ':') {
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim if (var[5]) {
e8f95a682820a599fe41b22977010636be5c2717jim request_rec *rr;
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim const char *path;
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (!strncasecmp(var, "HTTP", 4)) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe result = lookup_header(var+5, ctx);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe else if (!strncasecmp(var, "LA-U", 4)) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (ctx->uri && subreq_ok(r)) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe path = ctx->perdir ? la_u(ctx) : ctx->uri;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe rr = ap_sub_req_lookup_uri(path, r, NULL);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe ctx->r = rr;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe result = apr_pstrdup(r->pool, lookup_variable(var+5, ctx));
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe ctx->r = r;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe ap_destroy_sub_req(rr);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe rewritelog((r, 5, ctx->perdir, "lookahead: path=%s var=%s "
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe "-> val=%s", path, var+5, result));
6c05afd314b4ddd545d63b4ff5de822cc30eec79trawick
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe return (char *)result;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
e8f95a682820a599fe41b22977010636be5c2717jim else if (!strncasecmp(var, "LA-F", 4)) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (ctx->uri && subreq_ok(r)) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe path = ctx->uri;
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe if (ctx->perdir && *path == '/') {
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe /* sigh, the user wants a file based subrequest, but
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe * we can't do one, since we don't know what the file
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe * path is! In this case behave like LA-U.
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe */
5a5a6c22260854843c973e2ea9a14bec64362ab5wrowe rr = ap_sub_req_lookup_uri(path, r, NULL);
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe }
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe else {
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe if (ctx->perdir) {
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe rewrite_perdir_conf *conf;
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe conf = ap_get_module_config(r->per_dir_config,
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe &rewrite_module);
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe path = apr_pstrcat(r->pool, conf->directory, path,
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim NULL);
e8f95a682820a599fe41b22977010636be5c2717jim }
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe rr = ap_sub_req_lookup_file(path, r, NULL);
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere }
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere ctx->r = rr;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe result = apr_pstrdup(r->pool, lookup_variable(var+5, ctx));
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere ctx->r = r;
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere ap_destroy_sub_req(rr);
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere rewritelog((r, 5, ctx->perdir, "lookahead: path=%s var=%s "
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere "-> val=%s", path, var+5, result));
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere return (char *)result;
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere }
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe }
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe }
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe }
433dc2d5dae74ed067db6175010ff973d02511e9jerenkrantz
433dc2d5dae74ed067db6175010ff973d02511e9jerenkrantz /* well, do it the hard way */
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere else {
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere char *p;
a2d1780b346e147ca4d5c1cdeb0fd8a57fd93899jfclere apr_time_exp_t tm;
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe /* can't do this above, because of the getenv call */
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe for (p = var; *p; ++p) {
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe *p = apr_toupper(*p);
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe }
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe switch (varlen) {
e8f95a682820a599fe41b22977010636be5c2717jim case 4:
65efbf0826de766a90d745cc44427bfa4e2447b6mturk 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",
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim tm.tm_hour, tm.tm_min, tm.tm_sec);
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim rewritelog((r, 1, ctx->perdir, "RESULT='%s'", result));
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim return (char *)result;
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim }
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim break;
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe case 5:
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim if (!strcmp(var, "HTTPS")) {
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe int flag = rewrite_is_https && rewrite_is_https(r->connection);
0c4b0ffd3db7ae8e34662826098b5e46dadc1e88jim return apr_pstrdup(r->pool, flag ? "on" : "off");
0c4b0ffd3db7ae8e34662826098b5e46dadc1e88jim }
0c4b0ffd3db7ae8e34662826098b5e46dadc1e88jim break;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim
e8f95a682820a599fe41b22977010636be5c2717jim case 8:
0c4b0ffd3db7ae8e34662826098b5e46dadc1e88jim switch (var[6]) {
0c4b0ffd3db7ae8e34662826098b5e46dadc1e88jim case 'A':
0c4b0ffd3db7ae8e34662826098b5e46dadc1e88jim if (!strcmp(var, "TIME_DAY")) {
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung apr_time_exp_lt(&tm, apr_time_now());
7ba381d8371d632d25ba1256a9047fe601cb984djfclere return apr_psprintf(r->pool, "%02d", tm.tm_mday);
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung }
acfed915e00d4d0ca436b388b93610ceccd58a64minfrin break;
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim case 'E':
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe if (!strcmp(var, "TIME_SEC")) {
e8f95a682820a599fe41b22977010636be5c2717jim apr_time_exp_lt(&tm, apr_time_now());
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe return apr_psprintf(r->pool, "%02d", tm.tm_sec);
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe }
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe break;
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung case 'I':
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung if (!strcmp(var, "TIME_MIN")) {
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim apr_time_exp_lt(&tm, apr_time_now());
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung return apr_psprintf(r->pool, "%02d", tm.tm_min);
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim }
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung break;
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung case 'O':
06cdc8d205f0982074ab9b032d0b6d74c58f54carjung if (!strcmp(var, "TIME_MON")) {
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe apr_time_exp_lt(&tm, apr_time_now());
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim return apr_psprintf(r->pool, "%02d", tm.tm_mon+1);
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe }
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe break;
d52b01101efdd3a37493d1090f20eb23c4dd1521wrowe }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 9:
65efbf0826de766a90d745cc44427bfa4e2447b6mturk switch (var[7]) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 'A':
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (var[8] == 'Y' && !strcmp(var, "TIME_WDAY")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk apr_time_exp_lt(&tm, apr_time_now());
65efbf0826de766a90d745cc44427bfa4e2447b6mturk return apr_psprintf(r->pool, "%d", tm.tm_wday);
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk else if (!strcmp(var, "TIME_YEAR")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk apr_time_exp_lt(&tm, apr_time_now());
fef95ce9cdb638443693c21f181dd2494b467469mturk return apr_psprintf(r->pool, "%04d", tm.tm_year+1900);
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 'E':
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (!strcmp(var, "IS_SUBREQ")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk result = (r->main ? "true" : "false");
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
9738b63e3d24b2856b1b6a12fcddcbf325f26d4bnd case 'F':
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (!strcmp(var, "PATH_INFO")) {
fef95ce9cdb638443693c21f181dd2494b467469mturk result = r->path_info;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 'P':
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (!strcmp(var, "AUTH_TYPE")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk result = r->ap_auth_type;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
e8f95a682820a599fe41b22977010636be5c2717jim break;
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 'S':
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (!strcmp(var, "HTTP_HOST")) {
fef95ce9cdb638443693c21f181dd2494b467469mturk result = lookup_header("Host", ctx);
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim }
fef95ce9cdb638443693c21f181dd2494b467469mturk break;
fef95ce9cdb638443693c21f181dd2494b467469mturk
fef95ce9cdb638443693c21f181dd2494b467469mturk case 'U':
fef95ce9cdb638443693c21f181dd2494b467469mturk if (!strcmp(var, "TIME_HOUR")) {
fef95ce9cdb638443693c21f181dd2494b467469mturk apr_time_exp_lt(&tm, apr_time_now());
fef95ce9cdb638443693c21f181dd2494b467469mturk return apr_psprintf(r->pool, "%02d", tm.tm_hour);
fef95ce9cdb638443693c21f181dd2494b467469mturk }
e8f95a682820a599fe41b22977010636be5c2717jim break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk break;
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 11:
fef95ce9cdb638443693c21f181dd2494b467469mturk switch (var[8]) {
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim case 'A':
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim if (!strcmp(var, "SERVER_NAME")) {
fef95ce9cdb638443693c21f181dd2494b467469mturk result = ap_get_server_name(r);
fef95ce9cdb638443693c21f181dd2494b467469mturk }
fef95ce9cdb638443693c21f181dd2494b467469mturk break;
fef95ce9cdb638443693c21f181dd2494b467469mturk
fef95ce9cdb638443693c21f181dd2494b467469mturk case 'D':
fef95ce9cdb638443693c21f181dd2494b467469mturk if (*var == 'R' && !strcmp(var, "REMOTE_ADDR")) {
fef95ce9cdb638443693c21f181dd2494b467469mturk result = r->connection->remote_ip;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk else if (!strcmp(var, "SERVER_ADDR")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk result = r->connection->local_ip;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 'E':
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (*var == 'H' && !strcmp(var, "HTTP_ACCEPT")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk result = lookup_header("Accept", ctx);
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk else if (!strcmp(var, "THE_REQUEST")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk result = r->the_request;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
1febae173a82bc2a71c3c0ba4105cf674000791bjim case 'I':
65efbf0826de766a90d745cc44427bfa4e2447b6mturk if (!strcmp(var, "API_VERSION")) {
65efbf0826de766a90d745cc44427bfa4e2447b6mturk return apr_psprintf(r->pool, "%d:%d",
c332befc1519a1016d8de07608f0b859e6fab580jim MODULE_MAGIC_NUMBER_MAJOR,
65efbf0826de766a90d745cc44427bfa4e2447b6mturk MODULE_MAGIC_NUMBER_MINOR);
65efbf0826de766a90d745cc44427bfa4e2447b6mturk }
65efbf0826de766a90d745cc44427bfa4e2447b6mturk break;
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
65efbf0826de766a90d745cc44427bfa4e2447b6mturk case 'K':
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (!strcmp(var, "HTTP_COOKIE")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = lookup_header("Cookie", ctx);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
e8f95a682820a599fe41b22977010636be5c2717jim case 'O':
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (*var == 'S' && !strcmp(var, "SERVER_PORT")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe return apr_psprintf(r->pool, "%u", ap_get_server_port(r));
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe else if (var[7] == 'H' && !strcmp(var, "REMOTE_HOST")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = ap_get_remote_host(r->connection,r->per_dir_config,
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe REMOTE_NAME, NULL);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe else if (!strcmp(var, "REMOTE_PORT")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe return apr_itoa(r->pool, r->connection->remote_addr->port);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
ef5650b61a8e35f3cc93ec07e73efc17ea329894jorton
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 'S':
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk if (*var == 'R' && !strcmp(var, "REMOTE_USER")) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk result = r->user;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe else if (!strcmp(var, "SCRIPT_USER")) {
bdf8801c51d958b1d3ff40f60ab16ccfd999b0fawrowe result = "<unknown>";
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk if (r->finfo.valid & APR_FINFO_USER) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk apr_uid_name_get((char **)&result, r->finfo.user,
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk r->pool);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 'U':
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (!strcmp(var, "REQUEST_URI")) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard result = r->uri;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
35630e8756729a29273ef1a5c879b90df3594d66rjung }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 12:
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe switch (var[3]) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 'I':
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (!strcmp(var, "SCRIPT_GROUP")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = "<unknown>";
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (r->finfo.valid & APR_FINFO_GROUP) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe apr_gid_name_get((char **)&result, r->finfo.group,
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe r->pool);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
52489511342e4ff3fe399e57f29d38e5c4227bc8trawick }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
e8f95a682820a599fe41b22977010636be5c2717jim case 'O':
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (!strcmp(var, "REMOTE_IDENT")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = ap_get_remote_logname(r);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
ef5650b61a8e35f3cc93ec07e73efc17ea329894jorton
e6c244ee56578707b20a86e0e938498299a93b6cnd case 'P':
e6c244ee56578707b20a86e0e938498299a93b6cnd if (!strcmp(var, "HTTP_REFERER")) {
e6c244ee56578707b20a86e0e938498299a93b6cnd result = lookup_header("Referer", ctx);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 'R':
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (!strcmp(var, "QUERY_STRING")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = r->args;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
ef5650b61a8e35f3cc93ec07e73efc17ea329894jorton break;
e6c244ee56578707b20a86e0e938498299a93b6cnd
e6c244ee56578707b20a86e0e938498299a93b6cnd case 'V':
e6c244ee56578707b20a86e0e938498299a93b6cnd if (!strcmp(var, "SERVER_ADMIN")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = r->server->server_admin;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe case 13:
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (!strcmp(var, "DOCUMENT_ROOT")) {
e6366481b8fe06a24337f0b30b7da66cf64d6062stoddard result = ap_document_root(r);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe break;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
9a806b671337b22acf6418e60a83f6bbeabdf771wrowe case 14:
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (*var == 'H' && !strcmp(var, "HTTP_FORWARDED")) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe result = lookup_header("Forwarded", ctx);
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe else if (!strcmp(var, "REQUEST_METHOD")) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk result = r->method;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk break;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk case 15:
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk switch (var[7]) {
7033ee56ea894e9b3fdf573ab9960149a4e88a11jorton case 'E':
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk if (!strcmp(var, "HTTP_USER_AGENT")) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk result = lookup_header("User-Agent", ctx);
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim break;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk case 'F':
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim if (!strcmp(var, "SCRIPT_FILENAME")) {
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim result = r->filename; /* same as request_filename (16) */
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk break;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk case 'P':
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk if (!strcmp(var, "SERVER_PROTOCOL")) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk result = r->protocol;
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk break;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim case 'S':
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim if (!strcmp(var, "SERVER_SOFTWARE")) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk result = ap_get_server_banner();
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk break;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk break;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk case 16:
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk if (!strcmp(var, "REQUEST_FILENAME")) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk result = r->filename; /* same as script_filename (15) */
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk break;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk case 21:
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk if (!strcmp(var, "HTTP_PROXY_CONNECTION")) {
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk result = lookup_header("Proxy-Connection", ctx);
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk break;
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk }
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk return apr_pstrdup(r->pool, result ? result : "");
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk}
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk/*
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk * +-------------------------------------------------------+
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk * | |
144f8db798e3b92e4e4a3f51904e8f21ad160680mturk * | Expansion functions
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * | |
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * +-------------------------------------------------------+
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe */
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe/*
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * Bracketed expression handling
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe * s points after the opening bracket
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic APR_INLINE char *find_closing_curly(char *s)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
e8f95a682820a599fe41b22977010636be5c2717jim unsigned depth;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe for (depth = 1; *s; ++s) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe if (*s == RIGHT_CURLY && --depth == 0) {
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe return s;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb else if (*s == LEFT_CURLY) {
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb ++depth;
9379749d811388a7d0e3410940ddd6743a33d330jim }
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb }
9379749d811388a7d0e3410940ddd6743a33d330jim
9379749d811388a7d0e3410940ddd6743a33d330jim return NULL;
b0ac1e83f8582a9b5a72bff798ffb31a419c8adesf}
e99dfd55d29a7b4209b814efc7270d0b74ccee74niq
e99dfd55d29a7b4209b814efc7270d0b74ccee74niqstatic APR_INLINE char *find_char_in_curlies(char *s, int c)
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim{
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim unsigned depth;
d27b1ee5dae8f52cdde42e0ac1939cc2397c1be5jim
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb for (depth = 1; *s; ++s) {
997023faa943892aae20d092044aa983c2936982niq if (*s == c && depth == 1) {
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb return s;
997023faa943892aae20d092044aa983c2936982niq }
a812b025d139f465a31c76fc02ed162ed5271b03nd else if (*s == RIGHT_CURLY && --depth == 0) {
997023faa943892aae20d092044aa983c2936982niq return NULL;
a812b025d139f465a31c76fc02ed162ed5271b03nd }
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb else if (*s == LEFT_CURLY) {
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb ++depth;
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb }
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb }
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin
afef080e47ef499a5cbceb7ad7fadbb3abca0b48minfrin return NULL;
35c9e4d2c0a6465746a98958ef756114834461e6minfrin}
35c9e4d2c0a6465746a98958ef756114834461e6minfrin
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb/* perform all the expansions on the input string
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb * putting the result into a new string
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb *
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb * for security reasons this expansion must be performed in a
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb * single pass, otherwise an attacker can arrange for the result
a2f9f38db0931e6edf7b71378dd680c3c5fa5841rbb * of an earlier expansion to include expansion specifiers that
40b22d3b20454959fe51fdc89907908d77701078minfrin * are interpreted by a later expansion, producing results that
4ecd546edd89824908c2a9ad2e07339d89368f9cmartin * were not intended by the administrator.
3709b26f3370ae89c5324a3c03fab56a93b09ecdsf */
4ecd546edd89824908c2a9ad2e07339d89368f9cmartinstatic char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
4224d5789080ea5586d49420da1e1996f5653bb5ianh{
4224d5789080ea5586d49420da1e1996f5653bb5ianh result_list *result, *current;
4224d5789080ea5586d49420da1e1996f5653bb5ianh result_list sresult[SMALL_EXPANSION];
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim unsigned spc = 0;
db8ac7cbb1fa6cdd6abcc4bb797d4deed32dd269jim apr_size_t span, inputlen, outlen;
5d5c9e862c3d4e7f15c12d293de4111f52404760wrowe char *p, *c;
e8f95a682820a599fe41b22977010636be5c2717jim apr_pool_t *pool = ctx->r->pool;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe span = strcspn(input, "\\$%");
65efbf0826de766a90d745cc44427bfa4e2447b6mturk inputlen = strlen(input);
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
b2b9b7f0644773b50aee41956a841ac884086250niq /* fast exit */
b2b9b7f0644773b50aee41956a841ac884086250niq if (inputlen == span) {
93cf7fc650197b941ae31a7c7e51e901b129e954igalic return apr_pstrdup(pool, input);
93cf7fc650197b941ae31a7c7e51e901b129e954igalic }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* well, actually something to do */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding result = current = &(sresult[spc++]);
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm p = input + span;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk current->next = NULL;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk current->string = input;
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm current->len = span;
de8799b6a9e8221681873ab5a81b6af6596faaafwrowe outlen = span;
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm
e8f95a682820a599fe41b22977010636be5c2717jim /* loop for specials */
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm do {
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm /* prepare next entry */
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm if (current->len) {
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm current->next = (spc < SMALL_EXPANSION)
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm ? &(sresult[spc++])
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm : (result_list *)apr_palloc(pool,
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm sizeof(result_list));
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm current = current->next;
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm current->next = NULL;
1723d9ccdd3b647f5b7bae44cab9ab3eca7a4874dougm current->len = 0;
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm }
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm /* escaped character */
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm if (*p == '\\') {
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm current->len = 1;
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm ++outlen;
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm if (!p[1]) {
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm current->string = p;
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm break;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk }
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk else {
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk current->string = ++p;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk ++p;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk }
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk }
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk /* variable or map lookup */
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk else if (p[1] == '{') {
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk char *endp;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk endp = find_closing_curly(p+2);
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk if (!endp) {
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk current->len = 2;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk current->string = p;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk outlen += 2;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk p += 2;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk }
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk /* variable lookup */
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk else if (*p == '%') {
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm p = lookup_variable(apr_pstrmemdup(pool, p+2, endp-p-2), ctx);
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm span = strlen(p);
655b45ecbcfe204749cddff73f149dc0ec278905mturk current->len = span;
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm current->string = p;
621bd763d2e4d32f19013ac8b76b375b5a01851fdougm outlen += span;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk p = endp + 1;
79d97c2c5e2d3f8bb2a92cd21b3b4900d7bf04d6mturk }
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm /* map lookup */
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm else { /* *p == '$' */
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm char *key;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe /*
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe * To make rewrite maps useful, the lookup key and
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe * default values must be expanded, so we make
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe * recursive calls to do the work. For security
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe * reasons we must never expand a string that includes
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe * verbatim data from the network. The recursion here
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe * isn't a problem because the result of expansion is
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe * only passed to lookup_map() so it cannot be
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe * re-expanded, only re-looked-up. Another way of
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere * looking at it is that the recursion is entirely
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe * driven by the syntax of the nested curly brackets.
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe */
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe key = find_char_in_curlies(p+2, ':');
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (!key) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->len = 2;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->string = p;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe outlen += 2;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe p += 2;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
9e3209bc06ddf32f23e4b254faa45914bc323cc9jim else {
e8f95a682820a599fe41b22977010636be5c2717jim char *map, *dflt;
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim map = apr_pstrmemdup(pool, p+2, endp-p-2);
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim key = map + (key-p-2);
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim *key++ = '\0';
c64fb33e0c4634fd352c4a6c143cd1a087c09b13nd dflt = find_char_in_curlies(key, '|');
c64fb33e0c4634fd352c4a6c143cd1a087c09b13nd if (dflt) {
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim *dflt++ = '\0';
c64fb33e0c4634fd352c4a6c143cd1a087c09b13nd }
cd42921af450e87bc797da0ff899348b75732645jfclere
cd42921af450e87bc797da0ff899348b75732645jfclere /* reuse of key variable as result */
c64fb33e0c4634fd352c4a6c143cd1a087c09b13nd key = lookup_map(ctx->r, map, do_expand(key, ctx, entry));
cd42921af450e87bc797da0ff899348b75732645jfclere
9e3209bc06ddf32f23e4b254faa45914bc323cc9jim if (!key && dflt && *dflt) {
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim key = do_expand(dflt, ctx, entry);
9e3209bc06ddf32f23e4b254faa45914bc323cc9jim }
596716fb99c98e83ff7c2c3d78f9fc55ea116be6jim
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (key) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe span = strlen(key);
67d13599fd4a5f73a2d3fc2b566a9aad60b1c892mturk current->len = span;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->string = key;
f185ce14f5dd540ae54659f764989c017c619485jim outlen += span;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere p = endp + 1;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
166a9c7964cffc8193764d877edce5bb9b509551mturk }
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim }
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere /* backreference */
67d13599fd4a5f73a2d3fc2b566a9aad60b1c892mturk else if (apr_isdigit(p[1])) {
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere int n = p[1] - '0';
67d13599fd4a5f73a2d3fc2b566a9aad60b1c892mturk backrefinfo *bri = (*p == '$') ? &ctx->briRR : &ctx->briRC;
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere
67d13599fd4a5f73a2d3fc2b566a9aad60b1c892mturk /* see ap_pregsub() in server/util.c */
67d13599fd4a5f73a2d3fc2b566a9aad60b1c892mturk if (bri->source && n < AP_MAX_REG_MATCH
67d13599fd4a5f73a2d3fc2b566a9aad60b1c892mturk && bri->regmatch[n].rm_eo > bri->regmatch[n].rm_so) {
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere span = bri->regmatch[n].rm_eo - bri->regmatch[n].rm_so;
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere if (entry && (entry->flags & RULEFLAG_ESCAPEBACKREF)) {
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere /* escape the backreference */
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere char *tmp2, *tmp;
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere tmp = apr_pstrndup(pool, bri->source + bri->regmatch[n].rm_so, span);
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere tmp2 = ap_escape_path_segment(pool, tmp);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe rewritelog((ctx->r, 5, ctx->perdir, "escaping backreference '%s' to '%s'",
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere tmp, tmp2));
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->len = span = strlen(tmp2);
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->string = tmp2;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe else {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->len = span;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->string = bri->source + bri->regmatch[n].rm_so;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe outlen += span;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe p += 2;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe }
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
67d13599fd4a5f73a2d3fc2b566a9aad60b1c892mturk /* not for us, just copy it */
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe else {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->len = 1;
d993198d8a18c11aa4e80bc647587df10e663f88jim current->string = p++;
d993198d8a18c11aa4e80bc647587df10e663f88jim ++outlen;
b6832863054a2d09233ce92945e0faceb932a620jwoolley }
92e22cf3d516024d3ed9c6a85610e927e9b3b32djim
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe /* check the remainder */
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (*p && (span = strcspn(p, "\\$%")) > 0) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe if (current->len) {
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe current->next = (spc < SMALL_EXPANSION)
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe ? &(sresult[spc++])
1d2ff7570139286b0f0d16f92187a16ed5932291mturk : (result_list *)apr_palloc(pool,
1d2ff7570139286b0f0d16f92187a16ed5932291mturk sizeof(result_list));
a865e849a3b00dc8524ecdda09a1699452876219mturk current = current->next;
e8f95a682820a599fe41b22977010636be5c2717jim current->next = NULL;
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim }
888c31d26ec2735b6e744697dcaec1ab12877b01mturk
888c31d26ec2735b6e744697dcaec1ab12877b01mturk current->len = span;
888c31d26ec2735b6e744697dcaec1ab12877b01mturk current->string = p;
888c31d26ec2735b6e744697dcaec1ab12877b01mturk p += span;
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim outlen += span;
888c31d26ec2735b6e744697dcaec1ab12877b01mturk }
888c31d26ec2735b6e744697dcaec1ab12877b01mturk
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim } while (p < input+inputlen);
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim /* assemble result */
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim c = p = apr_palloc(pool, outlen + 1); /* don't forget the \0 */
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim do {
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim if (result->len) {
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim ap_assert(c+result->len <= p+outlen); /* XXX: can be removed after
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim * extensive testing and
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere * review
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere */
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim memcpy(c, result->string, result->len);
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim c += result->len;
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim }
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim result = result->next;
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim } while (result);
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim
14c8c18e6caab1bdeb0f26b2b031e000fef58ef9jim p[outlen] = '\0';
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim return p;
888c31d26ec2735b6e744697dcaec1ab12877b01mturk}
e8f95a682820a599fe41b22977010636be5c2717jim
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim/*
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim * perform all the expansions on the environment variables
888c31d26ec2735b6e744697dcaec1ab12877b01mturk */
a865e849a3b00dc8524ecdda09a1699452876219mturkstatic void do_expand_env(data_item *env, rewrite_ctx *ctx)
cb7cf74a315df272e2ec329ce2ef1d50b82b8384jim{
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim char *name, *val;
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim while (env) {
14c8c18e6caab1bdeb0f26b2b031e000fef58ef9jim name = do_expand(env->data, ctx, NULL);
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim if ((val = ap_strchr(name, ':')) != NULL) {
a865e849a3b00dc8524ecdda09a1699452876219mturk *val++ = '\0';
a865e849a3b00dc8524ecdda09a1699452876219mturk
e8f95a682820a599fe41b22977010636be5c2717jim apr_table_set(ctx->r->subprocess_env, name, val);
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim rewritelog((ctx->r, 5, NULL, "setting env variable '%s' to '%s'",
a865e849a3b00dc8524ecdda09a1699452876219mturk name, val));
a865e849a3b00dc8524ecdda09a1699452876219mturk }
748859d4eeb90f2a64b8b8318bc45c3a61dcd968jim
888c31d26ec2735b6e744697dcaec1ab12877b01mturk env = env->next;
1d2ff7570139286b0f0d16f92187a16ed5932291mturk }
1d2ff7570139286b0f0d16f92187a16ed5932291mturk
1d2ff7570139286b0f0d16f92187a16ed5932291mturk return;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe}
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe/*
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe * perform all the expansions on the cookies
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe *
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe * TODO: use cached time similar to how logging does it
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe */
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowestatic void add_cookie(request_rec *r, char *s)
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe{
e8f95a682820a599fe41b22977010636be5c2717jim char *var;
559db7681c06b49d8b57de9edb97b430c3b4d676mturk char *val;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe char *domain;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe char *expires;
73e8b26287de5c06fa470d36162e103dbac9c7e5wrowe char *path;
5babe00918c88eda487771fa6d6d4a1a19c0ced0chuck
65aeb4185d6a108b19c27b89f311dc57dab62239nd char *tok_cntx;
65aeb4185d6a108b19c27b89f311dc57dab62239nd char *cookie;
65aeb4185d6a108b19c27b89f311dc57dab62239nd
35630e8756729a29273ef1a5c879b90df3594d66rjung var = apr_strtok(s, ":", &tok_cntx);
1d2ff7570139286b0f0d16f92187a16ed5932291mturk val = apr_strtok(NULL, ":", &tok_cntx);
1d2ff7570139286b0f0d16f92187a16ed5932291mturk domain = apr_strtok(NULL, ":", &tok_cntx);
1d2ff7570139286b0f0d16f92187a16ed5932291mturk
1d2ff7570139286b0f0d16f92187a16ed5932291mturk if (var && val && domain) {
4b155326ef6781820619c10e518dce1a44df7f91rjung request_rec *rmain = r;
e8f95a682820a599fe41b22977010636be5c2717jim char *notename;
fdacf528f0125e0165de42b7783b1dcbf961a189chuck void *data;
fdacf528f0125e0165de42b7783b1dcbf961a189chuck
fdacf528f0125e0165de42b7783b1dcbf961a189chuck while (rmain->main) {
e5882a36d7756850cc829f5f2286120b877458b1pquerna rmain = rmain->main;
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe }
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe
fdacf528f0125e0165de42b7783b1dcbf961a189chuck notename = apr_pstrcat(rmain->pool, var, "_rewrite", NULL);
65aeb4185d6a108b19c27b89f311dc57dab62239nd apr_pool_userdata_get(&data, notename, rmain->pool);
fdacf528f0125e0165de42b7783b1dcbf961a189chuck if (!data) {
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe char *exp_time = NULL;
c0a549c3f6e8edc87e921cf76fac95d04feba72bwrowe
e8f95a682820a599fe41b22977010636be5c2717jim expires = apr_strtok(NULL, ":", &tok_cntx);
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm path = expires ? apr_strtok(NULL, ":", &tok_cntx) : NULL;
e1d00c81dc34e2c644cc936b9dea75ec9ccfca2adougm
1d2ff7570139286b0f0d16f92187a16ed5932291mturk if (expires) {
e8f95a682820a599fe41b22977010636be5c2717jim apr_time_exp_t tms;
1d2ff7570139286b0f0d16f92187a16ed5932291mturk apr_time_exp_gmt(&tms, r->request_time
5babe00918c88eda487771fa6d6d4a1a19c0ced0chuck + apr_time_from_sec((60 * atol(expires))));
5babe00918c88eda487771fa6d6d4a1a19c0ced0chuck exp_time = apr_psprintf(r->pool, "%s, %.2d-%s-%.4d "
36ef8f77bffe75d1aa327882be1b5bdbe2ff567asf "%.2d:%.2d:%.2d GMT",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_day_snames[tms.tm_wday],
5babe00918c88eda487771fa6d6d4a1a19c0ced0chuck tms.tm_mday,
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe apr_month_snames[tms.tm_mon],
2ceedfca3a2fdfdb5ff60ca17f030ce91f6331cbwrowe tms.tm_year+1900,
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk tms.tm_hour, tms.tm_min, tms.tm_sec);
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk }
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk
5babe00918c88eda487771fa6d6d4a1a19c0ced0chuck cookie = apr_pstrcat(rmain->pool,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding var, "=", val,
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin "; path=", path ? path : "/",
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin "; domain=", domain,
65efbf0826de766a90d745cc44427bfa4e2447b6mturk expires ? "; expires=" : NULL,
65efbf0826de766a90d745cc44427bfa4e2447b6mturk expires ? exp_time : NULL,
65efbf0826de766a90d745cc44427bfa4e2447b6mturk NULL);
65efbf0826de766a90d745cc44427bfa4e2447b6mturk
bda7a7d57377f45932c237d5aba00b189d85c2a9ianh apr_table_addn(rmain->err_headers_out, "Set-Cookie", cookie);
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin apr_pool_userdata_set("set", notename, NULL, rmain->pool);
2e41eca72bcc4167d1871b0941ee79845540d58eminfrin rewritelog((rmain, 5, NULL, "setting cookie '%s'", cookie));
e8f95a682820a599fe41b22977010636be5c2717jim }
446c6a9a1e1073798258f1237f8c848b5f917b66wrowe else {
e8f95a682820a599fe41b22977010636be5c2717jim rewritelog((rmain, 5, NULL, "skipping already set cookie '%s'",
e8f95a682820a599fe41b22977010636be5c2717jim var));
446c6a9a1e1073798258f1237f8c848b5f917b66wrowe }
446c6a9a1e1073798258f1237f8c848b5f917b66wrowe }
e8f95a682820a599fe41b22977010636be5c2717jim
446c6a9a1e1073798258f1237f8c848b5f917b66wrowe return;
446c6a9a1e1073798258f1237f8c848b5f917b66wrowe}
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe
d75bc22ab2702fa770f6935f07107efff16a76f0wrowestatic void do_expand_cookie(data_item *cookie, rewrite_ctx *ctx)
5a5a6c22260854843c973e2ea9a14bec64362ab5wrowe{
e8f95a682820a599fe41b22977010636be5c2717jim while (cookie) {
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe add_cookie(ctx->r, do_expand(cookie->data, ctx, NULL));
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe cookie = cookie->next;
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe }
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe return;
5a5a6c22260854843c973e2ea9a14bec64362ab5wrowe}
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe#if APR_HAS_USER
d75bc22ab2702fa770f6935f07107efff16a76f0wrowe/*
67f62b7a48ff9eb8d9f31898dceaf9f89280a723dougm * Expand tilde-paths (/~user) through Unix /etc/passwd
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk * database information (or other OS-specific database)
b9b3cd7661ec354e0eee71116faa1e4afdf3fcdcmturk */
bda7a7d57377f45932c237d5aba00b189d85c2a9ianhstatic char *expand_tildepaths(request_rec *r, char *uri)
e8f95a682820a599fe41b22977010636be5c2717jim{
bda7a7d57377f45932c237d5aba00b189d85c2a9ianh if (uri && *uri == '/' && uri[1] == '~') {
bda7a7d57377f45932c237d5aba00b189d85c2a9ianh 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;
/* only operate if a lockfile is used */
if (lockname == NULL || *(lockname) == '\0') {
return APR_SUCCESS;
}
/* create the lockfile */
rc = apr_global_mutex_create(&rewrite_mapr_lock_acquire, lockname,
APR_LOCK_DEFAULT, p);
if (rc != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rc, s,
"mod_rewrite: Parent could not create RewriteLock "
"file %s", lockname);
return rc;
}
#ifdef AP_NEED_SET_MUTEX_PERMS
rc = unixd_set_global_mutex_perms(rewrite_mapr_lock_acquire);
if (rc != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rc, s,
"mod_rewrite: Parent could not set permissions "
"on RewriteLock; check User and Group directives");
return rc;
}
#endif
return APR_SUCCESS;
}
static apr_status_t rewritelock_remove(void *data)
{
/* only operate if a lockfile is used */
if (lockname == NULL || *(lockname) == '\0') {
return APR_SUCCESS;
}
/* destroy the rewritelock */
apr_global_mutex_destroy (rewrite_mapr_lock_acquire);
rewrite_mapr_lock_acquire = NULL;
lockname = 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;
#ifndef REWRITELOG_DISABLED
a->rewritelogfile = NULL;
a->rewritelogfp = NULL;
a->rewriteloglevel = 0;
#endif
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;
a->options = overrides->options;
a->server = overrides->server;
if (a->options & OPTION_INHERIT) {
/*
* local directives override
* and anything else is inherited
*/
#ifndef REWRITELOG_DISABLED
a->rewriteloglevel = overrides->rewriteloglevel != 0
? overrides->rewriteloglevel
: base->rewriteloglevel;
a->rewritelogfile = overrides->rewritelogfile != NULL
? overrides->rewritelogfile
: base->rewritelogfile;
a->rewritelogfp = overrides->rewritelogfp != NULL
? overrides->rewritelogfp
: base->rewritelogfp;
#endif
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 {
/*
* local directives override
* and anything else gets defaults
*/
#ifndef REWRITELOG_DISABLED
a->rewriteloglevel = overrides->rewriteloglevel;
a->rewritelogfile = overrides->rewritelogfile;
a->rewritelogfp = overrides->rewritelogfp;
#endif
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;
a->options = overrides->options;
a->directory = overrides->directory;
a->baseurl = overrides->baseurl;
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 {
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);
if (cmd->path == NULL) { /* is server command */
sconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED);
}
else /* is per-directory command */ {
dconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED);
}
return NULL;
}
static const char *cmd_rewriteoptions(cmd_parms *cmd,
void *in_dconf, const char *option)
{
int options = 0;
char *w;
while (*option) {
w = ap_getword_conf(cmd->pool, &option);
if (!strcasecmp(w, "inherit")) {
options |= OPTION_INHERIT;
}
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);
}
}
/* put it into the appropriate config */
if (cmd->path == NULL) { /* is server command */
rewrite_server_conf *conf =
ap_get_module_config(cmd->server->module_config,
&rewrite_module);
conf->options |= options;
}
else { /* is per-directory command */
rewrite_perdir_conf *conf = in_dconf;
conf->options |= options;
}
return NULL;
}
#ifndef REWRITELOG_DISABLED
static const char *cmd_rewritelog(cmd_parms *cmd, void *dconf, const char *a1)
{
rewrite_server_conf *sconf;
sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
sconf->rewritelogfile = a1;
return NULL;
}
static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf,
const char *a1)
{
rewrite_server_conf *sconf;
sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
sconf->rewriteloglevel = atoi(a1);
return NULL;
}
#endif /* rewritelog */
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_rewritelock(cmd_parms *cmd, void *dconf, const char *a1)
{
const char *error;
if ((error = ap_check_cmd_context(cmd, GLOBAL_ONLY)) != NULL)
return error;
/* fixup the path, especially for rewritelock_remove() */
lockname = ap_server_root_relative(cmd->pool, a1);
if (!lockname) {
return apr_pstrcat(cmd->pool, "Invalid RewriteLock path ", a1);
}
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;
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 "RewriteCond: 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, "RewriteCond: 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 err;
}
}
/* arg2: the pattern */
if (*a2 == '!') {
newcond->flags |= CONDFLAG_NOTMATCH;
++a2;
}
/* determine the pattern type */
newcond->ptype = 0;
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 'l': newcond->ptype = CONDPAT_FILE_LINK; break;
case 'd': newcond->ptype = CONDPAT_FILE_DIR; break;
case 'x': newcond->ptype = CONDPAT_FILE_XBIT; break;
case 'U': newcond->ptype = CONDPAT_LU_URL; break;
case 'F': newcond->ptype = CONDPAT_LU_FILE; break;
}
}
else {
switch (*a2) {
case '>': newcond->ptype = CONDPAT_STR_GT; break;
case '<': 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 && newcond->ptype != CONDPAT_STR_EQ &&
(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->pattern = a2;
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 '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 {
++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 {
++error;
}
break;
case 'r':
case 'R':
if (!*key || !strcasecmp(key, "edirect")) { /* redirect */
int status = 0;
cfg->flags |= RULEFLAG_FORCEREDIRECT;
if (strlen(val) > 0) {
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, "RewriteRule: 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, "RewriteRule: 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 err;
}
}
/* 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;
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_GT:
rc = (compare_lexicography(input, p->pattern+1) == 1) ? 1 : 0;
break;
case CONDPAT_STR_LT:
rc = (compare_lexicography(input, p->pattern+1) == -1) ? 1 : 0;
break;
case CONDPAT_STR_EQ:
if (p->flags & CONDFLAG_NOCASE) {
rc = !strcasecmp(input, p->pattern);
}
else {
rc = !strcmp(input, 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'%s "
"=> %s", input, (p->flags & CONDFLAG_NOTMATCH) ? "!" : "",
(p->ptype == CONDPAT_STR_EQ) ? "=" : "", p->pattern,
(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;
splitout_queryargs(r, p->flags & RULEFLAG_QSAPPEND);
/* 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) {
/* PR#39746: Escaping things here gets repeated in mod_proxy */
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;
}
/*
* 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;
/* register int: rewritemap handlers */
mapfunc_hash = apr_hash_make(pconf);
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);
#ifndef REWRITELOG_DISABLED
/* create the rewriting lockfiles in the parent */
if ((rv = apr_global_mutex_create(&rewrite_log_lock, NULL,
APR_LOCK_DEFAULT, p)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
"mod_rewrite: could not create rewrite_log_lock");
return HTTP_INTERNAL_SERVER_ERROR;
}
#ifdef AP_NEED_SET_MUTEX_PERMS
rv = unixd_set_global_mutex_perms(rewrite_log_lock);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
"mod_rewrite: Could not set permissions on "
"rewrite_log_lock; check User and Group directives");
return HTTP_INTERNAL_SERVER_ERROR;
}
#endif /* perms */
#endif /* rewritelog */
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) {
#ifndef REWRITELOG_DISABLED
if (!open_rewritelog(s, p)) {
return HTTP_INTERNAL_SERVER_ERROR;
}
#endif
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 (lockname != NULL && *(lockname) != '\0') {
rv = apr_global_mutex_child_init(&rewrite_mapr_lock_acquire,
lockname, 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");
}
}
#ifndef REWRITELOG_DISABLED
rv = apr_global_mutex_child_init(&rewrite_log_lock, NULL, p);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
"mod_rewrite: could not init rewrite log lock in child");
}
#endif
/* 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_server_conf *conf;
const char *saved_rulestatus;
const char *var;
const char *thisserver;
char *thisport;
const char *thisurl;
unsigned int port;
int rulestatus;
/*
* retrieve the config structures
*/
conf = ap_get_module_config(r->server->module_config, &rewrite_module);
/*
* only do something under runtime if the engine is really enabled,
* else return immediately!
*/
if (conf->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;
}
/*
* 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(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->uri == r->unparsed_uri) {
/* 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;
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->state == ENGINE_DISABLED) {
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, "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
* | |
* +-------------------------------------------------------+
*/
#ifdef REWRITELOG_DISABLED
static const char *fake_rewritelog(cmd_parms *cmd, void *dummy, const char *a1)
{
return "RewriteLog and RewriteLogLevel are not supported by this build "
"of mod_rewrite because it was compiled using the "
"-DREWRITELOG_DISABLED compiler option. You have to recompile "
"mod_rewrite WITHOUT this option in order to use the rewrite log.";
}
#endif
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"),
AP_INIT_TAKE1( "RewriteLock", cmd_rewritelock, NULL, RSRC_CONF,
"the filename of a lockfile used for inter-process "
"synchronization"),
#ifndef REWRITELOG_DISABLED
AP_INIT_TAKE1( "RewriteLog", cmd_rewritelog, NULL, RSRC_CONF,
"the filename of the rewriting logfile"),
AP_INIT_TAKE1( "RewriteLogLevel", cmd_rewriteloglevel, NULL, RSRC_CONF,
"the level of the rewriting logfile verbosity "
"(0=none, 1=std, .., 9=max)"),
#else
AP_INIT_TAKE1( "RewriteLog", fake_rewritelog, NULL, RSRC_CONF,
"[DISABLED] the filename of the rewriting logfile"),
AP_INIT_TAKE1( "RewriteLogLevel", fake_rewritelog, NULL, RSRC_CONF,
"[DISABLED] the level of the rewriting logfile verbosity"),
#endif
{ 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 };
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 */
module AP_MODULE_DECLARE_DATA rewrite_module = {
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*/