bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / modules / mappers / mod_dir.c
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  * mod_dir.c: handle default index files, and trailing-/ redirects
19  */
20
21 #include "apr_strings.h"
22 #include "ap_config.h"
23 #include "httpd.h"
24 #include "http_config.h"
25 #include "http_core.h"
26 #include "http_request.h"
27 #include "http_protocol.h"
28 #include "http_log.h"
29 #include "http_main.h"
30 #include "util_script.h"
31
32 module AP_MODULE_DECLARE_DATA dir_module;
33
34 typedef enum {
35     SLASH_OFF = 0,
36     SLASH_ON,
37     SLASH_UNSET
38 } slash_cfg;
39
40 typedef struct dir_config_struct {
41     apr_array_header_t *index_names;
42     slash_cfg do_slash;
43 } dir_config_rec;
44
45 #define DIR_CMD_PERMS OR_INDEXES
46
47 static const char *add_index(cmd_parms *cmd, void *dummy, const char *arg)
48 {
49     dir_config_rec *d = dummy;
50
51     if (!d->index_names) {
52         d->index_names = apr_array_make(cmd->pool, 2, sizeof(char *));
53     }
54     *(const char **)apr_array_push(d->index_names) = arg;
55     return NULL;
56 }
57
58 static const char *configure_slash(cmd_parms *cmd, void *d_, int arg)
59 {
60     dir_config_rec *d = d_;
61
62     d->do_slash = arg ? SLASH_ON : SLASH_OFF;
63     return NULL;
64 }
65
66 static const command_rec dir_cmds[] =
67 {
68     AP_INIT_ITERATE("DirectoryIndex", add_index, NULL, DIR_CMD_PERMS,
69                     "a list of file names"),
70     AP_INIT_FLAG("DirectorySlash", configure_slash, NULL, DIR_CMD_PERMS,
71                  "On or Off"),
72     {NULL}
73 };
74
75 static void *create_dir_config(apr_pool_t *p, char *dummy)
76 {
77     dir_config_rec *new = apr_pcalloc(p, sizeof(dir_config_rec));
78
79     new->index_names = NULL;
80     new->do_slash = SLASH_UNSET;
81     return (void *) new;
82 }
83
84 static void *merge_dir_configs(apr_pool_t *p, void *basev, void *addv)
85 {
86     dir_config_rec *new = apr_pcalloc(p, sizeof(dir_config_rec));
87     dir_config_rec *base = (dir_config_rec *)basev;
88     dir_config_rec *add = (dir_config_rec *)addv;
89
90     new->index_names = add->index_names ? add->index_names : base->index_names;
91     new->do_slash =
92         (add->do_slash == SLASH_UNSET) ? base->do_slash : add->do_slash;
93     return new;
94 }
95
96 static int fixup_dir(request_rec *r)
97 {
98     dir_config_rec *d;
99     char *dummy_ptr[1];
100     char **names_ptr;
101     int num_names;
102     int error_notfound = 0;
103
104     /* only handle requests against directories */
105     if (r->finfo.filetype != APR_DIR) {
106         return DECLINED;
107     }
108     
109     /* In case mod_mime wasn't present, and no handler was assigned. */
110     if (!r->handler) {
111         r->handler = DIR_MAGIC_TYPE;
112     }
113
114     /* Never tolerate path_info on dir requests */
115     if (r->path_info && *r->path_info) {
116         return DECLINED;
117     }
118
119     d = (dir_config_rec *)ap_get_module_config(r->per_dir_config,
120                                                &dir_module);
121
122     /* Redirect requests that are not '/' terminated */
123     if (r->uri[0] == '\0' || r->uri[strlen(r->uri) - 1] != '/') 
124     {
125         char *ifile;
126
127         if (!d->do_slash) {
128             return DECLINED;
129         }
130
131         /* Only redirect non-get requests if we have no note to warn
132          * that this browser cannot handle redirs on non-GET requests 
133          * (such as Microsoft's WebFolders). 
134          */
135         if ((r->method_number != M_GET)
136                 && apr_table_get(r->subprocess_env, "redirect-carefully")) {
137             return DECLINED;
138         }
139
140         if (r->args != NULL) {
141             ifile = apr_pstrcat(r->pool, ap_escape_uri(r->pool, r->uri),
142                                 "/", "?", r->args, NULL);
143         }
144         else {
145             ifile = apr_pstrcat(r->pool, ap_escape_uri(r->pool, r->uri),
146                                 "/", NULL);
147         }
148
149         apr_table_setn(r->headers_out, "Location",
150                        ap_construct_url(r->pool, ifile, r));
151         return HTTP_MOVED_PERMANENTLY;
152     }
153
154     if (strcmp(r->handler, DIR_MAGIC_TYPE)) {
155         return DECLINED;
156     }
157
158     if (d->index_names) {
159         names_ptr = (char **)d->index_names->elts;
160         num_names = d->index_names->nelts;
161     }
162     else {
163         dummy_ptr[0] = AP_DEFAULT_INDEX;
164         names_ptr = dummy_ptr;
165         num_names = 1;
166     }
167
168     for (; num_names; ++names_ptr, --num_names) {
169         /* XXX: Is this name_ptr considered escaped yet, or not??? */
170         char *name_ptr = *names_ptr;
171         request_rec *rr;
172
173         /* Once upon a time args were handled _after_ the successful redirect.
174          * But that redirect might then _refuse_ the given r->args, creating
175          * a nasty tangle.  It seems safer to consider the r->args while we
176          * determine if name_ptr is our viable index, and therefore set them
177          * up correctly on redirect.
178          */
179         if (r->args != NULL) {
180             name_ptr = apr_pstrcat(r->pool, name_ptr, "?", r->args, NULL);
181         }
182
183         rr = ap_sub_req_lookup_uri(name_ptr, r, NULL);
184
185         /* XXX: (filetype == APR_REG) - we can't use a non-file index??? */
186         if (   rr->status == HTTP_OK
187             && (   (rr->handler && !strcmp(rr->handler, "proxy-server"))
188                 || rr->finfo.filetype == APR_REG)) {
189             ap_internal_fast_redirect(rr, r);
190             return OK;
191         }
192             
193         /* If the request returned a redirect, propagate it to the client */
194
195         if (ap_is_HTTP_REDIRECT(rr->status)
196             || (rr->status == HTTP_NOT_ACCEPTABLE && num_names == 1)
197             || (rr->status == HTTP_UNAUTHORIZED && num_names == 1)) {
198
199             apr_pool_join(r->pool, rr->pool);
200             error_notfound = rr->status;
201             r->notes = apr_table_overlay(r->pool, r->notes, rr->notes);
202             r->headers_out = apr_table_overlay(r->pool, r->headers_out,
203                                                rr->headers_out);
204             r->err_headers_out = apr_table_overlay(r->pool, r->err_headers_out,
205                                                    rr->err_headers_out);
206             return error_notfound;
207         }
208
209         /* If the request returned something other than 404 (or 200),
210          * it means the module encountered some sort of problem. To be
211          * secure, we should return the error, rather than allow autoindex
212          * to create a (possibly unsafe) directory index.
213          *
214          * So we store the error, and if none of the listed files
215          * exist, we return the last error response we got, instead
216          * of a directory listing.
217          */
218         if (rr->status && rr->status != HTTP_NOT_FOUND
219                 && rr->status != HTTP_OK) {
220             error_notfound = rr->status;
221         }
222
223         ap_destroy_sub_req(rr);
224     }
225
226     if (error_notfound) {
227         return error_notfound;
228     }
229
230     /* nothing for us to do, pass on through */
231     return DECLINED;
232 }
233
234 static void register_hooks(apr_pool_t *p)
235 {
236     ap_hook_fixups(fixup_dir,NULL,NULL,APR_HOOK_LAST);
237 }
238
239 module AP_MODULE_DECLARE_DATA dir_module = {
240     STANDARD20_MODULE_STUFF,
241     create_dir_config,          /* create per-directory config structure */
242     merge_dir_configs,          /* merge per-directory config structures */
243     NULL,                       /* create per-server config structure */
244     NULL,                       /* merge per-server config structures */
245     dir_cmds,                   /* command apr_table_t */
246     register_hooks              /* register hooks */
247 };