1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #define MOD_REWRITE_H 1
22 ** _ __ ___ ___ __| | _ __ _____ ___ __(_) |_ ___
23 ** | '_ ` _ \ / _ \ / _` | | '__/ _ \ \ /\ / / '__| | __/ _ \
24 ** | | | | | | (_) | (_| | | | | __/\ V V /| | | | || __/
25 ** |_| |_| |_|\___/ \__,_|___|_| \___| \_/\_/ |_| |_|\__\___|
28 ** URL Rewriting Module
30 ** This module uses a rule-based rewriting engine (based on a
31 ** regular-expression parser) to rewrite requested URLs on the fly.
33 ** It supports an unlimited number of additional rule conditions (which can
34 ** operate on a lot of variables, even on HTTP headers) for granular
35 ** matching and even external database lookups (either via plain text
36 ** tables, DBM hash files or even external processes) for advanced URL
39 ** It operates on the full URLs (including the PATH_INFO part) both in
40 ** per-server context (httpd.conf) and per-dir context (.htaccess) and even
41 ** can generate QUERY_STRING parts on result. The rewriting result finally
42 ** can lead to internal subprocessing, external request redirection or even
43 ** to internal proxy throughput.
45 ** This module was originally written in April 1996 and
46 ** gifted exclusively to the The Apache Software Foundation in July 1997 by
48 ** Ralf S. Engelschall
49 ** rse@engelschall.com
50 ** www.engelschall.com
55 #define APR_WANT_STRFUNC
56 #define APR_WANT_MEMFUNC
59 /* Include from the underlaying Unix system ... */
69 #if APR_HAVE_SYS_TYPES_H
70 #include <sys/types.h>
74 #include "apr_thread_mutex.h"
76 #include "apr_optional.h"
78 #include "ap_config.h"
80 /* Include from the Apache server ... */
83 #include "http_config.h"
84 #include "http_request.h"
85 #include "http_core.h"
87 #include "http_vhost.h"
90 * The key in the r->notes apr_table_t wherein we store our accumulated
91 * Vary values, and the one used for per-condition checks in a chain.
93 #define VARY_KEY "rewrite-Vary"
94 #define VARY_KEY_THIS "rewrite-Vary-this"
102 #define ENVVAR_SCRIPT_URL "SCRIPT_URL"
103 #define ENVVAR_SCRIPT_URI "SCRIPT_URI"
105 #define REWRITE_FORCED_MIMETYPE_NOTEVAR "rewrite-forced-mimetype"
107 #define CONDFLAG_NONE 1<<0
108 #define CONDFLAG_NOCASE 1<<1
109 #define CONDFLAG_NOTMATCH 1<<2
110 #define CONDFLAG_ORNEXT 1<<3
112 #define RULEFLAG_NONE 1<<0
113 #define RULEFLAG_FORCEREDIRECT 1<<1
114 #define RULEFLAG_LASTRULE 1<<2
115 #define RULEFLAG_NEWROUND 1<<3
116 #define RULEFLAG_CHAIN 1<<4
117 #define RULEFLAG_IGNOREONSUBREQ 1<<5
118 #define RULEFLAG_NOTMATCH 1<<6
119 #define RULEFLAG_PROXY 1<<7
120 #define RULEFLAG_PASSTHROUGH 1<<8
121 #define RULEFLAG_FORBIDDEN 1<<9
122 #define RULEFLAG_GONE 1<<10
123 #define RULEFLAG_QSAPPEND 1<<11
124 #define RULEFLAG_NOCASE 1<<12
125 #define RULEFLAG_NOESCAPE 1<<13
127 #define ACTION_NORMAL 1<<0
128 #define ACTION_NOESCAPE 1<<1
130 #define MAPTYPE_TXT 1<<0
131 #define MAPTYPE_DBM 1<<1
132 #define MAPTYPE_PRG 1<<2
133 #define MAPTYPE_INT 1<<3
134 #define MAPTYPE_RND 1<<4
136 #define ENGINE_DISABLED 1<<0
137 #define ENGINE_ENABLED 1<<1
139 #define OPTION_NONE 1<<0
140 #define OPTION_INHERIT 1<<1
142 #define CACHEMODE_TS 1<<0
143 #define CACHEMODE_TTL 1<<1
145 #define CACHE_TLB_ROWS 1024
146 #define CACHE_TLB_COLS 4
159 #define RAND_MAX 32767
162 #ifndef LONG_STRING_LEN
163 #define LONG_STRING_LEN 2048
166 #define MAX_ENV_FLAGS 15
167 #define MAX_COOKIE_FLAGS 15
168 /*** max cookie size in rfc 2109 ***/
169 #define MAX_COOKIE_LEN 4096
171 /* default maximum number of internal redirects */
172 #define REWRITE_REDIRECT_LIMIT 10
177 ** our private data structures we handle with
181 /* the list structures for holding the mapfile information
182 * and the rewrite rules
185 const char *name; /* the name of the map */
186 const char *datafile; /* filename for map data files */
187 const char *dbmtype; /* dbm type for dbm map data files */
188 const char *checkfile; /* filename to check for map existence */
189 int type; /* the type of the map */
190 apr_file_t *fpin; /* in file pointer for program maps */
191 apr_file_t *fpout; /* out file pointer for program maps */
192 apr_file_t *fperr; /* err file pointer for program maps */
193 char *(*func)(request_rec *, /* function pointer for internal maps */
196 char *cachename; /* name for the cache */
200 char *input; /* Input string of RewriteCond */
201 char *pattern; /* the RegExp pattern string */
203 int flags; /* Flags which control the match */
207 apr_array_header_t *rewriteconds; /* the corresponding RewriteCond entries */
208 char *pattern; /* the RegExp pattern string */
209 regex_t *regexp; /* the RegExp pattern compilation */
210 char *output; /* the Substitution string */
211 int flags; /* Flags which control the substitution */
212 char *forced_mimetype; /* forced MIME type of substitution */
213 int forced_responsecode; /* forced HTTP redirect response status */
214 char *env[MAX_ENV_FLAGS+1]; /* added environment variables */
215 char *cookie[MAX_COOKIE_FLAGS+1]; /* added cookies */
216 int skip; /* number of next rules to skip */
220 /* the per-server or per-virtual-server configuration
221 * statically generated once on startup for every server
224 int state; /* the RewriteEngine state */
225 int options; /* the RewriteOption state */
226 const char *rewritelogfile; /* the RewriteLog filename */
227 apr_file_t *rewritelogfp; /* the RewriteLog open filepointer */
228 int rewriteloglevel; /* the RewriteLog level of verbosity */
229 apr_array_header_t *rewritemaps; /* the RewriteMap entries */
230 apr_array_header_t *rewriteconds; /* the RewriteCond entries (temporary) */
231 apr_array_header_t *rewriterules; /* the RewriteRule entries */
232 server_rec *server; /* the corresponding server indicator */
233 int redirect_limit; /* maximum number of internal redirects */
234 } rewrite_server_conf;
237 /* the per-directory configuration
238 * generated on-the-fly by Apache server for current request
241 int state; /* the RewriteEngine state */
242 int options; /* the RewriteOption state */
243 apr_array_header_t *rewriteconds; /* the RewriteCond entries (temporary) */
244 apr_array_header_t *rewriterules; /* the RewriteRule entries */
245 char *directory; /* the directory where it applies */
246 const char *baseurl; /* the base-URL where it applies */
247 int redirect_limit; /* maximum number of internal redirects */
248 } rewrite_perdir_conf;
251 /* the per-request configuration
254 int redirects; /* current number of redirects */
255 int redirect_limit; /* maximum number of redirects */
256 } rewrite_request_conf;
259 /* the cache structures,
260 * a 4-way hash apr_table_t with LRU functionality
262 typedef struct cacheentry {
268 typedef struct tlbentry {
269 int t[CACHE_TLB_COLS];
272 typedef struct cachelist {
274 apr_array_header_t *entries;
275 apr_array_header_t *tlb;
278 typedef struct cache {
280 apr_array_header_t *lists;
282 apr_thread_mutex_t *lock;
287 /* the regex structure for the
288 * substitution of backreferences
290 typedef struct backrefinfo {
293 regmatch_t regmatch[AP_MAX_REG_MATCH];
299 ** forward declarations
303 /* config structure handling */
304 static void *config_server_create(apr_pool_t *p, server_rec *s);
305 static void *config_server_merge (apr_pool_t *p, void *basev, void *overridesv);
306 static void *config_perdir_create(apr_pool_t *p, char *path);
307 static void *config_perdir_merge (apr_pool_t *p, void *basev, void *overridesv);
309 /* config directive handling */
310 static const char *cmd_rewriteengine(cmd_parms *cmd,
311 void *dconf, int flag);
312 static const char *cmd_rewriteoptions(cmd_parms *cmd,
315 static const char *cmd_rewritelog (cmd_parms *cmd, void *dconf, const char *a1);
316 static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, const char *a1);
317 static const char *cmd_rewritemap (cmd_parms *cmd, void *dconf,
318 const char *a1, const char *a2);
319 static const char *cmd_rewritelock(cmd_parms *cmd, void *dconf, const char *a1);
320 static const char *cmd_rewritebase(cmd_parms *cmd, void *dconf,
322 static const char *cmd_rewritecond(cmd_parms *cmd, void *dconf,
324 static const char *cmd_rewritecond_parseflagfield(apr_pool_t *p,
325 rewritecond_entry *new,
327 static const char *cmd_rewritecond_setflag(apr_pool_t *p, rewritecond_entry *cfg,
328 char *key, char *val);
329 static const char *cmd_rewriterule(cmd_parms *cmd, void *dconf,
331 static const char *cmd_rewriterule_parseflagfield(apr_pool_t *p,
332 rewriterule_entry *new,
334 static const char *cmd_rewriterule_setflag(apr_pool_t *p, rewriterule_entry *cfg,
335 char *key, char *val);
338 static int pre_config(apr_pool_t *pconf,
341 static int post_config(apr_pool_t *pconf,
345 static void init_child(apr_pool_t *p, server_rec *s);
348 static int hook_uri2file (request_rec *r);
349 static int hook_mimetype (request_rec *r);
350 static int hook_fixup (request_rec *r);
351 static int handler_redirect(request_rec *r);
353 /* rewriting engine */
354 static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules,
356 static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p,
358 static int apply_rewrite_cond(request_rec *r, rewritecond_entry *p,
359 char *perdir, backrefinfo *briRR,
362 static void do_expand(request_rec *r, char *input, char *buffer, int nbuf,
363 backrefinfo *briRR, backrefinfo *briRC);
364 static void do_expand_env(request_rec *r, char *env[],
365 backrefinfo *briRR, backrefinfo *briRC);
366 static void do_expand_cookie(request_rec *r, char *cookie[],
367 backrefinfo *briRR, backrefinfo *briRC);
369 /* URI transformation function */
370 static void splitout_queryargs(request_rec *r, int qsappend);
371 static void fully_qualify_uri(request_rec *r);
372 static void reduce_uri(request_rec *r);
373 static unsigned is_absolute_uri(char *uri);
374 static char *escape_absolute_uri(apr_pool_t *p, char *uri, unsigned scheme);
375 static char *expand_tildepaths(request_rec *r, char *uri);
377 /* rewrite map support functions */
378 static char *lookup_map(request_rec *r, char *name, char *key);
379 static char *lookup_map_txtfile(request_rec *r, const char *file, char *key);
380 static char *lookup_map_dbmfile(request_rec *r, const char *file,
381 const char *dbmtype, char *key);
382 static char *lookup_map_program(request_rec *r, apr_file_t *fpin,
383 apr_file_t *fpout, char *key);
385 typedef char *(rewrite_mapfunc_t)(request_rec *r, char *key);
386 static void ap_register_rewrite_mapfunc(char *name, rewrite_mapfunc_t *func);
387 APR_DECLARE_OPTIONAL_FN(void, ap_register_rewrite_mapfunc,
388 (char *name, rewrite_mapfunc_t *func));
390 static char *rewrite_mapfunc_toupper(request_rec *r, char *key);
391 static char *rewrite_mapfunc_tolower(request_rec *r, char *key);
392 static char *rewrite_mapfunc_escape(request_rec *r, char *key);
393 static char *rewrite_mapfunc_unescape(request_rec *r, char *key);
395 static char *select_random_value_part(request_rec *r, char *value);
396 static void rewrite_rand_init(void);
397 static int rewrite_rand(int l, int h);
399 /* rewriting logfile support */
400 static int open_rewritelog(server_rec *s, apr_pool_t *p);
401 static void rewritelog(request_rec *r, int level, const char *text, ...)
402 __attribute__((format(printf,3,4)));
403 static char *current_logtime(request_rec *r);
405 /* rewriting lockfile support */
406 static apr_status_t rewritelock_create(server_rec *s, apr_pool_t *p);
407 static apr_status_t rewritelock_remove(void *data);
409 /* program map support */
410 static apr_status_t run_rewritemap_programs(server_rec *s, apr_pool_t *p);
411 static apr_status_t rewritemap_program_child(apr_pool_t *p,
412 const char *progname, char **argv,
416 /* env variable support */
417 static char *lookup_variable(request_rec *r, char *var);
418 static char *lookup_header(request_rec *r, const char *name);
420 /* caching functions */
421 static cache *init_cache(apr_pool_t *p);
422 static char *get_cache_string(cache *c, const char *res, int mode, apr_time_t mtime,
424 static void set_cache_string(cache *c, const char *res, int mode, apr_time_t mtime,
425 char *key, char *value);
426 static cacheentry *retrieve_cache_string(cache *c, const char *res, char *key);
427 static void store_cache_string(cache *c, const char *res, cacheentry *ce);
430 static char *subst_prefix_path(request_rec *r, char *input, char *match,
432 static int parseargline(char *str, char **a1, char **a2, char **a3);
433 static int prefix_stat(const char *path, apr_pool_t *pool);
434 static void add_env_variable(request_rec *r, char *s);
435 static void add_cookie(request_rec *r, char *s);
436 static int subreq_ok(request_rec *r);
437 static int is_redirect_limit_exceeded(request_rec *r);
439 /* Lexicographic Comparison */
440 static int compare_lexicography(char *cpNum1, char *cpNum2);
442 /* Bracketed expression handling */
443 static char *find_closing_bracket(char *s, int left, int right);
444 static char *find_char_in_brackets(char *s, int c, int left, int right);
446 #endif /* MOD_REWRITE_H */