~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to modules/mappers/mod_alias.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

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