/[Apache-SVN]/httpd/httpd/trunk/modules/mappers/mod_alias.c
ViewVC logotype

Contents of /httpd/httpd/trunk/modules/mappers/mod_alias.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 102949 - (show annotations)
Sat Mar 13 21:19:56 2004 UTC (5 years, 8 months ago) by nd
File MIME type: text/plain
File size: 16345 byte(s)
emit the config filename when warning about overlapping aliases

Submitted by: Guenter Knauf <eflash gmx.net>
Reviewed by: Dirk-Willem van Gulik
1 /* Copyright 1999-2004 The Apache Software Foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /*
17 * http_alias.c: Stuff for dealing with directory aliases
18 *
19 * Original by Rob McCool, rewritten in succession by David Robinson
20 * and rst.
21 *
22 */
23
24 #include "apr_strings.h"
25 #include "apr_lib.h"
26
27 #define APR_WANT_STRFUNC
28 #include "apr_want.h"
29
30 #include "ap_config.h"
31 #include "httpd.h"
32 #include "http_core.h"
33 #include "http_config.h"
34 #include "http_request.h"
35 #include "http_log.h"
36
37
38 typedef struct {
39 const char *real;
40 const char *fake;
41 char *handler;
42 regex_t *regexp;
43 int redir_status; /* 301, 302, 303, 410, etc */
44 } alias_entry;
45
46 typedef struct {
47 apr_array_header_t *aliases;
48 apr_array_header_t *redirects;
49 } alias_server_conf;
50
51 typedef struct {
52 apr_array_header_t *redirects;
53 } alias_dir_conf;
54
55 module AP_MODULE_DECLARE_DATA alias_module;
56
57 static void *create_alias_config(apr_pool_t *p, server_rec *s)
58 {
59 alias_server_conf *a =
60 (alias_server_conf *) apr_pcalloc(p, sizeof(alias_server_conf));
61
62 a->aliases = apr_array_make(p, 20, sizeof(alias_entry));
63 a->redirects = apr_array_make(p, 20, sizeof(alias_entry));
64 return a;
65 }
66
67 static void *create_alias_dir_config(apr_pool_t *p, char *d)
68 {
69 alias_dir_conf *a =
70 (alias_dir_conf *) apr_pcalloc(p, sizeof(alias_dir_conf));
71 a->redirects = apr_array_make(p, 2, sizeof(alias_entry));
72 return a;
73 }
74
75 static void *merge_alias_config(apr_pool_t *p, void *basev, void *overridesv)
76 {
77 alias_server_conf *a =
78 (alias_server_conf *) apr_pcalloc(p, sizeof(alias_server_conf));
79 alias_server_conf *base = (alias_server_conf *) basev;
80 alias_server_conf *overrides = (alias_server_conf *) overridesv;
81
82 a->aliases = apr_array_append(p, overrides->aliases, base->aliases);
83 a->redirects = apr_array_append(p, overrides->redirects, base->redirects);
84 return a;
85 }
86
87 static void *merge_alias_dir_config(apr_pool_t *p, void *basev, void *overridesv)
88 {
89 alias_dir_conf *a =
90 (alias_dir_conf *) apr_pcalloc(p, sizeof(alias_dir_conf));
91 alias_dir_conf *base = (alias_dir_conf *) basev;
92 alias_dir_conf *overrides = (alias_dir_conf *) overridesv;
93 a->redirects = apr_array_append(p, overrides->redirects, base->redirects);
94 return a;
95 }
96
97 /* need prototype for overlap check */
98 static int alias_matches(const char *uri, const char *alias_fakename);
99
100 static const char *add_alias_internal(cmd_parms *cmd, void *dummy,
101 const char *f, const char *r,
102 int use_regex)
103 {
104 server_rec *s = cmd->server;
105 alias_server_conf *conf = ap_get_module_config(s->module_config,
106 &alias_module);
107 alias_entry *new = apr_array_push(conf->aliases);
108 alias_entry *entries = (alias_entry *)conf->aliases->elts;
109 int i;
110
111 /* XX r can NOT be relative to DocumentRoot here... compat bug. */
112
113 if (use_regex) {
114 new->regexp = ap_pregcomp(cmd->pool, f, REG_EXTENDED);
115 if (new->regexp == NULL)
116 return "Regular expression could not be compiled.";
117 new->real = r;
118 }
119 else {
120 /* XXX This may be optimized, but we must know that new->real
121 * exists. If so, we can dir merge later, trusing new->real
122 * and just canonicalizing the remainder. Not till I finish
123 * cleaning out the old ap_canonical stuff first.
124 */
125 new->real = r;
126 }
127 new->fake = f;
128 new->handler = cmd->info;
129
130 /* check for overlapping (Script)Alias directives
131 * and throw a warning if found one
132 */
133 if (!use_regex) {
134 for (i = 0; i < conf->aliases->nelts - 1; ++i) {
135 alias_entry *p = &entries[i];
136
137 if ( (!p->regexp && alias_matches(f, p->fake) > 0)
138 || (p->regexp && !ap_regexec(p->regexp, f, 0, NULL, 0))) {
139 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
140 "The %s directive in %s at line %d will probably "
141 "never match because it overlaps an earlier "
142 "%sAlias%s.",
143 cmd->cmd->name, cmd->directive->filename,
144 cmd->directive->line_num,
145 p->handler ? "Script" : "",
146 p->regexp ? "Match" : "");
147
148 break; /* one warning per alias should be sufficient */
149 }
150 }
151 }
152
153 return NULL;
154 }
155
156 static const char *add_alias(cmd_parms *cmd, void *dummy, const char *f,
157 const char *r)
158 {
159 return add_alias_internal(cmd, dummy, f, r, 0);
160 }
161
162 static const char *add_alias_regex(cmd_parms *cmd, void *dummy, const char *f,
163 const char *r)
164 {
165 return add_alias_internal(cmd, dummy, f, r, 1);
166 }
167
168 static const char *add_redirect_internal(cmd_parms *cmd,
169 alias_dir_conf *dirconf,
170 const char *arg1, const char *arg2,
171 const char *arg3, int use_regex)
172 {
173 alias_entry *new;
174 server_rec *s = cmd->server;
175 alias_server_conf *serverconf = ap_get_module_config(s->module_config,
176 &alias_module);
177 int status = (int) (long) cmd->info;
178 regex_t *r = NULL;
179 const char *f = arg2;
180 const char *url = arg3;
181
182 if (!strcasecmp(arg1, "gone"))
183 status = HTTP_GONE;
184 else if (!strcasecmp(arg1, "permanent"))
185 status = HTTP_MOVED_PERMANENTLY;
186 else if (!strcasecmp(arg1, "temp"))
187 status = HTTP_MOVED_TEMPORARILY;
188 else if (!strcasecmp(arg1, "seeother"))
189 status = HTTP_SEE_OTHER;
190 else if (apr_isdigit(*arg1))
191 status = atoi(arg1);
192 else {
193 f = arg1;
194 url = arg2;
195 }
196
197 if (use_regex) {
198 r = ap_pregcomp(cmd->pool, f, REG_EXTENDED);
199 if (r == NULL)
200 return "Regular expression could not be compiled.";
201 }
202
203 if (ap_is_HTTP_REDIRECT(status)) {
204 if (!url)
205 return "URL to redirect to is missing";
206 if (!use_regex && !ap_is_url(url))
207 return "Redirect to non-URL";
208 }
209 else {
210 if (url)
211 return "Redirect URL not valid for this status";
212 }
213
214 if (cmd->path)
215 new = apr_array_push(dirconf->redirects);
216 else
217 new = apr_array_push(serverconf->redirects);
218
219 new->fake = f;
220 new->real = url;
221 new->regexp = r;
222 new->redir_status = status;
223 return NULL;
224 }
225
226 static const char *add_redirect(cmd_parms *cmd, void *dirconf,
227 const char *arg1, const char *arg2,
228 const char *arg3)
229 {
230 return add_redirect_internal(cmd, dirconf, arg1, arg2, arg3, 0);
231 }
232
233 static const char *add_redirect2(cmd_parms *cmd, void *dirconf,
234 const char *arg1, const char *arg2)
235 {
236 return add_redirect_internal(cmd, dirconf, arg1, arg2, NULL, 0);
237 }
238
239 static const char *add_redirect_regex(cmd_parms *cmd, void *dirconf,
240 const char *arg1, const char *arg2,
241 const char *arg3)
242 {
243 return add_redirect_internal(cmd, dirconf, arg1, arg2, arg3, 1);
244 }
245
246 static const command_rec alias_cmds[] =
247 {
248 AP_INIT_TAKE2("Alias", add_alias, NULL, RSRC_CONF,
249 "a fakename and a realname"),
250 AP_INIT_TAKE2("ScriptAlias", add_alias, "cgi-script", RSRC_CONF,
251 "a fakename and a realname"),
252 AP_INIT_TAKE23("Redirect", add_redirect, (void *) HTTP_MOVED_TEMPORARILY,
253 OR_FILEINFO,
254 "an optional status, then document to be redirected and "
255 "destination URL"),
256 AP_INIT_TAKE2("AliasMatch", add_alias_regex, NULL, RSRC_CONF,
257 "a regular expression and a filename"),
258 AP_INIT_TAKE2("ScriptAliasMatch", add_alias_regex, "cgi-script", RSRC_CONF,
259 "a regular expression and a filename"),
260 AP_INIT_TAKE23("RedirectMatch", add_redirect_regex,
261 (void *) HTTP_MOVED_TEMPORARILY, OR_FILEINFO,
262 "an optional status, then a regular expression and "
263 "destination URL"),
264 AP_INIT_TAKE2("RedirectTemp", add_redirect2,
265 (void *) HTTP_MOVED_TEMPORARILY, OR_FILEINFO,
266 "a document to be redirected, then the destination URL"),
267 AP_INIT_TAKE2("RedirectPermanent", add_redirect2,
268 (void *) HTTP_MOVED_PERMANENTLY, OR_FILEINFO,
269 "a document to be redirected, then the destination URL"),
270 {NULL}
271 };
272
273 static int alias_matches(const char *uri, const char *alias_fakename)
274 {
275 const char *aliasp = alias_fakename, *urip = uri;
276
277 while (*aliasp) {
278 if (*aliasp == '/') {
279 /* any number of '/' in the alias matches any number in
280 * the supplied URI, but there must be at least one...
281 */
282 if (*urip != '/')
283 return 0;
284
285 do {
286 ++aliasp;
287 } while (*aliasp == '/');
288 do {
289 ++urip;
290 } while (*urip == '/');
291 }
292 else {
293 /* Other characters are compared literally */
294 if (*urip++ != *aliasp++)
295 return 0;
296 }
297 }
298
299 /* Check last alias path component matched all the way */
300
301 if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/')
302 return 0;
303
304 /* Return number of characters from URI which matched (may be
305 * greater than length of alias, since we may have matched
306 * doubled slashes)
307 */
308
309 return urip - uri;
310 }
311
312 static char *try_alias_list(request_rec *r, apr_array_header_t *aliases,
313 int doesc, int *status)
314 {
315 alias_entry *entries = (alias_entry *) aliases->elts;
316 regmatch_t regm[AP_MAX_REG_MATCH];
317 char *found = NULL;
318 int i;
319
320 for (i = 0; i < aliases->nelts; ++i) {
321 alias_entry *p = &entries[i];
322 int l;
323
324 if (p->regexp) {
325 if (!ap_regexec(p->regexp, r->uri, AP_MAX_REG_MATCH, regm, 0)) {
326 if (p->real) {
327 found = ap_pregsub(r->pool, p->real, r->uri,
328 AP_MAX_REG_MATCH, regm);
329 if (found && doesc) {
330 apr_uri_t uri;
331 apr_uri_parse(r->pool, found, &uri);
332 /* Do not escape the query string or fragment. */
333 found = apr_uri_unparse(r->pool, &uri,
334 APR_URI_UNP_OMITQUERY);
335 found = ap_escape_uri(r->pool, found);
336 if (uri.query) {
337 found = apr_pstrcat(r->pool, found, "?",
338 uri.query, NULL);
339 }
340 if (uri.fragment) {
341 found = apr_pstrcat(r->pool, found, "#",
342 uri.fragment, NULL);
343 }
344 }
345 }
346 else {
347 /* need something non-null */
348 found = apr_pstrdup(r->pool, "");
349 }
350 }
351 }
352 else {
353 l = alias_matches(r->uri, p->fake);
354
355 if (l > 0) {
356 if (doesc) {
357 char *escurl;
358 escurl = ap_os_escape_path(r->pool, r->uri + l, 1);
359
360 found = apr_pstrcat(r->pool, p->real, escurl, NULL);
361 }
362 else
363 found = apr_pstrcat(r->pool, p->real, r->uri + l, NULL);
364 }
365 }
366
367 if (found) {
368 if (p->handler) { /* Set handler, and leave a note for mod_cgi */
369 r->handler = p->handler;
370 apr_table_setn(r->notes, "alias-forced-type", r->handler);
371 }
372 /* XXX This is as SLOW as can be, next step, we optimize
373 * and merge to whatever part of the found path was already
374 * canonicalized. After I finish eliminating os canonical.
375 * Better fail test for ap_server_root_relative needed here.
376 */
377 if (!doesc) {
378 found = ap_server_root_relative(r->pool, found);
379 }
380 if (found) {
381 *status = p->redir_status;
382 }
383 return found;
384 }
385
386 }
387
388 return NULL;
389 }
390
391 static int translate_alias_redir(request_rec *r)
392 {
393 ap_conf_vector_t *sconf = r->server->module_config;
394 alias_server_conf *serverconf = ap_get_module_config(sconf, &alias_module);
395 char *ret;
396 int status;
397
398 if (r->uri[0] != '/' && r->uri[0] != '\0') {
399 return DECLINED;
400 }
401
402 if ((ret = try_alias_list(r, serverconf->redirects, 1, &status)) != NULL) {
403 if (ap_is_HTTP_REDIRECT(status)) {
404 /* include QUERY_STRING if any */
405 if (r->args) {
406 ret = apr_pstrcat(r->pool, ret, "?", r->args, NULL);
407 }
408 apr_table_setn(r->headers_out, "Location", ret);
409 }
410 return status;
411 }
412
413 if ((ret = try_alias_list(r, serverconf->aliases, 0, &status)) != NULL) {
414 r->filename = ret;
415 return OK;
416 }
417
418 return DECLINED;
419 }
420
421 static int fixup_redir(request_rec *r)
422 {
423 void *dconf = r->per_dir_config;
424 alias_dir_conf *dirconf =
425 (alias_dir_conf *) ap_get_module_config(dconf, &alias_module);
426 char *ret;
427 int status;
428
429 /* It may have changed since last time, so try again */
430
431 if ((ret = try_alias_list(r, dirconf->redirects, 1, &status)) != NULL) {
432 if (ap_is_HTTP_REDIRECT(status)) {
433 if (ret[0] == '/') {
434 char *orig_target = ret;
435
436 ret = ap_construct_url(r->pool, ret, r);
437 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
438 "incomplete redirection target of '%s' for "
439 "URI '%s' modified to '%s'",
440 orig_target, r->uri, ret);
441 }
442 if (!ap_is_url(ret)) {
443 status = HTTP_INTERNAL_SERVER_ERROR;
444 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
445 "cannot redirect '%s' to '%s'; "
446 "target is not a valid absoluteURI or abs_path",
447 r->uri, ret);
448 }
449 else {
450 /* append requested query only, if the config didn't
451 * supply its own.
452 */
453 if (r->args && !ap_strchr(ret, '?')) {
454 ret = apr_pstrcat(r->pool, ret, "?", r->args, NULL);
455 }
456 apr_table_setn(r->headers_out, "Location", ret);
457 }
458 }
459 return status;
460 }
461
462 return DECLINED;
463 }
464
465 static void register_hooks(apr_pool_t *p)
466 {
467 static const char * const aszSucc[]={ "mod_userdir.c",
468 "mod_vhost_alias.c",NULL };
469
470 ap_hook_translate_name(translate_alias_redir,NULL,aszSucc,APR_HOOK_MIDDLE);
471 ap_hook_fixups(fixup_redir,NULL,NULL,APR_HOOK_MIDDLE);
472 }
473
474 module AP_MODULE_DECLARE_DATA alias_module =
475 {
476 STANDARD20_MODULE_STUFF,
477 create_alias_dir_config, /* dir config creater */
478 merge_alias_dir_config, /* dir merger --- default is to override */
479 create_alias_config, /* server config */
480 merge_alias_config, /* merge server configs */
481 alias_cmds, /* command apr_table_t */
482 register_hooks /* register hooks */
483 };

Properties

Name Value
cvs2svn:cvs-rev 1.55
svn:eol-style native
svn:keywords Author Date Id Revision

apache@apache.org
ViewVC Help
Powered by ViewVC 1.1.2