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

« back to all changes in this revision

Viewing changes to server/request.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
 * @file  request.c
 
19
 * @brief functions to get and process requests
 
20
 *
 
21
 * @author Rob McCool 3/21/93
 
22
 *
 
23
 * Thoroughly revamped by rst for Apache.  NB this file reads
 
24
 * best from the bottom up.
 
25
 *
 
26
 */
 
27
 
 
28
#include "apr_strings.h"
 
29
#include "apr_file_io.h"
 
30
#include "apr_fnmatch.h"
 
31
 
 
32
#define APR_WANT_STRFUNC
 
33
#include "apr_want.h"
 
34
 
 
35
#define CORE_PRIVATE
 
36
#include "ap_config.h"
 
37
#include "httpd.h"
 
38
#include "http_config.h"
 
39
#include "http_request.h"
 
40
#include "http_core.h"
 
41
#include "http_protocol.h"
 
42
#include "http_log.h"
 
43
#include "http_main.h"
 
44
#include "util_filter.h"
 
45
#include "util_charset.h"
 
46
#include "util_script.h"
 
47
 
 
48
#include "mod_core.h"
 
49
 
 
50
#if APR_HAVE_STDARG_H
 
51
#include <stdarg.h>
 
52
#endif
 
53
 
 
54
APR_HOOK_STRUCT(
 
55
    APR_HOOK_LINK(translate_name)
 
56
    APR_HOOK_LINK(map_to_storage)
 
57
    APR_HOOK_LINK(check_user_id)
 
58
    APR_HOOK_LINK(fixups)
 
59
    APR_HOOK_LINK(type_checker)
 
60
    APR_HOOK_LINK(access_checker)
 
61
    APR_HOOK_LINK(auth_checker)
 
62
    APR_HOOK_LINK(insert_filter)
 
63
    APR_HOOK_LINK(create_request)
 
64
)
 
65
 
 
66
AP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name,
 
67
                            (request_rec *r), (r), DECLINED)
 
68
AP_IMPLEMENT_HOOK_RUN_FIRST(int,map_to_storage,
 
69
                            (request_rec *r), (r), DECLINED)
 
70
AP_IMPLEMENT_HOOK_RUN_FIRST(int,check_user_id,
 
71
                            (request_rec *r), (r), DECLINED)
 
72
AP_IMPLEMENT_HOOK_RUN_ALL(int,fixups,
 
73
                          (request_rec *r), (r), OK, DECLINED)
 
74
AP_IMPLEMENT_HOOK_RUN_FIRST(int,type_checker,
 
75
                            (request_rec *r), (r), DECLINED)
 
76
AP_IMPLEMENT_HOOK_RUN_ALL(int,access_checker,
 
77
                          (request_rec *r), (r), OK, DECLINED)
 
78
AP_IMPLEMENT_HOOK_RUN_FIRST(int,auth_checker,
 
79
                            (request_rec *r), (r), DECLINED)
 
80
AP_IMPLEMENT_HOOK_VOID(insert_filter, (request_rec *r), (r))
 
81
AP_IMPLEMENT_HOOK_RUN_ALL(int, create_request,
 
82
                          (request_rec *r), (r), OK, DECLINED)
 
83
 
 
84
 
 
85
static int decl_die(int status, char *phase, request_rec *r)
 
86
{
 
87
    if (status == DECLINED) {
 
88
        ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
 
89
                      "configuration error:  couldn't %s: %s", phase, r->uri);
 
90
        return HTTP_INTERNAL_SERVER_ERROR;
 
91
    }
 
92
    else {
 
93
        return status;
 
94
    }
 
95
}
 
96
 
 
97
/* This is the master logic for processing requests.  Do NOT duplicate
 
98
 * this logic elsewhere, or the security model will be broken by future
 
99
 * API changes.  Each phase must be individually optimized to pick up
 
100
 * redundant/duplicate calls by subrequests, and redirects.
 
101
 */
 
102
AP_DECLARE(int) ap_process_request_internal(request_rec *r)
 
103
{
 
104
    int file_req = (r->main && r->filename);
 
105
    int access_status;
 
106
 
 
107
    /* Ignore embedded %2F's in path for proxy requests */
 
108
    if (!r->proxyreq && r->parsed_uri.path) {
 
109
        core_dir_config *d;
 
110
        d = ap_get_module_config(r->per_dir_config, &core_module);
 
111
        if (d->allow_encoded_slashes) {
 
112
            access_status = ap_unescape_url_keep2f(r->parsed_uri.path);
 
113
        }
 
114
        else {
 
115
            access_status = ap_unescape_url(r->parsed_uri.path);
 
116
        }
 
117
        if (access_status) {
 
118
            if (access_status == HTTP_NOT_FOUND) {
 
119
                if (! d->allow_encoded_slashes) {
 
120
                    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
 
121
                                  "found %%2f (encoded '/') in URI "
 
122
                                  "(decoded='%s'), returning 404",
 
123
                                  r->parsed_uri.path);
 
124
                }
 
125
            }
 
126
            return access_status;
 
127
        }
 
128
    }
 
129
 
 
130
    ap_getparents(r->uri);     /* OK --- shrinking transformations... */
 
131
 
 
132
    /* All file subrequests are a huge pain... they cannot bubble through the
 
133
     * next several steps.  Only file subrequests are allowed an empty uri,
 
134
     * otherwise let translate_name kill the request.
 
135
     */
 
136
    if (!file_req) {
 
137
        if ((access_status = ap_location_walk(r))) {
 
138
            return access_status;
 
139
        }
 
140
 
 
141
        if ((access_status = ap_run_translate_name(r))) {
 
142
            return decl_die(access_status, "translate", r);
 
143
        }
 
144
    }
 
145
 
 
146
    /* Reset to the server default config prior to running map_to_storage
 
147
     */
 
148
    r->per_dir_config = r->server->lookup_defaults;
 
149
 
 
150
    if ((access_status = ap_run_map_to_storage(r))) {
 
151
        /* This request wasn't in storage (e.g. TRACE) */
 
152
        return access_status;
 
153
    }
 
154
 
 
155
    /* Excluding file-specific requests with no 'true' URI...
 
156
     */
 
157
    if (!file_req) {
 
158
        /* Rerun the location walk, which overrides any map_to_storage config.
 
159
         */
 
160
        if ((access_status = ap_location_walk(r))) {
 
161
            return access_status;
 
162
        }
 
163
    }
 
164
 
 
165
    /* Only on the main request! */
 
166
    if (r->main == NULL) {
 
167
        if ((access_status = ap_run_header_parser(r))) {
 
168
            return access_status;
 
169
        }
 
170
    }
 
171
 
 
172
    /* Skip authn/authz if the parent or prior request passed the authn/authz,
 
173
     * and that configuration didn't change (this requires optimized _walk()
 
174
     * functions in map_to_storage that use the same merge results given
 
175
     * identical input.)  If the config changes, we must re-auth.
 
176
     */
 
177
    if (r->main && (r->main->per_dir_config == r->per_dir_config)) {
 
178
        r->user = r->main->user;
 
179
        r->ap_auth_type = r->main->ap_auth_type;
 
180
    }
 
181
    else if (r->prev && (r->prev->per_dir_config == r->per_dir_config)) {
 
182
        r->user = r->prev->user;
 
183
        r->ap_auth_type = r->prev->ap_auth_type;
 
184
    }
 
185
    else {
 
186
        switch (ap_satisfies(r)) {
 
187
        case SATISFY_ALL:
 
188
        case SATISFY_NOSPEC:
 
189
            if ((access_status = ap_run_access_checker(r)) != 0) {
 
190
                return decl_die(access_status, "check access", r);
 
191
            }
 
192
 
 
193
            if (ap_some_auth_required(r)) {
 
194
                if (((access_status = ap_run_check_user_id(r)) != 0)
 
195
                    || !ap_auth_type(r)) {
 
196
                    return decl_die(access_status, ap_auth_type(r)
 
197
                                  ? "check user.  No user file?"
 
198
                                  : "perform authentication. AuthType not set!",
 
199
                                  r);
 
200
                }
 
201
 
 
202
                if (((access_status = ap_run_auth_checker(r)) != 0)
 
203
                    || !ap_auth_type(r)) {
 
204
                    return decl_die(access_status, ap_auth_type(r)
 
205
                                  ? "check access.  No groups file?"
 
206
                                  : "perform authentication. AuthType not set!",
 
207
                                   r);
 
208
                }
 
209
            }
 
210
            break;
 
211
 
 
212
        case SATISFY_ANY:
 
213
            if (((access_status = ap_run_access_checker(r)) != 0)) {
 
214
                if (!ap_some_auth_required(r)) {
 
215
                    return decl_die(access_status, "check access", r);
 
216
                }
 
217
 
 
218
                if (((access_status = ap_run_check_user_id(r)) != 0)
 
219
                    || !ap_auth_type(r)) {
 
220
                    return decl_die(access_status, ap_auth_type(r)
 
221
                                  ? "check user.  No user file?"
 
222
                                  : "perform authentication. AuthType not set!",
 
223
                                  r);
 
224
                }
 
225
 
 
226
                if (((access_status = ap_run_auth_checker(r)) != 0)
 
227
                    || !ap_auth_type(r)) {
 
228
                    return decl_die(access_status, ap_auth_type(r)
 
229
                                  ? "check access.  No groups file?"
 
230
                                  : "perform authentication. AuthType not set!",
 
231
                                  r);
 
232
                }
 
233
            }
 
234
            break;
 
235
        }
 
236
    }
 
237
    /* XXX Must make certain the ap_run_type_checker short circuits mime
 
238
     * in mod-proxy for r->proxyreq && r->parsed_uri.scheme
 
239
     *                              && !strcmp(r->parsed_uri.scheme, "http")
 
240
     */
 
241
    if ((access_status = ap_run_type_checker(r)) != 0) {
 
242
        return decl_die(access_status, "find types", r);
 
243
    }
 
244
 
 
245
    if ((access_status = ap_run_fixups(r)) != 0) {
 
246
        return access_status;
 
247
    }
 
248
 
 
249
    return OK;
 
250
}
 
251
 
 
252
 
 
253
/* Useful caching structures to repeat _walk/merge sequences as required
 
254
 * when a subrequest or redirect reuses substantially the same config.
 
255
 *
 
256
 * Directive order in the httpd.conf file and its Includes significantly
 
257
 * impact this optimization.  Grouping common blocks at the front of the
 
258
 * config that are less likely to change between a request and
 
259
 * its subrequests, or between a request and its redirects reduced
 
260
 * the work of these functions significantly.
 
261
 */
 
262
 
 
263
typedef struct walk_walked_t {
 
264
    ap_conf_vector_t *matched; /* A dir_conf sections we matched */
 
265
    ap_conf_vector_t *merged;  /* The dir_conf merged result */
 
266
} walk_walked_t;
 
267
 
 
268
typedef struct walk_cache_t {
 
269
    const char         *cached;          /* The identifier we matched */
 
270
    ap_conf_vector_t  **dir_conf_tested; /* The sections we matched against */
 
271
    ap_conf_vector_t   *dir_conf_merged; /* Base per_dir_config */
 
272
    ap_conf_vector_t   *per_dir_result;  /* per_dir_config += walked result */
 
273
    apr_array_header_t *walked;          /* The list of walk_walked_t results */
 
274
} walk_cache_t;
 
275
 
 
276
static walk_cache_t *prep_walk_cache(apr_size_t t, request_rec *r)
 
277
{
 
278
    walk_cache_t *cache;
 
279
    void **note;
 
280
 
 
281
    /* Find the most relevant, recent entry to work from.  That would be
 
282
     * this request (on the second call), or the parent request of a
 
283
     * subrequest, or the prior request of an internal redirect.  Provide
 
284
     * this _walk()er with a copy it is allowed to munge.  If there is no
 
285
     * parent or prior cached request, then create a new walk cache.
 
286
     */
 
287
    note = ap_get_request_note(r, t);
 
288
    if (!note) {
 
289
        return NULL;
 
290
    }
 
291
 
 
292
    if (!(cache = *note)) {
 
293
        void **inherit_note;
 
294
 
 
295
        if ((r->main
 
296
             && ((inherit_note = ap_get_request_note(r->main, t)))
 
297
             && *inherit_note)
 
298
            || (r->prev
 
299
                && ((inherit_note = ap_get_request_note(r->prev, t)))
 
300
                && *inherit_note)) {
 
301
            cache = apr_pmemdup(r->pool, *inherit_note,
 
302
                                sizeof(*cache));
 
303
            cache->walked = apr_array_copy(r->pool, cache->walked);
 
304
        }
 
305
        else {
 
306
            cache = apr_pcalloc(r->pool, sizeof(*cache));
 
307
            cache->walked = apr_array_make(r->pool, 4, sizeof(walk_walked_t));
 
308
        }
 
309
 
 
310
        *note = cache;
 
311
    }
 
312
    return cache;
 
313
}
 
314
 
 
315
/*****************************************************************
 
316
 *
 
317
 * Getting and checking directory configuration.  Also checks the
 
318
 * FollowSymlinks and FollowSymOwner stuff, since this is really the
 
319
 * only place that can happen (barring a new mid_dir_walk callout).
 
320
 *
 
321
 * We can't do it as an access_checker module function which gets
 
322
 * called with the final per_dir_config, since we could have a directory
 
323
 * with FollowSymLinks disabled, which contains a symlink to another
 
324
 * with a .htaccess file which turns FollowSymLinks back on --- and
 
325
 * access in such a case must be denied.  So, whatever it is that
 
326
 * checks FollowSymLinks needs to know the state of the options as
 
327
 * they change, all the way down.
 
328
 */
 
329
 
 
330
 
 
331
/*
 
332
 * resolve_symlink must _always_ be called on an APR_LNK file type!
 
333
 * It will resolve the actual target file type, modification date, etc,
 
334
 * and provide any processing required for symlink evaluation.
 
335
 * Path must already be cleaned, no trailing slash, no multi-slashes,
 
336
 * and don't call this on the root!
 
337
 *
 
338
 * Simply, the number of times we deref a symlink are minimal compared
 
339
 * to the number of times we had an extra lstat() since we 'weren't sure'.
 
340
 *
 
341
 * To optimize, we stat() anything when given (opts & OPT_SYM_LINKS), otherwise
 
342
 * we start off with an lstat().  Every lstat() must be dereferenced in case
 
343
 * it points at a 'nasty' - we must always rerun check_safe_file (or similar.)
 
344
 */
 
345
static int resolve_symlink(char *d, apr_finfo_t *lfi, int opts, apr_pool_t *p)
 
346
{
 
347
    apr_finfo_t fi;
 
348
    int res;
 
349
    const char *savename;
 
350
 
 
351
    if (!(opts & (OPT_SYM_OWNER | OPT_SYM_LINKS))) {
 
352
        return HTTP_FORBIDDEN;
 
353
    }
 
354
 
 
355
    /* Save the name from the valid bits. */
 
356
    savename = (lfi->valid & APR_FINFO_NAME) ? lfi->name : NULL;
 
357
 
 
358
    if (opts & OPT_SYM_LINKS) {
 
359
        if ((res = apr_stat(&fi, d, lfi->valid & ~(APR_FINFO_NAME
 
360
                                                 | APR_FINFO_LINK), p))
 
361
                 != APR_SUCCESS) {
 
362
            return HTTP_FORBIDDEN;
 
363
        }
 
364
 
 
365
        /* Give back the target */
 
366
        memcpy(lfi, &fi, sizeof(fi));
 
367
        if (savename) {
 
368
            lfi->name = savename;
 
369
            lfi->valid |= APR_FINFO_NAME;
 
370
        }
 
371
 
 
372
        return OK;
 
373
    }
 
374
 
 
375
    /* OPT_SYM_OWNER only works if we can get the owner of
 
376
     * both the file and symlink.  First fill in a missing
 
377
     * owner of the symlink, then get the info of the target.
 
378
     */
 
379
    if (!(lfi->valid & APR_FINFO_OWNER)) {
 
380
        if ((res = apr_stat(&fi, d,
 
381
                            lfi->valid | APR_FINFO_LINK | APR_FINFO_OWNER, p))
 
382
            != APR_SUCCESS) {
 
383
            return HTTP_FORBIDDEN;
 
384
        }
 
385
    }
 
386
 
 
387
    if ((res = apr_stat(&fi, d, lfi->valid & ~(APR_FINFO_NAME), p))
 
388
        != APR_SUCCESS) {
 
389
        return HTTP_FORBIDDEN;
 
390
    }
 
391
 
 
392
    if (apr_uid_compare(fi.user, lfi->user) != APR_SUCCESS) {
 
393
        return HTTP_FORBIDDEN;
 
394
    }
 
395
 
 
396
    /* Give back the target */
 
397
    memcpy(lfi, &fi, sizeof(fi));
 
398
    if (savename) {
 
399
        lfi->name = savename;
 
400
        lfi->valid |= APR_FINFO_NAME;
 
401
    }
 
402
 
 
403
    return OK;
 
404
}
 
405
 
 
406
 
 
407
/*
 
408
 * As we walk the directory configuration, the merged config won't
 
409
 * be 'rooted' to a specific vhost until the very end of the merge.
 
410
 *
 
411
 * We need a very fast mini-merge to a real, vhost-rooted merge
 
412
 * of core.opts and core.override, the only options tested within
 
413
 * directory_walk itself.
 
414
 *
 
415
 * See core.c::merge_core_dir_configs() for explanation.
 
416
 */
 
417
 
 
418
typedef struct core_opts_t {
 
419
        allow_options_t opts;
 
420
        allow_options_t add;
 
421
        allow_options_t remove;
 
422
        overrides_t override;
 
423
        overrides_t override_opts;
 
424
} core_opts_t;
 
425
 
 
426
static void core_opts_merge(const ap_conf_vector_t *sec, core_opts_t *opts)
 
427
{
 
428
    core_dir_config *this_dir = ap_get_module_config(sec, &core_module);
 
429
 
 
430
    if (!this_dir) {
 
431
        return;
 
432
    }
 
433
 
 
434
    if (this_dir->opts & OPT_UNSET) {
 
435
        opts->add = (opts->add & ~this_dir->opts_remove)
 
436
                   | this_dir->opts_add;
 
437
        opts->remove = (opts->remove & ~this_dir->opts_add)
 
438
                      | this_dir->opts_remove;
 
439
        opts->opts = (opts->opts & ~opts->remove) | opts->add;
 
440
    }
 
441
    else {
 
442
        opts->opts = this_dir->opts;
 
443
        opts->add = this_dir->opts_add;
 
444
        opts->remove = this_dir->opts_remove;
 
445
    }
 
446
 
 
447
    if (!(this_dir->override & OR_UNSET)) {
 
448
        opts->override = this_dir->override;
 
449
        opts->override_opts = this_dir->override_opts;
 
450
    }
 
451
}
 
452
 
 
453
 
 
454
/*****************************************************************
 
455
 *
 
456
 * Getting and checking directory configuration.  Also checks the
 
457
 * FollowSymlinks and FollowSymOwner stuff, since this is really the
 
458
 * only place that can happen (barring a new mid_dir_walk callout).
 
459
 *
 
460
 * We can't do it as an access_checker module function which gets
 
461
 * called with the final per_dir_config, since we could have a directory
 
462
 * with FollowSymLinks disabled, which contains a symlink to another
 
463
 * with a .htaccess file which turns FollowSymLinks back on --- and
 
464
 * access in such a case must be denied.  So, whatever it is that
 
465
 * checks FollowSymLinks needs to know the state of the options as
 
466
 * they change, all the way down.
 
467
 */
 
468
 
 
469
AP_DECLARE(int) ap_directory_walk(request_rec *r)
 
470
{
 
471
    ap_conf_vector_t *now_merged = NULL;
 
472
    core_server_config *sconf = ap_get_module_config(r->server->module_config,
 
473
                                                     &core_module);
 
474
    ap_conf_vector_t **sec_ent = (ap_conf_vector_t **) sconf->sec_dir->elts;
 
475
    int num_sec = sconf->sec_dir->nelts;
 
476
    walk_cache_t *cache;
 
477
    char *entry_dir;
 
478
    apr_status_t rv;
 
479
 
 
480
    /* XXX: Better (faster) tests needed!!!
 
481
     *
 
482
     * "OK" as a response to a real problem is not _OK_, but to allow broken
 
483
     * modules to proceed, we will permit the not-a-path filename to pass the
 
484
     * following two tests.  This behavior may be revoked in future versions
 
485
     * of Apache.  We still must catch it later if it's heading for the core
 
486
     * handler.  Leave INFO notes here for module debugging.
 
487
     */
 
488
    if (r->filename == NULL) {
 
489
        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
 
490
                      "Module bug?  Request filename is missing for URI %s",
 
491
                      r->uri);
 
492
       return OK;
 
493
    }
 
494
 
 
495
    /* Canonicalize the file path without resolving filename case or aliases
 
496
     * so we can begin by checking the cache for a recent directory walk.
 
497
     * This call will ensure we have an absolute path in the same pass.
 
498
     */
 
499
    if ((rv = apr_filepath_merge(&entry_dir, NULL, r->filename,
 
500
                                 APR_FILEPATH_NOTRELATIVE, r->pool))
 
501
                  != APR_SUCCESS) {
 
502
        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
 
503
                      "Module bug?  Request filename path %s is invalid or "
 
504
                      "or not absolute for uri %s",
 
505
                      r->filename, r->uri);
 
506
        return OK;
 
507
    }
 
508
 
 
509
    /* XXX Notice that this forces path_info to be canonical.  That might
 
510
     * not be desired by all apps.  However, some of those same apps likely
 
511
     * have significant security holes.
 
512
     */
 
513
    r->filename = entry_dir;
 
514
 
 
515
    cache = prep_walk_cache(AP_NOTE_DIRECTORY_WALK, r);
 
516
 
 
517
    /* If this is not a dirent subrequest with a preconstructed
 
518
     * r->finfo value, then we can simply stat the filename to
 
519
     * save burning mega-cycles with unneeded stats - if this is
 
520
     * an exact file match.  We don't care about failure... we
 
521
     * will stat by component failing this meager attempt.
 
522
     *
 
523
     * It would be nice to distinguish APR_ENOENT from other
 
524
     * types of failure, such as APR_ENOTDIR.  We can do something
 
525
     * with APR_ENOENT, knowing that the path is good.
 
526
     */
 
527
    if (!r->finfo.filetype || r->finfo.filetype == APR_LNK) {
 
528
        rv = apr_stat(&r->finfo, r->filename, APR_FINFO_MIN, r->pool);
 
529
 
 
530
        /* some OSs will return APR_SUCCESS/APR_REG if we stat
 
531
         * a regular file but we have '/' at the end of the name;
 
532
         *
 
533
         * other OSs will return APR_ENOTDIR for that situation;
 
534
         *
 
535
         * handle it the same everywhere by simulating a failure
 
536
         * if it looks like a directory but really isn't
 
537
         *
 
538
         * Also reset if the stat failed, just for safety.
 
539
         */
 
540
        if ((rv != APR_SUCCESS) ||
 
541
            (r->finfo.filetype &&
 
542
             (r->finfo.filetype != APR_DIR) &&
 
543
             (r->filename[strlen(r->filename) - 1] == '/'))) {
 
544
             r->finfo.filetype = 0; /* forget what we learned */
 
545
        }
 
546
    }
 
547
 
 
548
    if (r->finfo.filetype == APR_REG) {
 
549
        entry_dir = ap_make_dirstr_parent(r->pool, entry_dir);
 
550
    }
 
551
    else if (r->filename[strlen(r->filename) - 1] != '/') {
 
552
        entry_dir = apr_pstrcat(r->pool, r->filename, "/", NULL);
 
553
    }
 
554
 
 
555
    /* If we have a file already matches the path of r->filename,
 
556
     * and the vhost's list of directory sections hasn't changed,
 
557
     * we can skip rewalking the directory_walk entries.
 
558
     */
 
559
    if (cache->cached
 
560
        && ((r->finfo.filetype == APR_REG)
 
561
            || ((r->finfo.filetype == APR_DIR)
 
562
                && (!r->path_info || !*r->path_info)))
 
563
        && (cache->dir_conf_tested == sec_ent)
 
564
        && (strcmp(entry_dir, cache->cached) == 0)) {
 
565
        /* Well this looks really familiar!  If our end-result (per_dir_result)
 
566
         * didn't change, we have absolutely nothing to do :)
 
567
         * Otherwise (as is the case with most dir_merged/file_merged requests)
 
568
         * we must merge our dir_conf_merged onto this new r->per_dir_config.
 
569
         */
 
570
        if (r->per_dir_config == cache->per_dir_result) {
 
571
            return OK;
 
572
        }
 
573
 
 
574
        if (r->per_dir_config == cache->dir_conf_merged) {
 
575
            r->per_dir_config = cache->per_dir_result;
 
576
            return OK;
 
577
        }
 
578
 
 
579
        if (cache->walked->nelts) {
 
580
            now_merged = ((walk_walked_t*)cache->walked->elts)
 
581
                [cache->walked->nelts - 1].merged;
 
582
        }
 
583
    }
 
584
    else {
 
585
        /* We start now_merged from NULL since we want to build
 
586
         * a locations list that can be merged to any vhost.
 
587
         */
 
588
        int sec_idx;
 
589
        int matches = cache->walked->nelts;
 
590
        walk_walked_t *last_walk = (walk_walked_t*)cache->walked->elts;
 
591
        core_dir_config *this_dir;
 
592
        core_opts_t opts;
 
593
        apr_finfo_t thisinfo;
 
594
        char *save_path_info;
 
595
        apr_size_t buflen;
 
596
        char *buf;
 
597
        unsigned int seg, startseg;
 
598
 
 
599
        /* Invariant: from the first time filename_len is set until
 
600
         * it goes out of scope, filename_len==strlen(r->filename)
 
601
         */
 
602
        apr_size_t filename_len;
 
603
#ifdef CASE_BLIND_FILESYSTEM
 
604
        apr_size_t canonical_len;
 
605
#endif
 
606
 
 
607
        /*
 
608
         * We must play our own mini-merge game here, for the few
 
609
         * running dir_config values we care about within dir_walk.
 
610
         * We didn't start the merge from r->per_dir_config, so we
 
611
         * accumulate opts and override as we merge, from the globals.
 
612
         */
 
613
        this_dir = ap_get_module_config(r->per_dir_config, &core_module);
 
614
        opts.opts = this_dir->opts;
 
615
        opts.add = this_dir->opts_add;
 
616
        opts.remove = this_dir->opts_remove;
 
617
        opts.override = this_dir->override;
 
618
 
 
619
        /* Set aside path_info to merge back onto path_info later.
 
620
         * If r->filename is a directory, we must remerge the path_info,
 
621
         * before we continue!  [Directories cannot, by defintion, have
 
622
         * path info.  Either the next segment is not-found, or a file.]
 
623
         *
 
624
         * r->path_info tracks the unconsumed source path.
 
625
         * r->filename  tracks the path as we process it
 
626
         */
 
627
        if ((r->finfo.filetype == APR_DIR) && r->path_info && *r->path_info)
 
628
        {
 
629
            if ((rv = apr_filepath_merge(&r->path_info, r->filename,
 
630
                                         r->path_info,
 
631
                                         APR_FILEPATH_NOTABOVEROOT, r->pool))
 
632
                != APR_SUCCESS) {
 
633
                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
 
634
                              "dir_walk error, path_info %s is not relative "
 
635
                              "to the filename path %s for uri %s",
 
636
                              r->path_info, r->filename, r->uri);
 
637
                return HTTP_INTERNAL_SERVER_ERROR;
 
638
            }
 
639
 
 
640
            save_path_info = NULL;
 
641
        }
 
642
        else {
 
643
            save_path_info = r->path_info;
 
644
            r->path_info = r->filename;
 
645
        }
 
646
 
 
647
#ifdef CASE_BLIND_FILESYSTEM
 
648
 
 
649
        canonical_len = 0;
 
650
        while (r->canonical_filename && r->canonical_filename[canonical_len]
 
651
               && (r->canonical_filename[canonical_len]
 
652
                   == r->path_info[canonical_len])) {
 
653
             ++canonical_len;
 
654
        }
 
655
 
 
656
        while (canonical_len
 
657
               && ((r->canonical_filename[canonical_len - 1] != '/'
 
658
                   && r->canonical_filename[canonical_len - 1])
 
659
                   || (r->path_info[canonical_len - 1] != '/'
 
660
                       && r->path_info[canonical_len - 1]))) {
 
661
            --canonical_len;
 
662
        }
 
663
 
 
664
        /*
 
665
         * Now build r->filename component by component, starting
 
666
         * with the root (on Unix, simply "/").  We will make a huge
 
667
         * assumption here for efficiency, that any canonical path
 
668
         * already given included a canonical root.
 
669
         */
 
670
        rv = apr_filepath_root((const char **)&r->filename,
 
671
                               (const char **)&r->path_info,
 
672
                               canonical_len ? 0 : APR_FILEPATH_TRUENAME,
 
673
                               r->pool);
 
674
        filename_len = strlen(r->filename);
 
675
 
 
676
        /*
 
677
         * Bad assumption above?  If the root's length is longer
 
678
         * than the canonical length, then it cannot be trusted as
 
679
         * a truename.  So try again, this time more seriously.
 
680
         */
 
681
        if ((rv == APR_SUCCESS) && canonical_len
 
682
            && (filename_len > canonical_len)) {
 
683
            rv = apr_filepath_root((const char **)&r->filename,
 
684
                                   (const char **)&r->path_info,
 
685
                                   APR_FILEPATH_TRUENAME, r->pool);
 
686
            filename_len = strlen(r->filename);
 
687
            canonical_len = 0;
 
688
        }
 
689
 
 
690
#else /* ndef CASE_BLIND_FILESYSTEM, really this simple for Unix today; */
 
691
 
 
692
        rv = apr_filepath_root((const char **)&r->filename,
 
693
                               (const char **)&r->path_info,
 
694
                               0, r->pool);
 
695
        filename_len = strlen(r->filename);
 
696
 
 
697
#endif
 
698
 
 
699
        if (rv != APR_SUCCESS) {
 
700
            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
 
701
                          "dir_walk error, could not determine the root "
 
702
                          "path of filename %s%s for uri %s",
 
703
                          r->filename, r->path_info, r->uri);
 
704
            return HTTP_INTERNAL_SERVER_ERROR;
 
705
        }
 
706
 
 
707
        /* Working space for terminating null and an extra / is required.
 
708
         */
 
709
        buflen = filename_len + strlen(r->path_info) + 2;
 
710
        buf = apr_palloc(r->pool, buflen);
 
711
        memcpy(buf, r->filename, filename_len + 1);
 
712
        r->filename = buf;
 
713
        thisinfo.valid = APR_FINFO_TYPE;
 
714
        thisinfo.filetype = APR_DIR; /* It's the root, of course it's a dir */
 
715
 
 
716
        /*
 
717
         * seg keeps track of which segment we've copied.
 
718
         * sec_idx keeps track of which section we're on, since sections are
 
719
         *     ordered by number of segments. See core_reorder_directories
 
720
         * startseg tells us how many segments describe the root path
 
721
         *     e.g. the complete path "//host/foo/" to a UNC share (4)
 
722
         */
 
723
        startseg = seg = ap_count_dirs(r->filename);
 
724
        sec_idx = 0;
 
725
 
 
726
        /*
 
727
         * Go down the directory hierarchy.  Where we have to check for
 
728
         * symlinks, do so.  Where a .htaccess file has permission to
 
729
         * override anything, try to find one.
 
730
         */
 
731
        do {
 
732
            int res;
 
733
            char *seg_name;
 
734
            char *delim;
 
735
            int temp_slash=0;
 
736
 
 
737
            /* We have no trailing slash, but we sure would appreciate one.
 
738
             * However, we don't want to append a / our first time through.
 
739
             */
 
740
            if ((seg > startseg) && r->filename[filename_len-1] != '/') {
 
741
                r->filename[filename_len++] = '/';
 
742
                r->filename[filename_len] = 0;
 
743
                temp_slash=1;
 
744
            }
 
745
 
 
746
            /* Begin *this* level by looking for matching <Directory> sections
 
747
             * from the server config.
 
748
             */
 
749
            for (; sec_idx < num_sec; ++sec_idx) {
 
750
 
 
751
                ap_conf_vector_t *entry_config = sec_ent[sec_idx];
 
752
                core_dir_config *entry_core;
 
753
                entry_core = ap_get_module_config(entry_config, &core_module);
 
754
 
 
755
                /* No more possible matches for this many segments?
 
756
                 * We are done when we find relative/regex/longer components.
 
757
                 */
 
758
                if (entry_core->r || entry_core->d_components > seg) {
 
759
                    break;
 
760
                }
 
761
 
 
762
                /* We will never skip '0' element components, e.g. plain old
 
763
                 * <Directory >, and <Directory "/"> are classified as zero
 
764
                 * so that Win32/Netware/OS2 etc all pick them up.
 
765
                 * Otherwise, skip over the mismatches.
 
766
                 */
 
767
                if (entry_core->d_components
 
768
                    && ((entry_core->d_components < seg)
 
769
                     || (entry_core->d_is_fnmatch
 
770
                         ? (apr_fnmatch(entry_core->d, r->filename,
 
771
                                        APR_FNM_PATHNAME) != APR_SUCCESS)
 
772
                         : (strcmp(r->filename, entry_core->d) != 0)))) {
 
773
                    continue;
 
774
                }
 
775
 
 
776
                /* If we haven't continue'd above, we have a match.
 
777
                 *
 
778
                 * Calculate our full-context core opts & override.
 
779
                 */
 
780
                core_opts_merge(sec_ent[sec_idx], &opts);
 
781
 
 
782
                /* If we merged this same section last time, reuse it
 
783
                 */
 
784
                if (matches) {
 
785
                    if (last_walk->matched == sec_ent[sec_idx]) {
 
786
                        now_merged = last_walk->merged;
 
787
                        ++last_walk;
 
788
                        --matches;
 
789
                        continue;
 
790
                    }
 
791
 
 
792
                    /* We fell out of sync.  This is our own copy of walked,
 
793
                     * so truncate the remaining matches and reset remaining.
 
794
                     */
 
795
                    cache->walked->nelts -= matches;
 
796
                    matches = 0;
 
797
                }
 
798
 
 
799
                if (now_merged) {
 
800
                    now_merged = ap_merge_per_dir_configs(r->pool,
 
801
                                                          now_merged,
 
802
                                                          sec_ent[sec_idx]);
 
803
                }
 
804
                else {
 
805
                    now_merged = sec_ent[sec_idx];
 
806
                }
 
807
 
 
808
                last_walk = (walk_walked_t*)apr_array_push(cache->walked);
 
809
                last_walk->matched = sec_ent[sec_idx];
 
810
                last_walk->merged = now_merged;
 
811
            }
 
812
 
 
813
            /* If .htaccess files are enabled, check for one, provided we
 
814
             * have reached a real path.
 
815
             */
 
816
            do {  /* Not really a loop, just a break'able code block */
 
817
 
 
818
                ap_conf_vector_t *htaccess_conf = NULL;
 
819
 
 
820
                /* No htaccess in an incomplete root path,
 
821
                 * nor if it's disabled
 
822
                 */
 
823
                if (seg < startseg || !opts.override) {
 
824
                    break;
 
825
                }
 
826
 
 
827
                res = ap_parse_htaccess(&htaccess_conf, r, opts.override,
 
828
                                        opts.override_opts,
 
829
                                        apr_pstrdup(r->pool, r->filename),
 
830
                                        sconf->access_name);
 
831
                if (res) {
 
832
                    return res;
 
833
                }
 
834
 
 
835
                if (!htaccess_conf) {
 
836
                    break;
 
837
                }
 
838
 
 
839
                /* If we are still here, we found our htaccess.
 
840
                 *
 
841
                 * Calculate our full-context core opts & override.
 
842
                 */
 
843
                core_opts_merge(htaccess_conf, &opts);
 
844
 
 
845
                /* If we merged this same htaccess last time, reuse it...
 
846
                 * this wouldn't work except that we cache the htaccess
 
847
                 * sections for the lifetime of the request, so we match
 
848
                 * the same conf.  Good planning (no, pure luck ;)
 
849
                 */
 
850
                if (matches) {
 
851
                    if (last_walk->matched == htaccess_conf) {
 
852
                        now_merged = last_walk->merged;
 
853
                        ++last_walk;
 
854
                        --matches;
 
855
                        break;
 
856
                    }
 
857
 
 
858
                    /* We fell out of sync.  This is our own copy of walked,
 
859
                     * so truncate the remaining matches and reset
 
860
                     * remaining.
 
861
                     */
 
862
                    cache->walked->nelts -= matches;
 
863
                    matches = 0;
 
864
                }
 
865
 
 
866
                if (now_merged) {
 
867
                    now_merged = ap_merge_per_dir_configs(r->pool,
 
868
                                                          now_merged,
 
869
                                                          htaccess_conf);
 
870
                }
 
871
                else {
 
872
                    now_merged = htaccess_conf;
 
873
                }
 
874
 
 
875
                last_walk = (walk_walked_t*)apr_array_push(cache->walked);
 
876
                last_walk->matched = htaccess_conf;
 
877
                last_walk->merged = now_merged;
 
878
 
 
879
            } while (0); /* Only one htaccess, not a real loop */
 
880
 
 
881
            /* That temporary trailing slash was useful, now drop it.
 
882
             */
 
883
            if (temp_slash) {
 
884
                r->filename[--filename_len] = '\0';
 
885
            }
 
886
 
 
887
            /* Time for all good things to come to an end?
 
888
             */
 
889
            if (!r->path_info || !*r->path_info) {
 
890
                break;
 
891
            }
 
892
 
 
893
            /* Now it's time for the next segment...
 
894
             * We will assume the next element is an end node, and fix it up
 
895
             * below as necessary...
 
896
             */
 
897
 
 
898
            seg_name = r->filename + filename_len;
 
899
            delim = strchr(r->path_info + (*r->path_info == '/' ? 1 : 0), '/');
 
900
            if (delim) {
 
901
                size_t path_info_len = delim - r->path_info;
 
902
                *delim = '\0';
 
903
                memcpy(seg_name, r->path_info, path_info_len + 1);
 
904
                filename_len += path_info_len;
 
905
                r->path_info = delim;
 
906
                *delim = '/';
 
907
            }
 
908
            else {
 
909
                size_t path_info_len = strlen(r->path_info);
 
910
                memcpy(seg_name, r->path_info, path_info_len + 1);
 
911
                filename_len += path_info_len;
 
912
                r->path_info += path_info_len;
 
913
            }
 
914
            if (*seg_name == '/')
 
915
                ++seg_name;
 
916
 
 
917
            /* If nothing remained but a '/' string, we are finished
 
918
             * XXX: NO WE ARE NOT!!!  Now process this puppy!!! */
 
919
            if (!*seg_name) {
 
920
                break;
 
921
            }
 
922
 
 
923
            /* First optimization;
 
924
             * If...we knew r->filename was a file, and
 
925
             * if...we have strict (case-sensitive) filenames, or
 
926
             *      we know the canonical_filename matches to _this_ name, and
 
927
             * if...we have allowed symlinks
 
928
             * skip the lstat and dummy up an APR_DIR value for thisinfo.
 
929
             */
 
930
            if (r->finfo.filetype
 
931
#ifdef CASE_BLIND_FILESYSTEM
 
932
                && (filename_len <= canonical_len)
 
933
#endif
 
934
                && ((opts.opts & (OPT_SYM_OWNER | OPT_SYM_LINKS)) == OPT_SYM_LINKS))
 
935
            {
 
936
 
 
937
                thisinfo.filetype = APR_DIR;
 
938
                ++seg;
 
939
                continue;
 
940
            }
 
941
 
 
942
            /* We choose apr_stat with flag APR_FINFO_LINK here, rather that
 
943
             * plain apr_stat, so that we capture this path object rather than
 
944
             * its target.  We will replace the info with our target's info
 
945
             * below.  We especially want the name of this 'link' object, not
 
946
             * the name of its target, if we are fixing the filename
 
947
             * case/resolving aliases.
 
948
             */
 
949
            rv = apr_stat(&thisinfo, r->filename,
 
950
                          APR_FINFO_MIN | APR_FINFO_NAME | APR_FINFO_LINK,
 
951
                          r->pool);
 
952
 
 
953
            if (APR_STATUS_IS_ENOENT(rv)) {
 
954
                /* Nothing?  That could be nice.  But our directory
 
955
                 * walk is done.
 
956
                 */
 
957
                thisinfo.filetype = APR_NOFILE;
 
958
                break;
 
959
            }
 
960
            else if (APR_STATUS_IS_EACCES(rv)) {
 
961
                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
 
962
                              "access to %s denied", r->uri);
 
963
                return r->status = HTTP_FORBIDDEN;
 
964
            }
 
965
            else if ((rv != APR_SUCCESS && rv != APR_INCOMPLETE)
 
966
                     || !(thisinfo.valid & APR_FINFO_TYPE)) {
 
967
                /* If we hit ENOTDIR, we must have over-optimized, deny
 
968
                 * rather than assume not found.
 
969
                 */
 
970
                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
 
971
                              "access to %s failed", r->uri);
 
972
                return r->status = HTTP_FORBIDDEN;
 
973
            }
 
974
 
 
975
            /* Fix up the path now if we have a name, and they don't agree
 
976
             */
 
977
            if ((thisinfo.valid & APR_FINFO_NAME)
 
978
                && strcmp(seg_name, thisinfo.name)) {
 
979
                /* TODO: provide users an option that an internal/external
 
980
                 * redirect is required here?  We need to walk the URI and
 
981
                 * filename in tandem to properly correlate these.
 
982
                 */
 
983
                strcpy(seg_name, thisinfo.name);
 
984
                filename_len = strlen(r->filename);
 
985
            }
 
986
 
 
987
            if (thisinfo.filetype == APR_LNK) {
 
988
                /* Is this a possibly acceptable symlink?
 
989
                 */
 
990
                if ((res = resolve_symlink(r->filename, &thisinfo,
 
991
                                           opts.opts, r->pool)) != OK) {
 
992
                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
 
993
                                  "Symbolic link not allowed "
 
994
                                  "or link target not accessible: %s",
 
995
                                  r->filename);
 
996
                    return r->status = res;
 
997
                }
 
998
            }
 
999
 
 
1000
            /* Ok, we are done with the link's info, test the real target
 
1001
             */
 
1002
            if (thisinfo.filetype == APR_REG ||
 
1003
                thisinfo.filetype == APR_NOFILE) {
 
1004
                /* That was fun, nothing left for us here
 
1005
                 */
 
1006
                break;
 
1007
            }
 
1008
            else if (thisinfo.filetype != APR_DIR) {
 
1009
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
 
1010
                              "Forbidden: %s doesn't point to "
 
1011
                              "a file or directory",
 
1012
                              r->filename);
 
1013
                return r->status = HTTP_FORBIDDEN;
 
1014
            }
 
1015
 
 
1016
            ++seg;
 
1017
        } while (thisinfo.filetype == APR_DIR);
 
1018
 
 
1019
        /* If we have _not_ optimized, this is the time to recover
 
1020
         * the final stat result.
 
1021
         */
 
1022
        if (!r->finfo.filetype || r->finfo.filetype == APR_LNK) {
 
1023
            r->finfo = thisinfo;
 
1024
        }
 
1025
 
 
1026
        /* Now splice the saved path_info back onto any new path_info
 
1027
         */
 
1028
        if (save_path_info) {
 
1029
            if (r->path_info && *r->path_info) {
 
1030
                r->path_info = ap_make_full_path(r->pool, r->path_info,
 
1031
                                                 save_path_info);
 
1032
            }
 
1033
            else {
 
1034
                r->path_info = save_path_info;
 
1035
            }
 
1036
        }
 
1037
 
 
1038
        /*
 
1039
         * Now we'll deal with the regexes, note we pick up sec_idx
 
1040
         * where we left off (we gave up after we hit entry_core->r)
 
1041
         */
 
1042
        for (; sec_idx < num_sec; ++sec_idx) {
 
1043
 
 
1044
            core_dir_config *entry_core;
 
1045
            entry_core = ap_get_module_config(sec_ent[sec_idx], &core_module);
 
1046
 
 
1047
            if (!entry_core->r) {
 
1048
                continue;
 
1049
            }
 
1050
 
 
1051
            if (ap_regexec(entry_core->r, r->filename, 0, NULL, AP_REG_NOTEOL)) {
 
1052
                continue;
 
1053
            }
 
1054
 
 
1055
            /* If we haven't already continue'd above, we have a match.
 
1056
             *
 
1057
             * Calculate our full-context core opts & override.
 
1058
             */
 
1059
            core_opts_merge(sec_ent[sec_idx], &opts);
 
1060
 
 
1061
            /* If we merged this same section last time, reuse it
 
1062
             */
 
1063
            if (matches) {
 
1064
                if (last_walk->matched == sec_ent[sec_idx]) {
 
1065
                    now_merged = last_walk->merged;
 
1066
                    ++last_walk;
 
1067
                    --matches;
 
1068
                    continue;
 
1069
                }
 
1070
 
 
1071
                /* We fell out of sync.  This is our own copy of walked,
 
1072
                 * so truncate the remaining matches and reset remaining.
 
1073
                 */
 
1074
                cache->walked->nelts -= matches;
 
1075
                matches = 0;
 
1076
            }
 
1077
 
 
1078
            if (now_merged) {
 
1079
                now_merged = ap_merge_per_dir_configs(r->pool,
 
1080
                                                      now_merged,
 
1081
                                                      sec_ent[sec_idx]);
 
1082
            }
 
1083
            else {
 
1084
                now_merged = sec_ent[sec_idx];
 
1085
            }
 
1086
 
 
1087
            last_walk = (walk_walked_t*)apr_array_push(cache->walked);
 
1088
            last_walk->matched = sec_ent[sec_idx];
 
1089
            last_walk->merged = now_merged;
 
1090
        }
 
1091
 
 
1092
        /* Whoops - everything matched in sequence, but the original walk
 
1093
         * found some additional matches.  Truncate them.
 
1094
         */
 
1095
        if (matches) {
 
1096
            cache->walked->nelts -= matches;
 
1097
        }
 
1098
    }
 
1099
 
 
1100
/* It seems this shouldn't be needed anymore.  We translated the
 
1101
 x symlink above into a real resource, and should have died up there.
 
1102
 x Even if we keep this, it needs more thought (maybe an r->file_is_symlink)
 
1103
 x perhaps it should actually happen in file_walk, so we catch more
 
1104
 x obscure cases in autoindex subrequests, etc.
 
1105
 x
 
1106
 x    * Symlink permissions are determined by the parent.  If the request is
 
1107
 x    * for a directory then applying the symlink test here would use the
 
1108
 x    * permissions of the directory as opposed to its parent.  Consider a
 
1109
 x    * symlink pointing to a dir with a .htaccess disallowing symlinks.  If
 
1110
 x    * you access /symlink (or /symlink/) you would get a 403 without this
 
1111
 x    * APR_DIR test.  But if you accessed /symlink/index.html, for example,
 
1112
 x    * you would *not* get the 403.
 
1113
 x
 
1114
 x   if (r->finfo.filetype != APR_DIR
 
1115
 x       && (res = resolve_symlink(r->filename, r->info, ap_allow_options(r),
 
1116
 x                                 r->pool))) {
 
1117
 x       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
 
1118
 x                     "Symbolic link not allowed: %s", r->filename);
 
1119
 x       return res;
 
1120
 x   }
 
1121
 */
 
1122
 
 
1123
    /* Save future sub-requestors much angst in processing
 
1124
     * this subrequest.  If dir_walk couldn't canonicalize
 
1125
     * the file path, nothing can.
 
1126
     */
 
1127
    r->canonical_filename = r->filename;
 
1128
 
 
1129
    if (r->finfo.filetype == APR_DIR) {
 
1130
        cache->cached = r->filename;
 
1131
    }
 
1132
    else {
 
1133
        cache->cached = ap_make_dirstr_parent(r->pool, r->filename);
 
1134
    }
 
1135
 
 
1136
    cache->dir_conf_tested = sec_ent;
 
1137
    cache->dir_conf_merged = r->per_dir_config;
 
1138
 
 
1139
    /* Merge our cache->dir_conf_merged construct with the r->per_dir_configs,
 
1140
     * and note the end result to (potentially) skip this step next time.
 
1141
     */
 
1142
    if (now_merged) {
 
1143
        r->per_dir_config = ap_merge_per_dir_configs(r->pool,
 
1144
                                                     r->per_dir_config,
 
1145
                                                     now_merged);
 
1146
    }
 
1147
    cache->per_dir_result = r->per_dir_config;
 
1148
 
 
1149
    return OK;
 
1150
}
 
1151
 
 
1152
 
 
1153
AP_DECLARE(int) ap_location_walk(request_rec *r)
 
1154
{
 
1155
    ap_conf_vector_t *now_merged = NULL;
 
1156
    core_server_config *sconf = ap_get_module_config(r->server->module_config,
 
1157
                                                     &core_module);
 
1158
    ap_conf_vector_t **sec_ent = (ap_conf_vector_t **)sconf->sec_url->elts;
 
1159
    int num_sec = sconf->sec_url->nelts;
 
1160
    walk_cache_t *cache;
 
1161
    const char *entry_uri;
 
1162
 
 
1163
    /* No tricks here, there are no <Locations > to parse in this vhost.
 
1164
     * We won't destroy the cache, just in case _this_ redirect is later
 
1165
     * redirected again to a vhost with <Location > blocks to optimize.
 
1166
     */
 
1167
    if (!num_sec) {
 
1168
        return OK;
 
1169
    }
 
1170
 
 
1171
    cache = prep_walk_cache(AP_NOTE_LOCATION_WALK, r);
 
1172
 
 
1173
    /* Location and LocationMatch differ on their behaviour w.r.t. multiple
 
1174
     * slashes.  Location matches multiple slashes with a single slash,
 
1175
     * LocationMatch doesn't.  An exception, for backwards brokenness is
 
1176
     * absoluteURIs... in which case neither match multiple slashes.
 
1177
     */
 
1178
    if (r->uri[0] != '/') {
 
1179
        entry_uri = r->uri;
 
1180
    }
 
1181
    else {
 
1182
        char *uri = apr_pstrdup(r->pool, r->uri);
 
1183
        ap_no2slash(uri);
 
1184
        entry_uri = uri;
 
1185
    }
 
1186
 
 
1187
    /* If we have an cache->cached location that matches r->uri,
 
1188
     * and the vhost's list of locations hasn't changed, we can skip
 
1189
     * rewalking the location_walk entries.
 
1190
     */
 
1191
    if (cache->cached
 
1192
        && (cache->dir_conf_tested == sec_ent)
 
1193
        && (strcmp(entry_uri, cache->cached) == 0)) {
 
1194
        /* Well this looks really familiar!  If our end-result (per_dir_result)
 
1195
         * didn't change, we have absolutely nothing to do :)
 
1196
         * Otherwise (as is the case with most dir_merged/file_merged requests)
 
1197
         * we must merge our dir_conf_merged onto this new r->per_dir_config.
 
1198
         */
 
1199
        if (r->per_dir_config == cache->per_dir_result) {
 
1200
            return OK;
 
1201
        }
 
1202
 
 
1203
        if (r->per_dir_config == cache->dir_conf_merged) {
 
1204
            r->per_dir_config = cache->per_dir_result;
 
1205
            return OK;
 
1206
        }
 
1207
 
 
1208
        if (cache->walked->nelts) {
 
1209
            now_merged = ((walk_walked_t*)cache->walked->elts)
 
1210
                                            [cache->walked->nelts - 1].merged;
 
1211
        }
 
1212
    }
 
1213
    else {
 
1214
        /* We start now_merged from NULL since we want to build
 
1215
         * a locations list that can be merged to any vhost.
 
1216
         */
 
1217
        int len, sec_idx;
 
1218
        int matches = cache->walked->nelts;
 
1219
        walk_walked_t *last_walk = (walk_walked_t*)cache->walked->elts;
 
1220
        cache->cached = entry_uri;
 
1221
 
 
1222
        /* Go through the location entries, and check for matches.
 
1223
         * We apply the directive sections in given order, we should
 
1224
         * really try them with the most general first.
 
1225
         */
 
1226
        for (sec_idx = 0; sec_idx < num_sec; ++sec_idx) {
 
1227
 
 
1228
            core_dir_config *entry_core;
 
1229
            entry_core = ap_get_module_config(sec_ent[sec_idx], &core_module);
 
1230
 
 
1231
            /* ### const strlen can be optimized in location config parsing */
 
1232
            len = strlen(entry_core->d);
 
1233
 
 
1234
            /* Test the regex, fnmatch or string as appropriate.
 
1235
             * If it's a strcmp, and the <Location > pattern was
 
1236
             * not slash terminated, then this uri must be slash
 
1237
             * terminated (or at the end of the string) to match.
 
1238
             */
 
1239
            if (entry_core->r
 
1240
                ? ap_regexec(entry_core->r, r->uri, 0, NULL, 0)
 
1241
                : (entry_core->d_is_fnmatch
 
1242
                   ? apr_fnmatch(entry_core->d, cache->cached, APR_FNM_PATHNAME)
 
1243
                   : (strncmp(entry_core->d, cache->cached, len)
 
1244
                      || (entry_core->d[len - 1] != '/'
 
1245
                          && cache->cached[len] != '/'
 
1246
                          && cache->cached[len] != '\0')))) {
 
1247
                continue;
 
1248
            }
 
1249
 
 
1250
            /* If we merged this same section last time, reuse it
 
1251
             */
 
1252
            if (matches) {
 
1253
                if (last_walk->matched == sec_ent[sec_idx]) {
 
1254
                    now_merged = last_walk->merged;
 
1255
                    ++last_walk;
 
1256
                    --matches;
 
1257
                    continue;
 
1258
                }
 
1259
 
 
1260
                /* We fell out of sync.  This is our own copy of walked,
 
1261
                 * so truncate the remaining matches and reset remaining.
 
1262
                 */
 
1263
                cache->walked->nelts -= matches;
 
1264
                matches = 0;
 
1265
            }
 
1266
 
 
1267
            if (now_merged) {
 
1268
                now_merged = ap_merge_per_dir_configs(r->pool,
 
1269
                                                      now_merged,
 
1270
                                                      sec_ent[sec_idx]);
 
1271
            }
 
1272
            else {
 
1273
                now_merged = sec_ent[sec_idx];
 
1274
            }
 
1275
 
 
1276
            last_walk = (walk_walked_t*)apr_array_push(cache->walked);
 
1277
            last_walk->matched = sec_ent[sec_idx];
 
1278
            last_walk->merged = now_merged;
 
1279
        }
 
1280
 
 
1281
        /* Whoops - everything matched in sequence, but the original walk
 
1282
         * found some additional matches.  Truncate them.
 
1283
         */
 
1284
        if (matches) {
 
1285
            cache->walked->nelts -= matches;
 
1286
        }
 
1287
    }
 
1288
 
 
1289
    cache->dir_conf_tested = sec_ent;
 
1290
    cache->dir_conf_merged = r->per_dir_config;
 
1291
 
 
1292
    /* Merge our cache->dir_conf_merged construct with the r->per_dir_configs,
 
1293
     * and note the end result to (potentially) skip this step next time.
 
1294
     */
 
1295
    if (now_merged) {
 
1296
        r->per_dir_config = ap_merge_per_dir_configs(r->pool,
 
1297
                                                     r->per_dir_config,
 
1298
                                                     now_merged);
 
1299
    }
 
1300
    cache->per_dir_result = r->per_dir_config;
 
1301
 
 
1302
    return OK;
 
1303
}
 
1304
 
 
1305
AP_DECLARE(int) ap_file_walk(request_rec *r)
 
1306
{
 
1307
    ap_conf_vector_t *now_merged = NULL;
 
1308
    core_dir_config *dconf = ap_get_module_config(r->per_dir_config,
 
1309
                                                  &core_module);
 
1310
    ap_conf_vector_t **sec_ent = (ap_conf_vector_t **)dconf->sec_file->elts;
 
1311
    int num_sec = dconf->sec_file->nelts;
 
1312
    walk_cache_t *cache;
 
1313
    const char *test_file;
 
1314
 
 
1315
    /* To allow broken modules to proceed, we allow missing filenames to pass.
 
1316
     * We will catch it later if it's heading for the core handler.
 
1317
     * directory_walk already posted an INFO note for module debugging.
 
1318
     */
 
1319
    if (r->filename == NULL) {
 
1320
        return OK;
 
1321
    }
 
1322
 
 
1323
    cache = prep_walk_cache(AP_NOTE_FILE_WALK, r);
 
1324
 
 
1325
    /* No tricks here, there are just no <Files > to parse in this context.
 
1326
     * We won't destroy the cache, just in case _this_ redirect is later
 
1327
     * redirected again to a context containing the same or similar <Files >.
 
1328
     */
 
1329
    if (!num_sec) {
 
1330
        return OK;
 
1331
    }
 
1332
 
 
1333
    /* Get the basename .. and copy for the cache just
 
1334
     * in case r->filename is munged by another module
 
1335
     */
 
1336
    test_file = strrchr(r->filename, '/');
 
1337
    if (test_file == NULL) {
 
1338
        test_file = apr_pstrdup(r->pool, r->filename);
 
1339
    }
 
1340
    else {
 
1341
        test_file = apr_pstrdup(r->pool, ++test_file);
 
1342
    }
 
1343
 
 
1344
    /* If we have an cache->cached file name that matches test_file,
 
1345
     * and the directory's list of file sections hasn't changed, we
 
1346
     * can skip rewalking the file_walk entries.
 
1347
     */
 
1348
    if (cache->cached
 
1349
        && (cache->dir_conf_tested == sec_ent)
 
1350
        && (strcmp(test_file, cache->cached) == 0)) {
 
1351
        /* Well this looks really familiar!  If our end-result (per_dir_result)
 
1352
         * didn't change, we have absolutely nothing to do :)
 
1353
         * Otherwise (as is the case with most dir_merged requests)
 
1354
         * we must merge our dir_conf_merged onto this new r->per_dir_config.
 
1355
         */
 
1356
        if (r->per_dir_config == cache->per_dir_result) {
 
1357
            return OK;
 
1358
        }
 
1359
 
 
1360
        if (r->per_dir_config == cache->dir_conf_merged) {
 
1361
            r->per_dir_config = cache->per_dir_result;
 
1362
            return OK;
 
1363
        }
 
1364
 
 
1365
        if (cache->walked->nelts) {
 
1366
            now_merged = ((walk_walked_t*)cache->walked->elts)
 
1367
                [cache->walked->nelts - 1].merged;
 
1368
        }
 
1369
    }
 
1370
    else {
 
1371
        /* We start now_merged from NULL since we want to build
 
1372
         * a file section list that can be merged to any dir_walk.
 
1373
         */
 
1374
        int sec_idx;
 
1375
        int matches = cache->walked->nelts;
 
1376
        walk_walked_t *last_walk = (walk_walked_t*)cache->walked->elts;
 
1377
        cache->cached = test_file;
 
1378
 
 
1379
        /* Go through the location entries, and check for matches.
 
1380
         * We apply the directive sections in given order, we should
 
1381
         * really try them with the most general first.
 
1382
         */
 
1383
        for (sec_idx = 0; sec_idx < num_sec; ++sec_idx) {
 
1384
 
 
1385
            core_dir_config *entry_core;
 
1386
            entry_core = ap_get_module_config(sec_ent[sec_idx], &core_module);
 
1387
 
 
1388
            if (entry_core->r
 
1389
                ? ap_regexec(entry_core->r, cache->cached , 0, NULL, 0)
 
1390
                : (entry_core->d_is_fnmatch
 
1391
                   ? apr_fnmatch(entry_core->d, cache->cached, APR_FNM_PATHNAME)
 
1392
                   : strcmp(entry_core->d, cache->cached))) {
 
1393
                continue;
 
1394
            }
 
1395
 
 
1396
            /* If we merged this same section last time, reuse it
 
1397
             */
 
1398
            if (matches) {
 
1399
                if (last_walk->matched == sec_ent[sec_idx]) {
 
1400
                    now_merged = last_walk->merged;
 
1401
                    ++last_walk;
 
1402
                    --matches;
 
1403
                    continue;
 
1404
                }
 
1405
 
 
1406
                /* We fell out of sync.  This is our own copy of walked,
 
1407
                 * so truncate the remaining matches and reset remaining.
 
1408
                 */
 
1409
                cache->walked->nelts -= matches;
 
1410
                matches = 0;
 
1411
            }
 
1412
 
 
1413
            if (now_merged) {
 
1414
                now_merged = ap_merge_per_dir_configs(r->pool,
 
1415
                                                      now_merged,
 
1416
                                                      sec_ent[sec_idx]);
 
1417
            }
 
1418
            else {
 
1419
                now_merged = sec_ent[sec_idx];
 
1420
            }
 
1421
 
 
1422
            last_walk = (walk_walked_t*)apr_array_push(cache->walked);
 
1423
            last_walk->matched = sec_ent[sec_idx];
 
1424
            last_walk->merged = now_merged;
 
1425
        }
 
1426
 
 
1427
        /* Whoops - everything matched in sequence, but the original walk
 
1428
         * found some additional matches.  Truncate them.
 
1429
         */
 
1430
        if (matches) {
 
1431
            cache->walked->nelts -= matches;
 
1432
        }
 
1433
    }
 
1434
 
 
1435
    cache->dir_conf_tested = sec_ent;
 
1436
    cache->dir_conf_merged = r->per_dir_config;
 
1437
 
 
1438
    /* Merge our cache->dir_conf_merged construct with the r->per_dir_configs,
 
1439
     * and note the end result to (potentially) skip this step next time.
 
1440
     */
 
1441
    if (now_merged) {
 
1442
        r->per_dir_config = ap_merge_per_dir_configs(r->pool,
 
1443
                                                     r->per_dir_config,
 
1444
                                                     now_merged);
 
1445
    }
 
1446
    cache->per_dir_result = r->per_dir_config;
 
1447
 
 
1448
    return OK;
 
1449
}
 
1450
 
 
1451
/*****************************************************************
 
1452
 *
 
1453
 * The sub_request mechanism.
 
1454
 *
 
1455
 * Fns to look up a relative URI from, e.g., a map file or SSI document.
 
1456
 * These do all access checks, etc., but don't actually run the transaction
 
1457
 * ... use run_sub_req below for that.  Also, be sure to use destroy_sub_req
 
1458
 * as appropriate if you're likely to be creating more than a few of these.
 
1459
 * (An early Apache version didn't destroy the sub_reqs used in directory
 
1460
 * indexing.  The result, when indexing a directory with 800-odd files in
 
1461
 * it, was massively excessive storage allocation).
 
1462
 *
 
1463
 * Note more manipulation of protocol-specific vars in the request
 
1464
 * structure...
 
1465
 */
 
1466
 
 
1467
static request_rec *make_sub_request(const request_rec *r,
 
1468
                                     ap_filter_t *next_filter)
 
1469
{
 
1470
    apr_pool_t *rrp;
 
1471
    request_rec *rnew;
 
1472
 
 
1473
    apr_pool_create(&rrp, r->pool);
 
1474
    apr_pool_tag(rrp, "subrequest");
 
1475
    rnew = apr_pcalloc(rrp, sizeof(request_rec));
 
1476
    rnew->pool = rrp;
 
1477
 
 
1478
    rnew->hostname       = r->hostname;
 
1479
    rnew->request_time   = r->request_time;
 
1480
    rnew->connection     = r->connection;
 
1481
    rnew->server         = r->server;
 
1482
 
 
1483
    rnew->request_config = ap_create_request_config(rnew->pool);
 
1484
 
 
1485
    /* Start a clean config from this subrequest's vhost.  Optimization in
 
1486
     * Location/File/Dir walks from the parent request assure that if the
 
1487
     * config blocks of the subrequest match the parent request, no merges
 
1488
     * will actually occur (and generally a minimal number of merges are
 
1489
     * required, even if the parent and subrequest aren't quite identical.)
 
1490
     */
 
1491
    rnew->per_dir_config = r->server->lookup_defaults;
 
1492
 
 
1493
    rnew->htaccess = r->htaccess;
 
1494
    rnew->allowed_methods = ap_make_method_list(rnew->pool, 2);
 
1495
 
 
1496
    /* make a copy of the allowed-methods list */
 
1497
    ap_copy_method_list(rnew->allowed_methods, r->allowed_methods);
 
1498
 
 
1499
    /* start with the same set of output filters */
 
1500
    if (next_filter) {
 
1501
        /* while there are no input filters for a subrequest, we will
 
1502
         * try to insert some, so if we don't have valid data, the code
 
1503
         * will seg fault.
 
1504
         */
 
1505
        rnew->input_filters = r->input_filters;
 
1506
        rnew->proto_input_filters = r->proto_input_filters;
 
1507
        rnew->output_filters = next_filter;
 
1508
        rnew->proto_output_filters = r->proto_output_filters;
 
1509
        ap_add_output_filter_handle(ap_subreq_core_filter_handle,
 
1510
                                    NULL, rnew, rnew->connection);
 
1511
    }
 
1512
    else {
 
1513
        /* If NULL - we are expecting to be internal_fast_redirect'ed
 
1514
         * to this subrequest - or this request will never be invoked.
 
1515
         * Ignore the original request filter stack entirely, and
 
1516
         * drill the input and output stacks back to the connection.
 
1517
         */
 
1518
        rnew->proto_input_filters = r->proto_input_filters;
 
1519
        rnew->proto_output_filters = r->proto_output_filters;
 
1520
 
 
1521
        rnew->input_filters = r->proto_input_filters;
 
1522
        rnew->output_filters = r->proto_output_filters;
 
1523
    }
 
1524
 
 
1525
    /* no input filters for a subrequest */
 
1526
 
 
1527
    ap_set_sub_req_protocol(rnew, r);
 
1528
 
 
1529
    /* We have to run this after we fill in sub req vars,
 
1530
     * or the r->main pointer won't be setup
 
1531
     */
 
1532
    ap_run_create_request(rnew);
 
1533
 
 
1534
    /* Begin by presuming any module can make its own path_info assumptions,
 
1535
     * until some module interjects and changes the value.
 
1536
     */
 
1537
    rnew->used_path_info = AP_REQ_DEFAULT_PATH_INFO;
 
1538
 
 
1539
    return rnew;
 
1540
}
 
1541
 
 
1542
AP_CORE_DECLARE_NONSTD(apr_status_t) ap_sub_req_output_filter(ap_filter_t *f,
 
1543
                                                              apr_bucket_brigade *bb)
 
1544
{
 
1545
    apr_bucket *e = APR_BRIGADE_LAST(bb);
 
1546
 
 
1547
    if (APR_BUCKET_IS_EOS(e)) {
 
1548
        apr_bucket_delete(e);
 
1549
    }
 
1550
 
 
1551
    if (!APR_BRIGADE_EMPTY(bb)) {
 
1552
        return ap_pass_brigade(f->next, bb);
 
1553
    }
 
1554
 
 
1555
    return APR_SUCCESS;
 
1556
}
 
1557
 
 
1558
 
 
1559
AP_DECLARE(int) ap_some_auth_required(request_rec *r)
 
1560
{
 
1561
    /* Is there a require line configured for the type of *this* req? */
 
1562
 
 
1563
    const apr_array_header_t *reqs_arr = ap_requires(r);
 
1564
    require_line *reqs;
 
1565
    int i;
 
1566
 
 
1567
    if (!reqs_arr) {
 
1568
        return 0;
 
1569
    }
 
1570
 
 
1571
    reqs = (require_line *) reqs_arr->elts;
 
1572
 
 
1573
    for (i = 0; i < reqs_arr->nelts; ++i) {
 
1574
        if (reqs[i].method_mask & (AP_METHOD_BIT << r->method_number)) {
 
1575
            return 1;
 
1576
        }
 
1577
    }
 
1578
 
 
1579
    return 0;
 
1580
}
 
1581
 
 
1582
 
 
1583
AP_DECLARE(request_rec *) ap_sub_req_method_uri(const char *method,
 
1584
                                                const char *new_uri,
 
1585
                                                const request_rec *r,
 
1586
                                                ap_filter_t *next_filter)
 
1587
{
 
1588
    request_rec *rnew;
 
1589
    /* Initialise res, to avoid a gcc warning */
 
1590
    int res = HTTP_INTERNAL_SERVER_ERROR;
 
1591
    char *udir;
 
1592
 
 
1593
    rnew = make_sub_request(r, next_filter);
 
1594
 
 
1595
    /* would be nicer to pass "method" to ap_set_sub_req_protocol */
 
1596
    rnew->method = method;
 
1597
    rnew->method_number = ap_method_number_of(method);
 
1598
 
 
1599
    if (new_uri[0] == '/') {
 
1600
        ap_parse_uri(rnew, new_uri);
 
1601
    }
 
1602
    else {
 
1603
        udir = ap_make_dirstr_parent(rnew->pool, r->uri);
 
1604
        udir = ap_escape_uri(rnew->pool, udir);    /* re-escape it */
 
1605
        ap_parse_uri(rnew, ap_make_full_path(rnew->pool, udir, new_uri));
 
1606
    }
 
1607
 
 
1608
    /* We cannot return NULL without violating the API. So just turn this
 
1609
     * subrequest into a 500 to indicate the failure. */
 
1610
    if (ap_is_recursion_limit_exceeded(r)) {
 
1611
        rnew->status = HTTP_INTERNAL_SERVER_ERROR;
 
1612
        return rnew;
 
1613
    }
 
1614
 
 
1615
    /* lookup_uri
 
1616
     * If the content can be served by the quick_handler, we can
 
1617
     * safely bypass request_internal processing.
 
1618
     *
 
1619
     * If next_filter is NULL we are expecting to be
 
1620
     * internal_fast_redirect'ed to the subrequest, or the subrequest will
 
1621
     * never be invoked. We need to make sure that the quickhandler is not
 
1622
     * invoked by any lookups. Since an internal_fast_redirect will always
 
1623
     * occur too late for the quickhandler to handle the request.
 
1624
     */
 
1625
    if (next_filter) {
 
1626
        res = ap_run_quick_handler(rnew, 1);
 
1627
    }
 
1628
 
 
1629
    if (next_filter == NULL || res != OK) {
 
1630
        if ((res = ap_process_request_internal(rnew))) {
 
1631
            rnew->status = res;
 
1632
        }
 
1633
    }
 
1634
 
 
1635
    return rnew;
 
1636
}
 
1637
 
 
1638
AP_DECLARE(request_rec *) ap_sub_req_lookup_uri(const char *new_uri,
 
1639
                                                const request_rec *r,
 
1640
                                                ap_filter_t *next_filter)
 
1641
{
 
1642
    return ap_sub_req_method_uri("GET", new_uri, r, next_filter);
 
1643
}
 
1644
 
 
1645
AP_DECLARE(request_rec *) ap_sub_req_lookup_dirent(const apr_finfo_t *dirent,
 
1646
                                                   const request_rec *r,
 
1647
                                                   int subtype,
 
1648
                                                   ap_filter_t *next_filter)
 
1649
{
 
1650
    request_rec *rnew;
 
1651
    int res;
 
1652
    char *fdir;
 
1653
    char *udir;
 
1654
 
 
1655
    rnew = make_sub_request(r, next_filter);
 
1656
 
 
1657
    /* Special case: we are looking at a relative lookup in the same directory.
 
1658
     * This is 100% safe, since dirent->name just came from the filesystem.
 
1659
     */
 
1660
    if (r->path_info && *r->path_info) {
 
1661
        /* strip path_info off the end of the uri to keep it in sync
 
1662
         * with r->filename, which has already been stripped by directory_walk,
 
1663
         * merge the dirent->name, and then, if the caller wants us to remerge
 
1664
         * the original path info, do so.  Note we never fix the path_info back
 
1665
         * to r->filename, since dir_walk would do so (but we don't expect it
 
1666
         * to happen in the usual cases)
 
1667
         */
 
1668
        udir = apr_pstrdup(rnew->pool, r->uri);
 
1669
        udir[ap_find_path_info(udir, r->path_info)] = '\0';
 
1670
        udir = ap_make_dirstr_parent(rnew->pool, udir);
 
1671
 
 
1672
        rnew->uri = ap_make_full_path(rnew->pool, udir, dirent->name);
 
1673
        if (subtype == AP_SUBREQ_MERGE_ARGS) {
 
1674
            rnew->uri = ap_make_full_path(rnew->pool, rnew->uri, r->path_info + 1);
 
1675
            rnew->path_info = apr_pstrdup(rnew->pool, r->path_info);
 
1676
        }
 
1677
        rnew->uri = ap_escape_uri(rnew->pool, rnew->uri);
 
1678
    }
 
1679
    else {
 
1680
        udir = ap_make_dirstr_parent(rnew->pool, r->uri);
 
1681
        rnew->uri = ap_escape_uri(rnew->pool, ap_make_full_path(rnew->pool,
 
1682
                                                                udir,
 
1683
                                                                dirent->name));
 
1684
    }
 
1685
 
 
1686
    fdir = ap_make_dirstr_parent(rnew->pool, r->filename);
 
1687
    rnew->filename = ap_make_full_path(rnew->pool, fdir, dirent->name);
 
1688
    if (r->canonical_filename == r->filename) {
 
1689
        rnew->canonical_filename = rnew->filename;
 
1690
    }
 
1691
 
 
1692
    /* XXX This is now less relevant; we will do a full location walk
 
1693
     * these days for this case.  Preserve the apr_stat results, and
 
1694
     * perhaps we also tag that symlinks were tested and/or found for
 
1695
     * r->filename.
 
1696
     */
 
1697
    rnew->per_dir_config = r->server->lookup_defaults;
 
1698
 
 
1699
    if ((dirent->valid & APR_FINFO_MIN) != APR_FINFO_MIN) {
 
1700
        /*
 
1701
         * apr_dir_read isn't very complete on this platform, so
 
1702
         * we need another apr_stat (with or without APR_FINFO_LINK
 
1703
         * depending on whether we allow all symlinks here.)  If this
 
1704
         * is an APR_LNK that resolves to an APR_DIR, then we will rerun
 
1705
         * everything anyways... this should be safe.
 
1706
         */
 
1707
        apr_status_t rv;
 
1708
        if (ap_allow_options(rnew) & OPT_SYM_LINKS) {
 
1709
            if (((rv = apr_stat(&rnew->finfo, rnew->filename,
 
1710
                                APR_FINFO_MIN, rnew->pool)) != APR_SUCCESS)
 
1711
                && (rv != APR_INCOMPLETE)) {
 
1712
                rnew->finfo.filetype = 0;
 
1713
            }
 
1714
        }
 
1715
        else {
 
1716
            if (((rv = apr_stat(&rnew->finfo, rnew->filename,
 
1717
                                APR_FINFO_LINK | APR_FINFO_MIN,
 
1718
                                rnew->pool)) != APR_SUCCESS)
 
1719
                && (rv != APR_INCOMPLETE)) {
 
1720
                rnew->finfo.filetype = 0;
 
1721
            }
 
1722
        }
 
1723
    }
 
1724
    else {
 
1725
        memcpy(&rnew->finfo, dirent, sizeof(apr_finfo_t));
 
1726
    }
 
1727
 
 
1728
    if (rnew->finfo.filetype == APR_LNK) {
 
1729
        /*
 
1730
         * Resolve this symlink.  We should tie this back to dir_walk's cache
 
1731
         */
 
1732
        if ((res = resolve_symlink(rnew->filename, &rnew->finfo,
 
1733
                                   ap_allow_options(rnew), rnew->pool))
 
1734
            != OK) {
 
1735
            rnew->status = res;
 
1736
            return rnew;
 
1737
        }
 
1738
    }
 
1739
 
 
1740
    if (rnew->finfo.filetype == APR_DIR) {
 
1741
        /* ap_make_full_path overallocated the buffers
 
1742
         * by one character to help us out here.
 
1743
         */
 
1744
        strcpy(rnew->filename + strlen(rnew->filename), "/");
 
1745
        if (!rnew->path_info || !*rnew->path_info) {
 
1746
            strcpy(rnew->uri  + strlen(rnew->uri ), "/");
 
1747
        }
 
1748
    }
 
1749
 
 
1750
    /* fill in parsed_uri values
 
1751
     */
 
1752
    if (r->args && *r->args && (subtype == AP_SUBREQ_MERGE_ARGS)) {
 
1753
        ap_parse_uri(rnew, apr_pstrcat(r->pool, rnew->uri, "?",
 
1754
                                       r->args, NULL));
 
1755
    }
 
1756
    else {
 
1757
        ap_parse_uri(rnew, rnew->uri);
 
1758
    }
 
1759
 
 
1760
    /* We cannot return NULL without violating the API. So just turn this
 
1761
     * subrequest into a 500. */
 
1762
    if (ap_is_recursion_limit_exceeded(r)) {
 
1763
        rnew->status = HTTP_INTERNAL_SERVER_ERROR;
 
1764
        return rnew;
 
1765
    }
 
1766
 
 
1767
    if ((res = ap_process_request_internal(rnew))) {
 
1768
        rnew->status = res;
 
1769
    }
 
1770
 
 
1771
    return rnew;
 
1772
}
 
1773
 
 
1774
AP_DECLARE(request_rec *) ap_sub_req_lookup_file(const char *new_file,
 
1775
                                                 const request_rec *r,
 
1776
                                                 ap_filter_t *next_filter)
 
1777
{
 
1778
    request_rec *rnew;
 
1779
    int res;
 
1780
    char *fdir;
 
1781
    apr_size_t fdirlen;
 
1782
 
 
1783
    rnew = make_sub_request(r, next_filter);
 
1784
 
 
1785
    fdir = ap_make_dirstr_parent(rnew->pool, r->filename);
 
1786
    fdirlen = strlen(fdir);
 
1787
 
 
1788
    /* Translate r->filename, if it was canonical, it stays canonical
 
1789
     */
 
1790
    if (r->canonical_filename == r->filename) {
 
1791
        rnew->canonical_filename = (char*)(1);
 
1792
    }
 
1793
 
 
1794
    if (apr_filepath_merge(&rnew->filename, fdir, new_file,
 
1795
                           APR_FILEPATH_TRUENAME, rnew->pool) != APR_SUCCESS) {
 
1796
        rnew->status = HTTP_FORBIDDEN;
 
1797
        return rnew;
 
1798
    }
 
1799
 
 
1800
    if (rnew->canonical_filename) {
 
1801
        rnew->canonical_filename = rnew->filename;
 
1802
    }
 
1803
 
 
1804
    /*
 
1805
     * Check for a special case... if there are no '/' characters in new_file
 
1806
     * at all, and the path was the same, then we are looking at a relative
 
1807
     * lookup in the same directory.  Fixup the URI to match.
 
1808
     */
 
1809
 
 
1810
    if (strncmp(rnew->filename, fdir, fdirlen) == 0
 
1811
        && rnew->filename[fdirlen]
 
1812
        && ap_strchr_c(rnew->filename + fdirlen, '/') == NULL) {
 
1813
        apr_status_t rv;
 
1814
        if (ap_allow_options(rnew) & OPT_SYM_LINKS) {
 
1815
            if (((rv = apr_stat(&rnew->finfo, rnew->filename,
 
1816
                                APR_FINFO_MIN, rnew->pool)) != APR_SUCCESS)
 
1817
                && (rv != APR_INCOMPLETE)) {
 
1818
                rnew->finfo.filetype = 0;
 
1819
            }
 
1820
        }
 
1821
        else {
 
1822
            if (((rv = apr_stat(&rnew->finfo, rnew->filename,
 
1823
                                APR_FINFO_LINK | APR_FINFO_MIN,
 
1824
                                rnew->pool)) != APR_SUCCESS)
 
1825
                && (rv != APR_INCOMPLETE)) {
 
1826
                rnew->finfo.filetype = 0;
 
1827
            }
 
1828
        }
 
1829
 
 
1830
        if (r->uri && *r->uri) {
 
1831
            char *udir = ap_make_dirstr_parent(rnew->pool, r->uri);
 
1832
            rnew->uri = ap_make_full_path(rnew->pool, udir,
 
1833
                                          rnew->filename + fdirlen);
 
1834
            ap_parse_uri(rnew, rnew->uri);    /* fill in parsed_uri values */
 
1835
        }
 
1836
        else {
 
1837
            ap_parse_uri(rnew, new_file);        /* fill in parsed_uri values */
 
1838
            rnew->uri = apr_pstrdup(rnew->pool, "");
 
1839
        }
 
1840
    }
 
1841
    else {
 
1842
        /* XXX: @@@: What should be done with the parsed_uri values?
 
1843
         * We would be better off stripping down to the 'common' elements
 
1844
         * of the path, then reassembling the URI as best as we can.
 
1845
         */
 
1846
        ap_parse_uri(rnew, new_file);        /* fill in parsed_uri values */
 
1847
        /*
 
1848
         * XXX: this should be set properly like it is in the same-dir case
 
1849
         * but it's actually sometimes to impossible to do it... because the
 
1850
         * file may not have a uri associated with it -djg
 
1851
         */
 
1852
        rnew->uri = apr_pstrdup(rnew->pool, "");
 
1853
    }
 
1854
 
 
1855
    /* We cannot return NULL without violating the API. So just turn this
 
1856
     * subrequest into a 500. */
 
1857
    if (ap_is_recursion_limit_exceeded(r)) {
 
1858
        rnew->status = HTTP_INTERNAL_SERVER_ERROR;
 
1859
        return rnew;
 
1860
    }
 
1861
 
 
1862
    if ((res = ap_process_request_internal(rnew))) {
 
1863
        rnew->status = res;
 
1864
    }
 
1865
 
 
1866
    return rnew;
 
1867
}
 
1868
 
 
1869
AP_DECLARE(int) ap_run_sub_req(request_rec *r)
 
1870
{
 
1871
    int retval = DECLINED;
 
1872
    /* Run the quick handler if the subrequest is not a dirent or file
 
1873
     * subrequest
 
1874
     */
 
1875
    if (!(r->filename && r->finfo.filetype)) {
 
1876
        retval = ap_run_quick_handler(r, 0);
 
1877
    }
 
1878
    if (retval != OK) {
 
1879
        retval = ap_invoke_handler(r);
 
1880
        if (retval == DONE) {
 
1881
            retval = OK;
 
1882
        }
 
1883
    }
 
1884
    ap_finalize_sub_req_protocol(r);
 
1885
    return retval;
 
1886
}
 
1887
 
 
1888
AP_DECLARE(void) ap_destroy_sub_req(request_rec *r)
 
1889
{
 
1890
    /* Reclaim the space */
 
1891
    apr_pool_destroy(r->pool);
 
1892
}
 
1893
 
 
1894
/*
 
1895
 * Function to set the r->mtime field to the specified value if it's later
 
1896
 * than what's already there.
 
1897
 */
 
1898
AP_DECLARE(void) ap_update_mtime(request_rec *r, apr_time_t dependency_mtime)
 
1899
{
 
1900
    if (r->mtime < dependency_mtime) {
 
1901
        r->mtime = dependency_mtime;
 
1902
    }
 
1903
}
 
1904
 
 
1905
/*
 
1906
 * Is it the initial main request, which we only get *once* per HTTP request?
 
1907
 */
 
1908
AP_DECLARE(int) ap_is_initial_req(request_rec *r)
 
1909
{
 
1910
    return (r->main == NULL)       /* otherwise, this is a sub-request */
 
1911
           && (r->prev == NULL);   /* otherwise, this is an internal redirect */
 
1912
}