]> granicus.if.org Git - apache/blob - server/core.c
Move the POSIX reg* implementations into the ap_* namespace;
[apache] / server / core.c
1 /* Copyright 2001-2005 The Apache Software Foundation or its licensors, as
2  * applicable.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * 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 #include "apr.h"
18 #include "apr_strings.h"
19 #include "apr_lib.h"
20 #include "apr_fnmatch.h"
21 #include "apr_hash.h"
22 #include "apr_thread_proc.h"    /* for RLIMIT stuff */
23 #include "apr_hooks.h"
24
25 #define APR_WANT_IOVEC
26 #define APR_WANT_STRFUNC
27 #define APR_WANT_MEMFUNC
28 #include "apr_want.h"
29
30 #define CORE_PRIVATE
31 #include "ap_config.h"
32 #include "httpd.h"
33 #include "http_config.h"
34 #include "http_core.h"
35 #include "http_protocol.h" /* For index_of_response().  Grump. */
36 #include "http_request.h"
37 #include "http_vhost.h"
38 #include "http_main.h"     /* For the default_handler below... */
39 #include "http_log.h"
40 #include "util_md5.h"
41 #include "http_connection.h"
42 #include "apr_buckets.h"
43 #include "util_filter.h"
44 #include "util_ebcdic.h"
45 #include "mpm.h"
46 #include "mpm_common.h"
47 #include "scoreboard.h"
48 #include "mod_core.h"
49 #include "mod_proxy.h"
50 #include "ap_listen.h"
51
52 #include "mod_so.h" /* for ap_find_loaded_module_symbol */
53
54 /* LimitRequestBody handling */
55 #define AP_LIMIT_REQ_BODY_UNSET         ((apr_off_t) -1)
56 #define AP_DEFAULT_LIMIT_REQ_BODY       ((apr_off_t) 0)
57
58 /* LimitXMLRequestBody handling */
59 #define AP_LIMIT_UNSET                  ((long) -1)
60 #define AP_DEFAULT_LIMIT_XML_BODY       ((size_t)1000000)
61
62 #define AP_MIN_SENDFILE_BYTES           (256)
63
64 /* maximum include nesting level */
65 #ifndef AP_MAX_INCLUDE_DEPTH
66 #define AP_MAX_INCLUDE_DEPTH            (128)
67 #endif
68
69 APR_HOOK_STRUCT(
70     APR_HOOK_LINK(get_mgmt_items)
71 )
72
73 AP_IMPLEMENT_HOOK_RUN_ALL(int, get_mgmt_items,
74                           (apr_pool_t *p, const char *val, apr_hash_t *ht),
75                           (p, val, ht), OK, DECLINED)
76
77 /* Server core module... This module provides support for really basic
78  * server operations, including options and commands which control the
79  * operation of other modules.  Consider this the bureaucracy module.
80  *
81  * The core module also defines handlers, etc., do handle just enough
82  * to allow a server with the core module ONLY to actually serve documents
83  * (though it slaps DefaultType on all of 'em); this was useful in testing,
84  * but may not be worth preserving.
85  *
86  * This file could almost be mod_core.c, except for the stuff which affects
87  * the http_conf_globals.
88  */
89
90 /* Handles for core filters */
91 AP_DECLARE_DATA ap_filter_rec_t *ap_subreq_core_filter_handle;
92 AP_DECLARE_DATA ap_filter_rec_t *ap_core_output_filter_handle;
93 AP_DECLARE_DATA ap_filter_rec_t *ap_content_length_filter_handle;
94 AP_DECLARE_DATA ap_filter_rec_t *ap_net_time_filter_handle;
95 AP_DECLARE_DATA ap_filter_rec_t *ap_core_input_filter_handle;
96
97 /* magic pointer for ErrorDocument xxx "default" */
98 static char errordocument_default;
99
100 static void *create_core_dir_config(apr_pool_t *a, char *dir)
101 {
102     core_dir_config *conf;
103     int i;
104
105     conf = (core_dir_config *)apr_pcalloc(a, sizeof(core_dir_config));
106
107     /* conf->r and conf->d[_*] are initialized by dirsection() or left NULL */
108
109     conf->opts = dir ? OPT_UNSET : OPT_UNSET|OPT_ALL;
110     conf->opts_add = conf->opts_remove = OPT_NONE;
111     conf->override = dir ? OR_UNSET : OR_UNSET|OR_ALL;
112     conf->override_opts = OPT_UNSET | OPT_ALL | OPT_INCNOEXEC | OPT_SYM_OWNER
113                          | OPT_MULTI;
114
115     conf->content_md5 = 2;
116     conf->accept_path_info = 3;
117
118     conf->use_canonical_name = USE_CANONICAL_NAME_UNSET;
119
120     conf->hostname_lookups = HOSTNAME_LOOKUP_UNSET;
121     conf->satisfy = apr_palloc(a, sizeof(*conf->satisfy) * METHODS);
122     for (i = 0; i < METHODS; ++i) {
123         conf->satisfy[i] = SATISFY_NOSPEC;
124     }
125
126 #ifdef RLIMIT_CPU
127     conf->limit_cpu = NULL;
128 #endif
129 #if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
130     conf->limit_mem = NULL;
131 #endif
132 #ifdef RLIMIT_NPROC
133     conf->limit_nproc = NULL;
134 #endif
135
136     conf->limit_req_body = AP_LIMIT_REQ_BODY_UNSET;
137     conf->limit_xml_body = AP_LIMIT_UNSET;
138     conf->sec_file = apr_array_make(a, 2, sizeof(ap_conf_vector_t *));
139
140     conf->server_signature = srv_sig_unset;
141
142     conf->add_default_charset = ADD_DEFAULT_CHARSET_UNSET;
143     conf->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
144
145     /* Overriding all negotiation
146      */
147     conf->mime_type = NULL;
148     conf->handler = NULL;
149     conf->output_filters = NULL;
150     conf->input_filters = NULL;
151
152     /*
153      * Flag for use of inodes in ETags.
154      */
155     conf->etag_bits = ETAG_UNSET;
156     conf->etag_add = ETAG_UNSET;
157     conf->etag_remove = ETAG_UNSET;
158
159     conf->enable_mmap = ENABLE_MMAP_UNSET;
160     conf->enable_sendfile = ENABLE_SENDFILE_UNSET;
161     conf->allow_encoded_slashes = 0;
162
163     return (void *)conf;
164 }
165
166 /*
167  * Overlay one hash table of ct_output_filters onto another
168  */
169 static void *merge_ct_filters(apr_pool_t *p,
170                               const void *key,
171                               apr_ssize_t klen,
172                               const void *overlay_val,
173                               const void *base_val,
174                               const void *data)
175 {
176     ap_filter_rec_t *cur;
177     const ap_filter_rec_t *overlay_info = (const ap_filter_rec_t *)overlay_val;
178     const ap_filter_rec_t *base_info = (const ap_filter_rec_t *)base_val;
179
180     cur = NULL;
181
182     while (overlay_info) {
183         ap_filter_rec_t *new;
184
185         new = apr_pcalloc(p, sizeof(ap_filter_rec_t));
186         new->name = apr_pstrdup(p, overlay_info->name);
187         new->next = cur;
188         cur = new;
189         overlay_info = overlay_info->next;
190     }
191
192     while (base_info) {
193         ap_filter_rec_t *f;
194         int found = 0;
195
196         /* We can't have dups. */
197         f = cur;
198         while (f) {
199             if (!strcasecmp(base_info->name, f->name)) {
200                 found = 1;
201                 break;
202             }
203
204             f = f->next;
205         }
206
207         if (!found) {
208             f = apr_pcalloc(p, sizeof(ap_filter_rec_t));
209             f->name = apr_pstrdup(p, base_info->name);
210             f->next = cur;
211             cur = f;
212         }
213
214         base_info = base_info->next;
215     }
216
217     return cur;
218 }
219
220 static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv)
221 {
222     core_dir_config *base = (core_dir_config *)basev;
223     core_dir_config *new = (core_dir_config *)newv;
224     core_dir_config *conf;
225     int i;
226
227     /* Create this conf by duplicating the base, replacing elements
228      * (or creating copies for merging) where new-> values exist.
229      */
230     conf = (core_dir_config *)apr_palloc(a, sizeof(core_dir_config));
231     memcpy(conf, base, sizeof(core_dir_config));
232
233     conf->d = new->d;
234     conf->d_is_fnmatch = new->d_is_fnmatch;
235     conf->d_components = new->d_components;
236     conf->r = new->r;
237
238     if (new->opts & OPT_UNSET) {
239         /* there was no explicit setting of new->opts, so we merge
240          * preserve the invariant (opts_add & opts_remove) == 0
241          */
242         conf->opts_add = (conf->opts_add & ~new->opts_remove) | new->opts_add;
243         conf->opts_remove = (conf->opts_remove & ~new->opts_add)
244                             | new->opts_remove;
245         conf->opts = (conf->opts & ~conf->opts_remove) | conf->opts_add;
246         if ((base->opts & OPT_INCNOEXEC) && (new->opts & OPT_INCLUDES)) {
247             conf->opts = (conf->opts & ~OPT_INCNOEXEC) | OPT_INCLUDES;
248         }
249     }
250     else {
251         /* otherwise we just copy, because an explicit opts setting
252          * overrides all earlier +/- modifiers
253          */
254         conf->opts = new->opts;
255         conf->opts_add = new->opts_add;
256         conf->opts_remove = new->opts_remove;
257     }
258
259     if (!(new->override & OR_UNSET)) {
260         conf->override = new->override;
261     }
262
263     if (!(new->override_opts & OPT_UNSET)) {
264         conf->override_opts = new->override_opts;
265     }
266
267     if (new->ap_default_type) {
268         conf->ap_default_type = new->ap_default_type;
269     }
270
271     if (new->ap_auth_type) {
272         conf->ap_auth_type = new->ap_auth_type;
273     }
274
275     if (new->ap_auth_name) {
276         conf->ap_auth_name = new->ap_auth_name;
277     }
278
279     if (new->ap_requires) {
280         conf->ap_requires = new->ap_requires;
281     }
282
283     if (conf->response_code_strings == NULL) {
284         conf->response_code_strings = new->response_code_strings;
285     }
286     else if (new->response_code_strings != NULL) {
287         /* If we merge, the merge-result must have it's own array
288          */
289         conf->response_code_strings = apr_palloc(a,
290             sizeof(*conf->response_code_strings) * RESPONSE_CODES);
291         memcpy(conf->response_code_strings, base->response_code_strings,
292                sizeof(*conf->response_code_strings) * RESPONSE_CODES);
293
294         for (i = 0; i < RESPONSE_CODES; ++i) {
295             if (new->response_code_strings[i] != NULL) {
296                 conf->response_code_strings[i] = new->response_code_strings[i];
297             }
298         }
299     }
300     /* Otherwise we simply use the base->response_code_strings array
301      */
302
303     if (new->hostname_lookups != HOSTNAME_LOOKUP_UNSET) {
304         conf->hostname_lookups = new->hostname_lookups;
305     }
306
307     if ((new->content_md5 & 2) == 0) {
308         conf->content_md5 = new->content_md5;
309     }
310
311     if (new->accept_path_info != 3) {
312         conf->accept_path_info = new->accept_path_info;
313     }
314
315     if (new->use_canonical_name != USE_CANONICAL_NAME_UNSET) {
316         conf->use_canonical_name = new->use_canonical_name;
317     }
318
319 #ifdef RLIMIT_CPU
320     if (new->limit_cpu) {
321         conf->limit_cpu = new->limit_cpu;
322     }
323 #endif
324
325 #if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
326     if (new->limit_mem) {
327         conf->limit_mem = new->limit_mem;
328     }
329 #endif
330
331 #ifdef RLIMIT_NPROC
332     if (new->limit_nproc) {
333         conf->limit_nproc = new->limit_nproc;
334     }
335 #endif
336
337     if (new->limit_req_body != AP_LIMIT_REQ_BODY_UNSET) {
338         conf->limit_req_body = new->limit_req_body;
339     }
340
341     if (new->limit_xml_body != AP_LIMIT_UNSET)
342         conf->limit_xml_body = new->limit_xml_body;
343     else
344         conf->limit_xml_body = base->limit_xml_body;
345
346     if (!conf->sec_file) {
347         conf->sec_file = new->sec_file;
348     }
349     else if (new->sec_file) {
350         /* If we merge, the merge-result must have it's own array
351          */
352         conf->sec_file = apr_array_append(a, base->sec_file, new->sec_file);
353     }
354     /* Otherwise we simply use the base->sec_file array
355      */
356
357     /* use a separate ->satisfy[] array either way */
358     conf->satisfy = apr_palloc(a, sizeof(*conf->satisfy) * METHODS);
359     for (i = 0; i < METHODS; ++i) {
360         if (new->satisfy[i] != SATISFY_NOSPEC) {
361             conf->satisfy[i] = new->satisfy[i];
362         } else {
363             conf->satisfy[i] = base->satisfy[i];
364         }
365     }
366
367     if (new->server_signature != srv_sig_unset) {
368         conf->server_signature = new->server_signature;
369     }
370
371     if (new->add_default_charset != ADD_DEFAULT_CHARSET_UNSET) {
372         conf->add_default_charset = new->add_default_charset;
373         conf->add_default_charset_name = new->add_default_charset_name;
374     }
375
376     /* Overriding all negotiation
377      */
378     if (new->mime_type) {
379         conf->mime_type = new->mime_type;
380     }
381
382     if (new->handler) {
383         conf->handler = new->handler;
384     }
385
386     if (new->output_filters) {
387         conf->output_filters = new->output_filters;
388     }
389
390     if (new->input_filters) {
391         conf->input_filters = new->input_filters;
392     }
393
394     if (conf->ct_output_filters && new->ct_output_filters) {
395         conf->ct_output_filters = apr_hash_merge(a,
396                                                  new->ct_output_filters,
397                                                  conf->ct_output_filters,
398                                                  merge_ct_filters,
399                                                  NULL);
400     }
401     else if (new->ct_output_filters) {
402         conf->ct_output_filters = apr_hash_copy(a, new->ct_output_filters);
403     }
404     else if (conf->ct_output_filters) {
405         /* That memcpy above isn't enough. */
406         conf->ct_output_filters = apr_hash_copy(a, base->ct_output_filters);
407     }
408
409     /*
410      * Now merge the setting of the FileETag directive.
411      */
412     if (new->etag_bits == ETAG_UNSET) {
413         conf->etag_add =
414             (conf->etag_add & (~ new->etag_remove)) | new->etag_add;
415         conf->etag_remove =
416             (conf->opts_remove & (~ new->etag_add)) | new->etag_remove;
417         conf->etag_bits =
418             (conf->etag_bits & (~ conf->etag_remove)) | conf->etag_add;
419     }
420     else {
421         conf->etag_bits = new->etag_bits;
422         conf->etag_add = new->etag_add;
423         conf->etag_remove = new->etag_remove;
424     }
425
426     if (conf->etag_bits != ETAG_NONE) {
427         conf->etag_bits &= (~ ETAG_NONE);
428     }
429
430     if (new->enable_mmap != ENABLE_MMAP_UNSET) {
431         conf->enable_mmap = new->enable_mmap;
432     }
433
434     if (new->enable_sendfile != ENABLE_SENDFILE_UNSET) {
435         conf->enable_sendfile = new->enable_sendfile;
436     }
437
438     conf->allow_encoded_slashes = new->allow_encoded_slashes;
439     
440     return (void*)conf;
441 }
442
443 static void *create_core_server_config(apr_pool_t *a, server_rec *s)
444 {
445     core_server_config *conf;
446     int is_virtual = s->is_virtual;
447
448     conf = (core_server_config *)apr_pcalloc(a, sizeof(core_server_config));
449
450 #ifdef GPROF
451     conf->gprof_dir = NULL;
452 #endif
453
454     conf->access_name = is_virtual ? NULL : DEFAULT_ACCESS_FNAME;
455     conf->ap_document_root = is_virtual ? NULL : DOCUMENT_LOCATION;
456     conf->sec_dir = apr_array_make(a, 40, sizeof(ap_conf_vector_t *));
457     conf->sec_url = apr_array_make(a, 40, sizeof(ap_conf_vector_t *));
458
459     /* recursion stopper */
460     conf->redirect_limit = 0; /* 0 == unset */
461     conf->subreq_limit = 0;
462
463     return (void *)conf;
464 }
465
466 static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
467 {
468     core_server_config *base = (core_server_config *)basev;
469     core_server_config *virt = (core_server_config *)virtv;
470     core_server_config *conf;
471
472     conf = (core_server_config *)apr_palloc(p, sizeof(core_server_config));
473     memcpy(conf, virt, sizeof(core_server_config));
474
475     if (!conf->access_name) {
476         conf->access_name = base->access_name;
477     }
478
479     if (!conf->ap_document_root) {
480         conf->ap_document_root = base->ap_document_root;
481     }
482
483     conf->sec_dir = apr_array_append(p, base->sec_dir, virt->sec_dir);
484     conf->sec_url = apr_array_append(p, base->sec_url, virt->sec_url);
485
486     conf->redirect_limit = virt->redirect_limit
487                            ? virt->redirect_limit
488                            : base->redirect_limit;
489
490     conf->subreq_limit = virt->subreq_limit
491                          ? virt->subreq_limit
492                          : base->subreq_limit;
493
494     return conf;
495 }
496
497 /* Add per-directory configuration entry (for <directory> section);
498  * these are part of the core server config.
499  */
500
501 AP_CORE_DECLARE(void) ap_add_per_dir_conf(server_rec *s, void *dir_config)
502 {
503     core_server_config *sconf = ap_get_module_config(s->module_config,
504                                                      &core_module);
505     void **new_space = (void **)apr_array_push(sconf->sec_dir);
506
507     *new_space = dir_config;
508 }
509
510 AP_CORE_DECLARE(void) ap_add_per_url_conf(server_rec *s, void *url_config)
511 {
512     core_server_config *sconf = ap_get_module_config(s->module_config,
513                                                      &core_module);
514     void **new_space = (void **)apr_array_push(sconf->sec_url);
515
516     *new_space = url_config;
517 }
518
519 AP_CORE_DECLARE(void) ap_add_file_conf(core_dir_config *conf, void *url_config)
520 {
521     void **new_space = (void **)apr_array_push(conf->sec_file);
522
523     *new_space = url_config;
524 }
525
526 /* We need to do a stable sort, qsort isn't stable.  So to make it stable
527  * we'll be maintaining the original index into the list, and using it
528  * as the minor key during sorting.  The major key is the number of
529  * components (where the root component is zero).
530  */
531 struct reorder_sort_rec {
532     ap_conf_vector_t *elt;
533     int orig_index;
534 };
535
536 static int reorder_sorter(const void *va, const void *vb)
537 {
538     const struct reorder_sort_rec *a = va;
539     const struct reorder_sort_rec *b = vb;
540     core_dir_config *core_a;
541     core_dir_config *core_b;
542
543     core_a = ap_get_module_config(a->elt, &core_module);
544     core_b = ap_get_module_config(b->elt, &core_module);
545
546     /* a regex always sorts after a non-regex
547      */
548     if (!core_a->r && core_b->r) {
549         return -1;
550     }
551     else if (core_a->r && !core_b->r) {
552         return 1;
553     }
554
555     /* we always sort next by the number of components
556      */
557     if (core_a->d_components < core_b->d_components) {
558         return -1;
559     }
560     else if (core_a->d_components > core_b->d_components) {
561         return 1;
562     }
563
564     /* They have the same number of components, we now have to compare
565      * the minor key to maintain the original order (from the config.)
566      */
567     return a->orig_index - b->orig_index;
568 }
569
570 void ap_core_reorder_directories(apr_pool_t *p, server_rec *s)
571 {
572     core_server_config *sconf;
573     apr_array_header_t *sec_dir;
574     struct reorder_sort_rec *sortbin;
575     int nelts;
576     ap_conf_vector_t **elts;
577     int i;
578     apr_pool_t *tmp;
579
580     sconf = ap_get_module_config(s->module_config, &core_module);
581     sec_dir = sconf->sec_dir;
582     nelts = sec_dir->nelts;
583     elts = (ap_conf_vector_t **)sec_dir->elts;
584
585     if (!nelts) {
586         /* simple case of already being sorted... */
587         /* We're not checking this condition to be fast... we're checking
588          * it to avoid trying to palloc zero bytes, which can trigger some
589          * memory debuggers to barf
590          */
591         return;
592     }
593
594     /* we have to allocate tmp space to do a stable sort */
595     apr_pool_create(&tmp, p);
596     sortbin = apr_palloc(tmp, sec_dir->nelts * sizeof(*sortbin));
597     for (i = 0; i < nelts; ++i) {
598         sortbin[i].orig_index = i;
599         sortbin[i].elt = elts[i];
600     }
601
602     qsort(sortbin, nelts, sizeof(*sortbin), reorder_sorter);
603
604     /* and now copy back to the original array */
605     for (i = 0; i < nelts; ++i) {
606         elts[i] = sortbin[i].elt;
607     }
608
609     apr_pool_destroy(tmp);
610 }
611
612 /*****************************************************************
613  *
614  * There are some elements of the core config structures in which
615  * other modules have a legitimate interest (this is ugly, but necessary
616  * to preserve NCSA back-compatibility).  So, we have a bunch of accessors
617  * here...
618  */
619
620 AP_DECLARE(int) ap_allow_options(request_rec *r)
621 {
622     core_dir_config *conf =
623       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
624
625     return conf->opts;
626 }
627
628 AP_DECLARE(int) ap_allow_overrides(request_rec *r)
629 {
630     core_dir_config *conf;
631     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
632                                                    &core_module);
633
634     return conf->override;
635 }
636
637 AP_DECLARE(const char *) ap_auth_type(request_rec *r)
638 {
639     core_dir_config *conf;
640
641     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
642                                                    &core_module);
643
644     return conf->ap_auth_type;
645 }
646
647 AP_DECLARE(const char *) ap_auth_name(request_rec *r)
648 {
649     core_dir_config *conf;
650
651     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
652                                                    &core_module);
653
654     return conf->ap_auth_name;
655 }
656
657 AP_DECLARE(const char *) ap_default_type(request_rec *r)
658 {
659     core_dir_config *conf;
660
661     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
662                                                    &core_module);
663
664     return conf->ap_default_type
665                ? conf->ap_default_type
666                : DEFAULT_CONTENT_TYPE;
667 }
668
669 AP_DECLARE(const char *) ap_document_root(request_rec *r) /* Don't use this! */
670 {
671     core_server_config *conf;
672
673     conf = (core_server_config *)ap_get_module_config(r->server->module_config,
674                                                       &core_module);
675
676     return conf->ap_document_root;
677 }
678
679 AP_DECLARE(const apr_array_header_t *) ap_requires(request_rec *r)
680 {
681     core_dir_config *conf;
682
683     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
684                                                    &core_module);
685
686     return conf->ap_requires;
687 }
688
689 AP_DECLARE(int) ap_satisfies(request_rec *r)
690 {
691     core_dir_config *conf;
692
693     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
694                                                    &core_module);
695
696     return conf->satisfy[r->method_number];
697 }
698
699 /* Should probably just get rid of this... the only code that cares is
700  * part of the core anyway (and in fact, it isn't publicised to other
701  * modules).
702  */
703
704 char *ap_response_code_string(request_rec *r, int error_index)
705 {
706     core_dir_config *dirconf;
707     core_request_config *reqconf;
708
709     /* check for string registered via ap_custom_response() first */
710     reqconf = (core_request_config *)ap_get_module_config(r->request_config,
711                                                           &core_module);
712     if (reqconf->response_code_strings != NULL &&
713         reqconf->response_code_strings[error_index] != NULL) {
714         return reqconf->response_code_strings[error_index];
715     }
716
717     /* check for string specified via ErrorDocument */
718     dirconf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
719                                                       &core_module);
720
721     if (dirconf->response_code_strings == NULL) {
722         return NULL;
723     }
724
725     if (dirconf->response_code_strings[error_index] == &errordocument_default) {
726         return NULL;
727     }
728
729     return dirconf->response_code_strings[error_index];
730 }
731
732
733 /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
734 static APR_INLINE void do_double_reverse (conn_rec *conn)
735 {
736     apr_sockaddr_t *sa;
737     apr_status_t rv;
738
739     if (conn->double_reverse) {
740         /* already done */
741         return;
742     }
743
744     if (conn->remote_host == NULL || conn->remote_host[0] == '\0') {
745         /* single reverse failed, so don't bother */
746         conn->double_reverse = -1;
747         return;
748     }
749
750     rv = apr_sockaddr_info_get(&sa, conn->remote_host, APR_UNSPEC, 0, 0, conn->pool);
751     if (rv == APR_SUCCESS) {
752         while (sa) {
753             if (apr_sockaddr_equal(sa, conn->remote_addr)) {
754                 conn->double_reverse = 1;
755                 return;
756             }
757
758             sa = sa->next;
759         }
760     }
761
762     conn->double_reverse = -1;
763 }
764
765 AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config,
766                                             int type, int *str_is_ip)
767 {
768     int hostname_lookups;
769     int ignored_str_is_ip;
770
771     if (!str_is_ip) { /* caller doesn't want to know */
772         str_is_ip = &ignored_str_is_ip;
773     }
774     *str_is_ip = 0;
775
776     /* If we haven't checked the host name, and we want to */
777     if (dir_config) {
778         hostname_lookups =
779             ((core_dir_config *)ap_get_module_config(dir_config, &core_module))
780             ->hostname_lookups;
781
782         if (hostname_lookups == HOSTNAME_LOOKUP_UNSET) {
783             hostname_lookups = HOSTNAME_LOOKUP_OFF;
784         }
785     }
786     else {
787         /* the default */
788         hostname_lookups = HOSTNAME_LOOKUP_OFF;
789     }
790
791     if (type != REMOTE_NOLOOKUP
792         && conn->remote_host == NULL
793         && (type == REMOTE_DOUBLE_REV
794         || hostname_lookups != HOSTNAME_LOOKUP_OFF)) {
795
796         if (apr_getnameinfo(&conn->remote_host, conn->remote_addr, 0)
797             == APR_SUCCESS) {
798             ap_str_tolower(conn->remote_host);
799
800             if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) {
801                 do_double_reverse(conn);
802                 if (conn->double_reverse != 1) {
803                     conn->remote_host = NULL;
804                 }
805             }
806         }
807
808         /* if failed, set it to the NULL string to indicate error */
809         if (conn->remote_host == NULL) {
810             conn->remote_host = "";
811         }
812     }
813
814     if (type == REMOTE_DOUBLE_REV) {
815         do_double_reverse(conn);
816         if (conn->double_reverse == -1) {
817             return NULL;
818         }
819     }
820
821     /*
822      * Return the desired information; either the remote DNS name, if found,
823      * or either NULL (if the hostname was requested) or the IP address
824      * (if any identifier was requested).
825      */
826     if (conn->remote_host != NULL && conn->remote_host[0] != '\0') {
827         return conn->remote_host;
828     }
829     else {
830         if (type == REMOTE_HOST || type == REMOTE_DOUBLE_REV) {
831             return NULL;
832         }
833         else {
834             *str_is_ip = 1;
835             return conn->remote_ip;
836         }
837     }
838 }
839
840 /*
841  * Optional function coming from mod_ident, used for looking up ident user
842  */
843 static APR_OPTIONAL_FN_TYPE(ap_ident_lookup) *ident_lookup;
844
845 AP_DECLARE(const char *) ap_get_remote_logname(request_rec *r)
846 {
847     if (r->connection->remote_logname != NULL) {
848         return r->connection->remote_logname;
849     }
850
851     if (ident_lookup) {
852         return ident_lookup(r);
853     }
854
855     return NULL;
856 }
857
858 /* There are two options regarding what the "name" of a server is.  The
859  * "canonical" name as defined by ServerName and Port, or the "client's
860  * name" as supplied by a possible Host: header or full URI.  We never
861  * trust the port passed in the client's headers, we always use the
862  * port of the actual socket.
863  *
864  * The DNS option to UseCanonicalName causes this routine to do a
865  * reverse lookup on the local IP address of the connection and use
866  * that for the ServerName. This makes its value more reliable while
867  * at the same time allowing Demon's magic virtual hosting to work.
868  * The assumption is that DNS lookups are sufficiently quick...
869  * -- fanf 1998-10-03
870  */
871 AP_DECLARE(const char *) ap_get_server_name(request_rec *r)
872 {
873     conn_rec *conn = r->connection;
874     core_dir_config *d;
875
876     d = (core_dir_config *)ap_get_module_config(r->per_dir_config,
877                                                 &core_module);
878
879     if (d->use_canonical_name == USE_CANONICAL_NAME_OFF) {
880         return r->hostname ? r->hostname : r->server->server_hostname;
881     }
882
883     if (d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
884         if (conn->local_host == NULL) {
885             if (apr_getnameinfo(&conn->local_host,
886                                 conn->local_addr, 0) != APR_SUCCESS)
887                 conn->local_host = apr_pstrdup(conn->pool,
888                                                r->server->server_hostname);
889             else {
890                 ap_str_tolower(conn->local_host);
891             }
892         }
893
894         return conn->local_host;
895     }
896
897     /* default */
898     return r->server->server_hostname;
899 }
900
901 /*
902  * Get the current server name from the request for the purposes
903  * of using in a URL.  If the server name is an IPv6 literal
904  * address, it will be returned in URL format (e.g., "[fe80::1]").
905  */
906 static const char *get_server_name_for_url(request_rec *r)
907 {
908     const char *plain_server_name = ap_get_server_name(r);
909
910 #if APR_HAVE_IPV6
911     if (ap_strchr_c(plain_server_name, ':')) { /* IPv6 literal? */
912         return apr_psprintf(r->pool, "[%s]", plain_server_name);
913     }
914 #endif
915     return plain_server_name;
916 }
917
918 AP_DECLARE(apr_port_t) ap_get_server_port(const request_rec *r)
919 {
920     apr_port_t port;
921     core_dir_config *d =
922       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
923
924     if (d->use_canonical_name == USE_CANONICAL_NAME_OFF
925         || d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
926
927         /* With UseCanonicalName off Apache will form self-referential
928          * URLs using the hostname and port supplied by the client if
929          * any are supplied (otherwise it will use the canonical name).
930          */
931         port = r->parsed_uri.port_str ? r->parsed_uri.port :
932                r->connection->local_addr->port ? r->connection->local_addr->port :
933                r->server->port ? r->server->port :
934                ap_default_port(r);
935     }
936     else { /* d->use_canonical_name == USE_CANONICAL_NAME_ON */
937
938         /* With UseCanonicalName on (and in all versions prior to 1.3)
939          * Apache will use the hostname and port specified in the
940          * ServerName directive to construct a canonical name for the
941          * server. (If no port was specified in the ServerName
942          * directive, Apache uses the port supplied by the client if
943          * any is supplied, and finally the default port for the protocol
944          * used.
945          */
946         port = r->server->port ? r->server->port :
947                r->connection->local_addr->port ? r->connection->local_addr->port :
948                ap_default_port(r);
949     }
950
951     /* default */
952     return port;
953 }
954
955 AP_DECLARE(char *) ap_construct_url(apr_pool_t *p, const char *uri,
956                                     request_rec *r)
957 {
958     unsigned port = ap_get_server_port(r);
959     const char *host = get_server_name_for_url(r);
960
961     if (ap_is_default_port(port, r)) {
962         return apr_pstrcat(p, ap_http_scheme(r), "://", host, uri, NULL);
963     }
964
965     return apr_psprintf(p, "%s://%s:%u%s", ap_http_scheme(r), host, port, uri);
966 }
967
968 AP_DECLARE(apr_off_t) ap_get_limit_req_body(const request_rec *r)
969 {
970     core_dir_config *d =
971       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
972
973     if (d->limit_req_body == AP_LIMIT_REQ_BODY_UNSET) {
974         return AP_DEFAULT_LIMIT_REQ_BODY;
975     }
976
977     return d->limit_req_body;
978 }
979
980
981 /*****************************************************************
982  *
983  * Commands... this module handles almost all of the NCSA httpd.conf
984  * commands, but most of the old srm.conf is in the the modules.
985  */
986
987
988 /* returns a parent if it matches the given directive */
989 static const ap_directive_t * find_parent(const ap_directive_t *dirp,
990                                           const char *what)
991 {
992     while (dirp->parent != NULL) {
993         dirp = dirp->parent;
994
995         /* ### it would be nice to have atom-ized directives */
996         if (strcasecmp(dirp->directive, what) == 0)
997             return dirp;
998     }
999
1000     return NULL;
1001 }
1002
1003 AP_DECLARE(const char *) ap_check_cmd_context(cmd_parms *cmd,
1004                                               unsigned forbidden)
1005 {
1006     const char *gt = (cmd->cmd->name[0] == '<'
1007                       && cmd->cmd->name[strlen(cmd->cmd->name)-1] != '>')
1008                          ? ">" : "";
1009     const ap_directive_t *found;
1010
1011     if ((forbidden & NOT_IN_VIRTUALHOST) && cmd->server->is_virtual) {
1012         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1013                            " cannot occur within <VirtualHost> section", NULL);
1014     }
1015
1016     if ((forbidden & NOT_IN_LIMIT) && cmd->limited != -1) {
1017         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1018                            " cannot occur within <Limit> section", NULL);
1019     }
1020
1021     if ((forbidden & NOT_IN_DIR_LOC_FILE) == NOT_IN_DIR_LOC_FILE) {
1022         if (cmd->path != NULL) {
1023             return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1024                             " cannot occur within <Directory/Location/Files> "
1025                             "section", NULL);
1026         }
1027         if (cmd->cmd->req_override & EXEC_ON_READ) {
1028             /* EXEC_ON_READ must be NOT_IN_DIR_LOC_FILE, if not, it will
1029              * (deliberately) segfault below in the individual tests...
1030              */
1031             return NULL;
1032         }
1033     }
1034     
1035     if (((forbidden & NOT_IN_DIRECTORY)
1036          && ((found = find_parent(cmd->directive, "<Directory"))
1037              || (found = find_parent(cmd->directive, "<DirectoryMatch"))))
1038         || ((forbidden & NOT_IN_LOCATION)
1039             && ((found = find_parent(cmd->directive, "<Location"))
1040                 || (found = find_parent(cmd->directive, "<LocationMatch"))))
1041         || ((forbidden & NOT_IN_FILES)
1042             && ((found = find_parent(cmd->directive, "<Files"))
1043                 || (found = find_parent(cmd->directive, "<FilesMatch"))))) {
1044         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1045                            " cannot occur within ", found->directive,
1046                            "> section", NULL);
1047     }
1048
1049     return NULL;
1050 }
1051
1052 static const char *set_access_name(cmd_parms *cmd, void *dummy,
1053                                    const char *arg)
1054 {
1055     void *sconf = cmd->server->module_config;
1056     core_server_config *conf = ap_get_module_config(sconf, &core_module);
1057
1058     const char *err = ap_check_cmd_context(cmd,
1059                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1060     if (err != NULL) {
1061         return err;
1062     }
1063
1064     conf->access_name = apr_pstrdup(cmd->pool, arg);
1065     return NULL;
1066 }
1067
1068 #ifdef GPROF
1069 static const char *set_gprof_dir(cmd_parms *cmd, void *dummy, const char *arg)
1070 {
1071     void *sconf = cmd->server->module_config;
1072     core_server_config *conf = ap_get_module_config(sconf, &core_module);
1073
1074     const char *err = ap_check_cmd_context(cmd,
1075                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1076     if (err != NULL) {
1077         return err;
1078     }
1079
1080     conf->gprof_dir = apr_pstrdup(cmd->pool, arg);
1081     return NULL;
1082 }
1083 #endif /*GPROF*/
1084
1085 static const char *set_add_default_charset(cmd_parms *cmd,
1086                                            void *d_, const char *arg)
1087 {
1088     core_dir_config *d = d_;
1089
1090     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1091     if (err != NULL) {
1092         return err;
1093     }
1094
1095     if (!strcasecmp(arg, "Off")) {
1096        d->add_default_charset = ADD_DEFAULT_CHARSET_OFF;
1097     }
1098     else if (!strcasecmp(arg, "On")) {
1099        d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
1100        d->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
1101     }
1102     else {
1103        d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
1104        d->add_default_charset_name = arg;
1105     }
1106
1107     return NULL;
1108 }
1109
1110 static const char *set_document_root(cmd_parms *cmd, void *dummy,
1111                                      const char *arg)
1112 {
1113     void *sconf = cmd->server->module_config;
1114     core_server_config *conf = ap_get_module_config(sconf, &core_module);
1115
1116     const char *err = ap_check_cmd_context(cmd,
1117                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1118     if (err != NULL) {
1119         return err;
1120     }
1121
1122     /* Make it absolute, relative to ServerRoot */
1123     arg = ap_server_root_relative(cmd->pool, arg);
1124
1125     /* TODO: ap_configtestonly && ap_docrootcheck && */
1126     if (apr_filepath_merge((char**)&conf->ap_document_root, NULL, arg,
1127                            APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS
1128         || !ap_is_directory(cmd->pool, arg)) {
1129         if (cmd->server->is_virtual) {
1130             ap_log_perror(APLOG_MARK, APLOG_STARTUP, 0,
1131                           cmd->pool,
1132                           "Warning: DocumentRoot [%s] does not exist",
1133                           arg);
1134             conf->ap_document_root = arg;
1135         }
1136         else {
1137             return "DocumentRoot must be a directory";
1138         }
1139     }
1140     return NULL;
1141 }
1142
1143 AP_DECLARE(void) ap_custom_response(request_rec *r, int status,
1144                                     const char *string)
1145 {
1146     core_request_config *conf =
1147         ap_get_module_config(r->request_config, &core_module);
1148     int idx;
1149
1150     if (conf->response_code_strings == NULL) {
1151         conf->response_code_strings =
1152             apr_pcalloc(r->pool,
1153                         sizeof(*conf->response_code_strings) * RESPONSE_CODES);
1154     }
1155
1156     idx = ap_index_of_response(status);
1157
1158     conf->response_code_strings[idx] =
1159        ((ap_is_url(string) || (*string == '/')) && (*string != '"')) ?
1160        apr_pstrdup(r->pool, string) : apr_pstrcat(r->pool, "\"", string, NULL);
1161 }
1162
1163 static const char *set_error_document(cmd_parms *cmd, void *conf_,
1164                                       const char *errno_str, const char *msg)
1165 {
1166     core_dir_config *conf = conf_;
1167     int error_number, index_number, idx500;
1168     enum { MSG, LOCAL_PATH, REMOTE_PATH } what = MSG;
1169
1170     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1171     if (err != NULL) {
1172         return err;
1173     }
1174
1175     /* 1st parameter should be a 3 digit number, which we recognize;
1176      * convert it into an array index
1177      */
1178     error_number = atoi(errno_str);
1179     idx500 = ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR);
1180
1181     if (error_number == HTTP_INTERNAL_SERVER_ERROR) {
1182         index_number = idx500;
1183     }
1184     else if ((index_number = ap_index_of_response(error_number)) == idx500) {
1185         return apr_pstrcat(cmd->pool, "Unsupported HTTP response code ",
1186                            errno_str, NULL);
1187     }
1188
1189     /* Heuristic to determine second argument. */
1190     if (ap_strchr_c(msg,' '))
1191         what = MSG;
1192     else if (msg[0] == '/')
1193         what = LOCAL_PATH;
1194     else if (ap_is_url(msg))
1195         what = REMOTE_PATH;
1196     else
1197         what = MSG;
1198
1199     /* The entry should be ignored if it is a full URL for a 401 error */
1200
1201     if (error_number == 401 && what == REMOTE_PATH) {
1202         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, cmd->server,
1203                      "cannot use a full URL in a 401 ErrorDocument "
1204                      "directive --- ignoring!");
1205     }
1206     else { /* Store it... */
1207         if (conf->response_code_strings == NULL) {
1208             conf->response_code_strings =
1209                 apr_pcalloc(cmd->pool,
1210                             sizeof(*conf->response_code_strings) *
1211                             RESPONSE_CODES);
1212         }
1213
1214         if (strcmp(msg, "default") == 0) {
1215             /* special case: ErrorDocument 404 default restores the
1216              * canned server error response
1217              */
1218             conf->response_code_strings[index_number] = &errordocument_default;
1219         }
1220         else {
1221             /* hack. Prefix a " if it is a msg; as that is what
1222              * http_protocol.c relies on to distinguish between
1223              * a msg and a (local) path.
1224              */
1225             conf->response_code_strings[index_number] = (what == MSG) ?
1226                     apr_pstrcat(cmd->pool, "\"",msg,NULL) :
1227                     apr_pstrdup(cmd->pool, msg);
1228         }
1229     }
1230
1231     return NULL;
1232 }
1233
1234 static const char *set_allow_opts(cmd_parms *cmd, allow_options_t *opts,
1235                                   const char *l)
1236 {
1237     allow_options_t opt;
1238     int first = 1;
1239
1240     char *w, *p = (char *) l;
1241     char *tok_state;
1242
1243     while ((w = apr_strtok(p, ",", &tok_state)) != NULL) {
1244
1245         if (first) {
1246             p = NULL;
1247             *opts = OPT_NONE;
1248             first = 0;
1249         }
1250
1251         if (!strcasecmp(w, "Indexes")) {
1252             opt = OPT_INDEXES;
1253         }
1254         else if (!strcasecmp(w, "Includes")) {
1255             opt = OPT_INCLUDES;
1256         }
1257         else if (!strcasecmp(w, "IncludesNOEXEC")) {
1258             opt = (OPT_INCLUDES | OPT_INCNOEXEC);
1259         }
1260         else if (!strcasecmp(w, "FollowSymLinks")) {
1261             opt = OPT_SYM_LINKS;
1262         }
1263         else if (!strcasecmp(w, "SymLinksIfOwnerMatch")) {
1264             opt = OPT_SYM_OWNER;
1265         }
1266         else if (!strcasecmp(w, "ExecCGI")) {
1267             opt = OPT_EXECCGI;
1268         }
1269         else if (!strcasecmp(w, "MultiViews")) {
1270             opt = OPT_MULTI;
1271         }
1272         else if (!strcasecmp(w, "RunScripts")) { /* AI backcompat. Yuck */
1273             opt = OPT_MULTI|OPT_EXECCGI;
1274         }
1275         else if (!strcasecmp(w, "None")) {
1276             opt = OPT_NONE;
1277         }
1278         else if (!strcasecmp(w, "All")) {
1279             opt = OPT_ALL;
1280         }
1281         else {
1282             return apr_pstrcat(cmd->pool, "Illegal option ", w, NULL);
1283         }
1284
1285         *opts |= opt;
1286     }
1287
1288     (*opts) &= (~OPT_UNSET);
1289
1290     return NULL;
1291 }
1292
1293 static const char *set_override(cmd_parms *cmd, void *d_, const char *l)
1294 {
1295     core_dir_config *d = d_;
1296     char *w;
1297     char *k, *v;
1298
1299     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1300     if (err != NULL) {
1301         return err;
1302     }
1303
1304     /* Throw a warning if we're in <Location> or <Files> */
1305     if (ap_check_cmd_context(cmd, NOT_IN_LOCATION | NOT_IN_FILES)) {
1306         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
1307                      "Useless use of AllowOverride in line %d.",
1308                      cmd->directive->line_num);
1309     }
1310
1311     d->override = OR_NONE;
1312     while (l[0]) {
1313         w = ap_getword_conf(cmd->pool, &l);
1314
1315         k = w;
1316         v = strchr(k, '=');
1317         if (v) {
1318                 *v++ = '\0';
1319         }
1320
1321         if (!strcasecmp(w, "Limit")) {
1322             d->override |= OR_LIMIT;
1323         }
1324         else if (!strcasecmp(k, "Options")) {
1325             d->override |= OR_OPTIONS;
1326             if (v) 
1327                 set_allow_opts(cmd, &(d->override_opts), v);
1328             else
1329                 d->override_opts = OPT_ALL;
1330         }
1331         else if (!strcasecmp(w, "FileInfo")) {
1332             d->override |= OR_FILEINFO;
1333         }
1334         else if (!strcasecmp(w, "AuthConfig")) {
1335             d->override |= OR_AUTHCFG;
1336         }
1337         else if (!strcasecmp(w, "Indexes")) {
1338             d->override |= OR_INDEXES;
1339         }
1340         else if (!strcasecmp(w, "None")) {
1341             d->override = OR_NONE;
1342         }
1343         else if (!strcasecmp(w, "All")) {
1344             d->override = OR_ALL;
1345         }
1346         else {
1347             return apr_pstrcat(cmd->pool, "Illegal override option ", w, NULL);
1348         }
1349
1350         d->override &= ~OR_UNSET;
1351     }
1352
1353     return NULL;
1354 }
1355
1356 static const char *set_options(cmd_parms *cmd, void *d_, const char *l)
1357 {
1358     core_dir_config *d = d_;
1359     allow_options_t opt;
1360     int first = 1;
1361     char action;
1362
1363     while (l[0]) {
1364         char *w = ap_getword_conf(cmd->pool, &l);
1365         action = '\0';
1366
1367         if (*w == '+' || *w == '-') {
1368             action = *(w++);
1369         }
1370         else if (first) {
1371               d->opts = OPT_NONE;
1372             first = 0;
1373         }
1374
1375         if (!strcasecmp(w, "Indexes")) {
1376             opt = OPT_INDEXES;
1377         }
1378         else if (!strcasecmp(w, "Includes")) {
1379             opt = OPT_INCLUDES;
1380         }
1381         else if (!strcasecmp(w, "IncludesNOEXEC")) {
1382             opt = (OPT_INCLUDES | OPT_INCNOEXEC);
1383         }
1384         else if (!strcasecmp(w, "FollowSymLinks")) {
1385             opt = OPT_SYM_LINKS;
1386         }
1387         else if (!strcasecmp(w, "SymLinksIfOwnerMatch")) {
1388             opt = OPT_SYM_OWNER;
1389         }
1390         else if (!strcasecmp(w, "ExecCGI")) {
1391             opt = OPT_EXECCGI;
1392         }
1393         else if (!strcasecmp(w, "MultiViews")) {
1394             opt = OPT_MULTI;
1395         }
1396         else if (!strcasecmp(w, "RunScripts")) { /* AI backcompat. Yuck */
1397             opt = OPT_MULTI|OPT_EXECCGI;
1398         }
1399         else if (!strcasecmp(w, "None")) {
1400             opt = OPT_NONE;
1401         }
1402         else if (!strcasecmp(w, "All")) {
1403             opt = OPT_ALL;
1404         }
1405         else {
1406             return apr_pstrcat(cmd->pool, "Illegal option ", w, NULL);
1407         }
1408
1409         if (!(cmd->override_opts & opt) && opt != OPT_NONE) {
1410             return apr_pstrcat(cmd->pool, "Option ", w, " not allowed here", NULL);
1411         }
1412         else if (action == '-') {
1413             /* we ensure the invariant (d->opts_add & d->opts_remove) == 0 */
1414             d->opts_remove |= opt;
1415             d->opts_add &= ~opt;
1416             d->opts &= ~opt;
1417         }
1418         else if (action == '+') {
1419             d->opts_add |= opt;
1420             d->opts_remove &= ~opt;
1421             d->opts |= opt;
1422         }
1423         else {
1424             d->opts |= opt;
1425         }
1426     }
1427
1428     return NULL;
1429 }
1430
1431 /*
1432  * Note what data should be used when forming file ETag values.
1433  * It would be nicer to do this as an ITERATE, but then we couldn't
1434  * remember the +/- state properly.
1435  */
1436 static const char *set_etag_bits(cmd_parms *cmd, void *mconfig,
1437                                  const char *args_p)
1438 {
1439     core_dir_config *cfg;
1440     etag_components_t bit;
1441     char action;
1442     char *token;
1443     const char *args;
1444     int valid;
1445     int first;
1446     int explicit;
1447
1448     cfg = (core_dir_config *)mconfig;
1449
1450     args = args_p;
1451     first = 1;
1452     explicit = 0;
1453     while (args[0] != '\0') {
1454         action = '*';
1455         bit = ETAG_UNSET;
1456         valid = 1;
1457         token = ap_getword_conf(cmd->pool, &args);
1458         if ((*token == '+') || (*token == '-')) {
1459             action = *token;
1460             token++;
1461         }
1462         else {
1463             /*
1464              * The occurrence of an absolute setting wipes
1465              * out any previous relative ones.  The first such
1466              * occurrence forgets any inherited ones, too.
1467              */
1468             if (first) {
1469                 cfg->etag_bits = ETAG_UNSET;
1470                 cfg->etag_add = ETAG_UNSET;
1471                 cfg->etag_remove = ETAG_UNSET;
1472                 first = 0;
1473             }
1474         }
1475
1476         if (strcasecmp(token, "None") == 0) {
1477             if (action != '*') {
1478                 valid = 0;
1479             }
1480             else {
1481                 cfg->etag_bits = bit = ETAG_NONE;
1482                 explicit = 1;
1483             }
1484         }
1485         else if (strcasecmp(token, "All") == 0) {
1486             if (action != '*') {
1487                 valid = 0;
1488             }
1489             else {
1490                 explicit = 1;
1491                 cfg->etag_bits = bit = ETAG_ALL;
1492             }
1493         }
1494         else if (strcasecmp(token, "Size") == 0) {
1495             bit = ETAG_SIZE;
1496         }
1497         else if ((strcasecmp(token, "LMTime") == 0)
1498                  || (strcasecmp(token, "MTime") == 0)
1499                  || (strcasecmp(token, "LastModified") == 0)) {
1500             bit = ETAG_MTIME;
1501         }
1502         else if (strcasecmp(token, "INode") == 0) {
1503             bit = ETAG_INODE;
1504         }
1505         else {
1506             return apr_pstrcat(cmd->pool, "Unknown keyword '",
1507                                token, "' for ", cmd->cmd->name,
1508                                " directive", NULL);
1509         }
1510
1511         if (! valid) {
1512             return apr_pstrcat(cmd->pool, cmd->cmd->name, " keyword '",
1513                                token, "' cannot be used with '+' or '-'",
1514                                NULL);
1515         }
1516
1517         if (action == '+') {
1518             /*
1519              * Make sure it's in the 'add' list and absent from the
1520              * 'subtract' list.
1521              */
1522             cfg->etag_add |= bit;
1523             cfg->etag_remove &= (~ bit);
1524         }
1525         else if (action == '-') {
1526             cfg->etag_remove |= bit;
1527             cfg->etag_add &= (~ bit);
1528         }
1529         else {
1530             /*
1531              * Non-relative values wipe out any + or - values
1532              * accumulated so far.
1533              */
1534             cfg->etag_bits |= bit;
1535             cfg->etag_add = ETAG_UNSET;
1536             cfg->etag_remove = ETAG_UNSET;
1537             explicit = 1;
1538         }
1539     }
1540
1541     /*
1542      * Any setting at all will clear the 'None' and 'Unset' bits.
1543      */
1544
1545     if (cfg->etag_add != ETAG_UNSET) {
1546         cfg->etag_add &= (~ ETAG_UNSET);
1547     }
1548
1549     if (cfg->etag_remove != ETAG_UNSET) {
1550         cfg->etag_remove &= (~ ETAG_UNSET);
1551     }
1552
1553     if (explicit) {
1554         cfg->etag_bits &= (~ ETAG_UNSET);
1555
1556         if ((cfg->etag_bits & ETAG_NONE) != ETAG_NONE) {
1557             cfg->etag_bits &= (~ ETAG_NONE);
1558         }
1559     }
1560
1561     return NULL;
1562 }
1563
1564 static const char *set_enable_mmap(cmd_parms *cmd, void *d_,
1565                                    const char *arg)
1566 {
1567     core_dir_config *d = d_;
1568     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1569
1570     if (err != NULL) {
1571         return err;
1572     }
1573
1574     if (strcasecmp(arg, "on") == 0) {
1575         d->enable_mmap = ENABLE_MMAP_ON;
1576     }
1577     else if (strcasecmp(arg, "off") == 0) {
1578         d->enable_mmap = ENABLE_MMAP_OFF;
1579     }
1580     else {
1581         return "parameter must be 'on' or 'off'";
1582     }
1583
1584     return NULL;
1585 }
1586
1587 static const char *set_enable_sendfile(cmd_parms *cmd, void *d_,
1588                                    const char *arg)
1589 {
1590     core_dir_config *d = d_;
1591     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1592
1593     if (err != NULL) {
1594         return err;
1595     }
1596
1597     if (strcasecmp(arg, "on") == 0) {
1598         d->enable_sendfile = ENABLE_SENDFILE_ON;
1599     }
1600     else if (strcasecmp(arg, "off") == 0) {
1601         d->enable_sendfile = ENABLE_SENDFILE_OFF;
1602     }
1603     else {
1604         return "parameter must be 'on' or 'off'";
1605     }
1606
1607     return NULL;
1608 }
1609
1610 static const char *satisfy(cmd_parms *cmd, void *c_, const char *arg)
1611 {
1612     core_dir_config *c = c_;
1613     int satisfy = SATISFY_NOSPEC;
1614     int i;
1615
1616     if (!strcasecmp(arg, "all")) {
1617         satisfy = SATISFY_ALL;
1618     }
1619     else if (!strcasecmp(arg, "any")) {
1620         satisfy = SATISFY_ANY;
1621     }
1622     else {
1623         return "Satisfy either 'any' or 'all'.";
1624     }
1625
1626     for (i = 0; i < METHODS; ++i) {
1627         if (cmd->limited & (AP_METHOD_BIT << i)) {
1628             c->satisfy[i] = satisfy;
1629         }
1630     }
1631
1632     return NULL;
1633 }
1634
1635 static const char *require(cmd_parms *cmd, void *c_, const char *arg)
1636 {
1637     require_line *r;
1638     core_dir_config *c = c_;
1639
1640     if (!c->ap_requires) {
1641         c->ap_requires = apr_array_make(cmd->pool, 2, sizeof(require_line));
1642     }
1643
1644     r = (require_line *)apr_array_push(c->ap_requires);
1645     r->requirement = apr_pstrdup(cmd->pool, arg);
1646     r->method_mask = cmd->limited;
1647
1648     return NULL;
1649 }
1650
1651 /*
1652  * Report a missing-'>' syntax error.
1653  */
1654 static char *unclosed_directive(cmd_parms *cmd)
1655 {
1656     return apr_pstrcat(cmd->pool, cmd->cmd->name,
1657                        "> directive missing closing '>'", NULL);
1658 }
1659
1660 /*
1661  * Report a missing args in '<Foo >' syntax error.
1662  */
1663 static char *missing_container_arg(cmd_parms *cmd)
1664 {
1665     return apr_pstrcat(cmd->pool, cmd->cmd->name,
1666                        "> directive requires additional arguments", NULL);
1667 }
1668
1669 AP_CORE_DECLARE_NONSTD(const char *) ap_limit_section(cmd_parms *cmd,
1670                                                       void *dummy,
1671                                                       const char *arg)
1672 {
1673     const char *endp = ap_strrchr_c(arg, '>');
1674     const char *limited_methods;
1675     void *tog = cmd->cmd->cmd_data;
1676     apr_int64_t limited = 0;
1677     const char *errmsg;
1678
1679     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1680     if (err != NULL) {
1681         return err;
1682     }
1683
1684     if (endp == NULL) {
1685         return unclosed_directive(cmd);
1686     }
1687
1688     limited_methods = apr_pstrndup(cmd->pool, arg, endp - arg);
1689
1690     if (!limited_methods[0]) {
1691         return missing_container_arg(cmd);
1692     }
1693
1694     while (limited_methods[0]) {
1695         char *method = ap_getword_conf(cmd->pool, &limited_methods);
1696         int methnum;
1697
1698         /* check for builtin or module registered method number */
1699         methnum = ap_method_number_of(method);
1700
1701         if (methnum == M_TRACE && !tog) {
1702             return "TRACE cannot be controlled by <Limit>";
1703         }
1704         else if (methnum == M_INVALID) {
1705             /* method has not been registered yet, but resorce restriction
1706              * is always checked before method handling, so register it.
1707              */
1708             methnum = ap_method_register(cmd->pool, method);
1709         }
1710
1711         limited |= (AP_METHOD_BIT << methnum);
1712     }
1713
1714     /* Killing two features with one function,
1715      * if (tog == NULL) <Limit>, else <LimitExcept>
1716      */
1717     cmd->limited = tog ? ~limited : limited;
1718
1719     errmsg = ap_walk_config(cmd->directive->first_child, cmd, cmd->context);
1720
1721     cmd->limited = -1;
1722
1723     return errmsg;
1724 }
1725
1726 /* XXX: Bogus - need to do this differently (at least OS2/Netware suffer
1727  * the same problem!!!
1728  * We use this in <DirectoryMatch> and <FilesMatch>, to ensure that
1729  * people don't get bitten by wrong-cased regex matches
1730  */
1731
1732 #ifdef WIN32
1733 #define USE_ICASE AP_REG_ICASE
1734 #else
1735 #define USE_ICASE 0
1736 #endif
1737
1738 static const char *dirsection(cmd_parms *cmd, void *mconfig, const char *arg)
1739 {
1740     const char *errmsg;
1741     const char *endp = ap_strrchr_c(arg, '>');
1742     int old_overrides = cmd->override;
1743     char *old_path = cmd->path;
1744     core_dir_config *conf;
1745     ap_conf_vector_t *new_dir_conf = ap_create_per_dir_config(cmd->pool);
1746     ap_regex_t *r = NULL;
1747     const command_rec *thiscmd = cmd->cmd;
1748
1749     const char *err = ap_check_cmd_context(cmd,
1750                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1751     if (err != NULL) {
1752         return err;
1753     }
1754
1755     if (endp == NULL) {
1756         return unclosed_directive(cmd);
1757     }
1758
1759     arg = apr_pstrndup(cmd->pool, arg, endp - arg);
1760
1761     if (!arg[0]) {
1762         return missing_container_arg(cmd);
1763     }
1764
1765     if (!arg) {
1766         if (thiscmd->cmd_data)
1767             return "<DirectoryMatch > block must specify a path";
1768         else
1769             return "<Directory > block must specify a path";
1770     }
1771
1772     cmd->path = ap_getword_conf(cmd->pool, &arg);
1773     cmd->override = OR_ALL|ACCESS_CONF;
1774
1775     if (!strcmp(cmd->path, "~")) {
1776         cmd->path = ap_getword_conf(cmd->pool, &arg);
1777         if (!cmd->path)
1778             return "<Directory ~ > block must specify a path";
1779         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
1780         if (!r) {
1781             return "Regex could not be compiled";
1782         }
1783     }
1784     else if (thiscmd->cmd_data) { /* <DirectoryMatch> */
1785         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
1786         if (!r) {
1787             return "Regex could not be compiled";
1788         }
1789     }
1790     else if (!strcmp(cmd->path, "/") == 0)
1791     {
1792         char *newpath;
1793
1794         /*
1795          * Ensure that the pathname is canonical, and append the trailing /
1796          */
1797         apr_status_t rv = apr_filepath_merge(&newpath, NULL, cmd->path,
1798                                              APR_FILEPATH_TRUENAME, cmd->pool);
1799         if (rv != APR_SUCCESS && rv != APR_EPATHWILD) {
1800             return apr_pstrcat(cmd->pool, "<Directory \"", cmd->path,
1801                                "\"> path is invalid.", NULL);
1802         }
1803
1804         cmd->path = newpath;
1805         if (cmd->path[strlen(cmd->path) - 1] != '/')
1806             cmd->path = apr_pstrcat(cmd->pool, cmd->path, "/", NULL);
1807     }
1808
1809     /* initialize our config and fetch it */
1810     conf = ap_set_config_vectors(cmd->server, new_dir_conf, cmd->path,
1811                                  &core_module, cmd->pool);
1812
1813     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_dir_conf);
1814     if (errmsg != NULL)
1815         return errmsg;
1816
1817     conf->r = r;
1818     conf->d = cmd->path;
1819     conf->d_is_fnmatch = (apr_fnmatch_test(conf->d) != 0);
1820
1821     /* Make this explicit - the "/" root has 0 elements, that is, we
1822      * will always merge it, and it will always sort and merge first.
1823      * All others are sorted and tested by the number of slashes.
1824      */
1825     if (strcmp(conf->d, "/") == 0)
1826         conf->d_components = 0;
1827     else
1828         conf->d_components = ap_count_dirs(conf->d);
1829
1830     ap_add_per_dir_conf(cmd->server, new_dir_conf);
1831
1832     if (*arg != '\0') {
1833         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1834                            "> arguments not (yet) supported.", NULL);
1835     }
1836
1837     cmd->path = old_path;
1838     cmd->override = old_overrides;
1839
1840     return NULL;
1841 }
1842
1843 static const char *urlsection(cmd_parms *cmd, void *mconfig, const char *arg)
1844 {
1845     const char *errmsg;
1846     const char *endp = ap_strrchr_c(arg, '>');
1847     int old_overrides = cmd->override;
1848     char *old_path = cmd->path;
1849     core_dir_config *conf;
1850     ap_regex_t *r = NULL;
1851     const command_rec *thiscmd = cmd->cmd;
1852     ap_conf_vector_t *new_url_conf = ap_create_per_dir_config(cmd->pool);
1853     const char *err = ap_check_cmd_context(cmd,
1854                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1855     if (err != NULL) {
1856         return err;
1857     }
1858
1859     if (endp == NULL) {
1860         return unclosed_directive(cmd);
1861     }
1862
1863     arg = apr_pstrndup(cmd->pool, arg, endp - arg);
1864
1865     if (!arg[0]) {
1866         return missing_container_arg(cmd);
1867     }
1868
1869     cmd->path = ap_getword_conf(cmd->pool, &arg);
1870     cmd->override = OR_ALL|ACCESS_CONF;
1871
1872     if (thiscmd->cmd_data) { /* <LocationMatch> */
1873         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED);
1874         if (!r) {
1875             return "Regex could not be compiled";
1876         }
1877     }
1878     else if (!strcmp(cmd->path, "~")) {
1879         cmd->path = ap_getword_conf(cmd->pool, &arg);
1880         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED);
1881         if (!r) {
1882             return "Regex could not be compiled";
1883         }
1884     }
1885
1886     /* initialize our config and fetch it */
1887     conf = ap_set_config_vectors(cmd->server, new_url_conf, cmd->path,
1888                                  &core_module, cmd->pool);
1889
1890     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_url_conf);
1891     if (errmsg != NULL)
1892         return errmsg;
1893
1894     conf->d = apr_pstrdup(cmd->pool, cmd->path);     /* No mangling, please */
1895     conf->d_is_fnmatch = apr_fnmatch_test(conf->d) != 0;
1896     conf->r = r;
1897
1898     ap_add_per_url_conf(cmd->server, new_url_conf);
1899
1900     if (*arg != '\0') {
1901         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1902                            "> arguments not (yet) supported.", NULL);
1903     }
1904
1905     cmd->path = old_path;
1906     cmd->override = old_overrides;
1907
1908     return NULL;
1909 }
1910
1911 static const char *filesection(cmd_parms *cmd, void *mconfig, const char *arg)
1912 {
1913     const char *errmsg;
1914     const char *endp = ap_strrchr_c(arg, '>');
1915     int old_overrides = cmd->override;
1916     char *old_path = cmd->path;
1917     core_dir_config *conf;
1918     ap_regex_t *r = NULL;
1919     const command_rec *thiscmd = cmd->cmd;
1920     core_dir_config *c = mconfig;
1921     ap_conf_vector_t *new_file_conf = ap_create_per_dir_config(cmd->pool);
1922     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_LOCATION);
1923
1924     if (err != NULL) {
1925         return err;
1926     }
1927
1928     if (endp == NULL) {
1929         return unclosed_directive(cmd);
1930     }
1931
1932     arg = apr_pstrndup(cmd->pool, arg, endp - arg);
1933
1934     if (!arg[0]) {
1935         return missing_container_arg(cmd);
1936     }
1937
1938     cmd->path = ap_getword_conf(cmd->pool, &arg);
1939     /* Only if not an .htaccess file */
1940     if (!old_path) {
1941         cmd->override = OR_ALL|ACCESS_CONF;
1942     }
1943
1944     if (thiscmd->cmd_data) { /* <FilesMatch> */
1945         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
1946         if (!r) {
1947             return "Regex could not be compiled";
1948         }
1949     }
1950     else if (!strcmp(cmd->path, "~")) {
1951         cmd->path = ap_getword_conf(cmd->pool, &arg);
1952         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
1953         if (!r) {
1954             return "Regex could not be compiled";
1955         }
1956     }
1957     else {
1958         char *newpath;
1959         /* Ensure that the pathname is canonical, but we
1960          * can't test the case/aliases without a fixed path */
1961         if (apr_filepath_merge(&newpath, "", cmd->path,
1962                                0, cmd->pool) != APR_SUCCESS)
1963                 return apr_pstrcat(cmd->pool, "<Files \"", cmd->path,
1964                                "\"> is invalid.", NULL);
1965         cmd->path = newpath;
1966     }
1967
1968     /* initialize our config and fetch it */
1969     conf = ap_set_config_vectors(cmd->server, new_file_conf, cmd->path,
1970                                  &core_module, cmd->pool);
1971
1972     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_file_conf);
1973     if (errmsg != NULL)
1974         return errmsg;
1975
1976     conf->d = cmd->path;
1977     conf->d_is_fnmatch = apr_fnmatch_test(conf->d) != 0;
1978     conf->r = r;
1979
1980     ap_add_file_conf(c, new_file_conf);
1981
1982     if (*arg != '\0') {
1983         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1984                            "> arguments not (yet) supported.", NULL);
1985     }
1986
1987     cmd->path = old_path;
1988     cmd->override = old_overrides;
1989
1990     return NULL;
1991 }
1992
1993 static const char *start_ifmod(cmd_parms *cmd, void *mconfig, const char *arg)
1994 {
1995     const char *endp = ap_strrchr_c(arg, '>');
1996     int not = (arg[0] == '!');
1997     module *found;
1998
1999     if (endp == NULL) {
2000         return unclosed_directive(cmd);
2001     }
2002
2003     arg = apr_pstrndup(cmd->pool, arg, endp - arg);
2004
2005     if (not) {
2006         arg++;
2007     }
2008
2009     if (!arg[0]) {
2010         return missing_container_arg(cmd);
2011     }
2012
2013     found = ap_find_linked_module(arg);
2014
2015     /* search prelinked stuff */
2016     if (!found) {
2017         ap_module_symbol_t *current = ap_prelinked_module_symbols;
2018
2019         for (; current->name; ++current) {
2020             if (!strcmp(current->name, arg)) {
2021                 found = current->modp;
2022                 break;
2023             }
2024         }
2025     }
2026
2027     /* search dynamic stuff */
2028     if (!found) {
2029         APR_OPTIONAL_FN_TYPE(ap_find_loaded_module_symbol) *check_symbol =
2030             APR_RETRIEVE_OPTIONAL_FN(ap_find_loaded_module_symbol);
2031
2032         if (check_symbol) {
2033             found = check_symbol(cmd->server, arg);
2034         }
2035     }
2036
2037     if ((!not && found) || (not && !found)) {
2038         ap_directive_t *parent = NULL;
2039         ap_directive_t *current = NULL;
2040         const char *retval;
2041
2042         retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd,
2043                                       &current, &parent, "<IfModule");
2044         *(ap_directive_t **)mconfig = current;
2045         return retval;
2046     }
2047     else {
2048         *(ap_directive_t **)mconfig = NULL;
2049         return ap_soak_end_container(cmd, "<IfModule");
2050     }
2051 }
2052
2053 AP_DECLARE(int) ap_exists_config_define(const char *name)
2054 {
2055     char **defines;
2056     int i;
2057
2058     defines = (char **)ap_server_config_defines->elts;
2059     for (i = 0; i < ap_server_config_defines->nelts; i++) {
2060         if (strcmp(defines[i], name) == 0) {
2061             return 1;
2062         }
2063     }
2064
2065     return 0;
2066 }
2067
2068 static const char *start_ifdefine(cmd_parms *cmd, void *dummy, const char *arg)
2069 {
2070     const char *endp;
2071     int defined;
2072     int not = 0;
2073
2074     endp = ap_strrchr_c(arg, '>');
2075     if (endp == NULL) {
2076         return unclosed_directive(cmd);
2077     }
2078
2079     arg = apr_pstrndup(cmd->pool, arg, endp - arg);
2080
2081     if (arg[0] == '!') {
2082         not = 1;
2083         arg++;
2084     }
2085
2086     if (!arg[0]) {
2087         return missing_container_arg(cmd);
2088     }
2089
2090     defined = ap_exists_config_define(arg);
2091     if ((!not && defined) || (not && !defined)) {
2092         ap_directive_t *parent = NULL;
2093         ap_directive_t *current = NULL;
2094         const char *retval;
2095
2096         retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd,
2097                                       &current, &parent, "<IfDefine");
2098         *(ap_directive_t **)dummy = current;
2099         return retval;
2100     }
2101     else {
2102         *(ap_directive_t **)dummy = NULL;
2103         return ap_soak_end_container(cmd, "<IfDefine");
2104     }
2105 }
2106
2107 /* httpd.conf commands... beginning with the <VirtualHost> business */
2108
2109 static const char *virtualhost_section(cmd_parms *cmd, void *dummy,
2110                                        const char *arg)
2111 {
2112     server_rec *main_server = cmd->server, *s;
2113     const char *errmsg;
2114     const char *endp = ap_strrchr_c(arg, '>');
2115     apr_pool_t *p = cmd->pool;
2116
2117     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2118     if (err != NULL) {
2119         return err;
2120     }
2121
2122     if (endp == NULL) {
2123         return unclosed_directive(cmd);
2124     }
2125
2126     arg = apr_pstrndup(cmd->pool, arg, endp - arg);
2127
2128     if (!arg[0]) {
2129         return missing_container_arg(cmd);
2130     }
2131
2132     /* FIXME: There's another feature waiting to happen here -- since you
2133         can now put multiple addresses/names on a single <VirtualHost>
2134         you might want to use it to group common definitions and then
2135         define other "subhosts" with their individual differences.  But
2136         personally I'd rather just do it with a macro preprocessor. -djg */
2137     if (main_server->is_virtual) {
2138         return "<VirtualHost> doesn't nest!";
2139     }
2140
2141     errmsg = ap_init_virtual_host(p, arg, main_server, &s);
2142     if (errmsg) {
2143         return errmsg;
2144     }
2145
2146     s->next = main_server->next;
2147     main_server->next = s;
2148
2149     s->defn_name = cmd->directive->filename;
2150     s->defn_line_number = cmd->directive->line_num;
2151
2152     cmd->server = s;
2153
2154     errmsg = ap_walk_config(cmd->directive->first_child, cmd,
2155                             s->lookup_defaults);
2156
2157     cmd->server = main_server;
2158
2159     return errmsg;
2160 }
2161
2162 static const char *set_server_alias(cmd_parms *cmd, void *dummy,
2163                                     const char *arg)
2164 {
2165     if (!cmd->server->names) {
2166         return "ServerAlias only used in <VirtualHost>";
2167     }
2168
2169     while (*arg) {
2170         char **item, *name = ap_getword_conf(cmd->pool, &arg);
2171
2172         if (ap_is_matchexp(name)) {
2173             item = (char **)apr_array_push(cmd->server->wild_names);
2174         }
2175         else {
2176             item = (char **)apr_array_push(cmd->server->names);
2177         }
2178
2179         *item = name;
2180     }
2181
2182     return NULL;
2183 }
2184
2185 static const char *set_server_string_slot(cmd_parms *cmd, void *dummy,
2186                                           const char *arg)
2187 {
2188     /* This one's pretty generic... */
2189
2190     int offset = (int)(long)cmd->info;
2191     char *struct_ptr = (char *)cmd->server;
2192
2193     const char *err = ap_check_cmd_context(cmd,
2194                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2195     if (err != NULL) {
2196         return err;
2197     }
2198
2199     *(const char **)(struct_ptr + offset) = arg;
2200     return NULL;
2201 }
2202
2203 static const char *server_hostname_port(cmd_parms *cmd, void *dummy, const char *arg)
2204 {
2205     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2206     const char *portstr;
2207     int port;
2208
2209     if (err != NULL) {
2210         return err;
2211     }
2212
2213     portstr = ap_strchr_c(arg, ':');
2214     if (portstr) {
2215         cmd->server->server_hostname = apr_pstrndup(cmd->pool, arg,
2216                                                     portstr - arg);
2217         portstr++;
2218         port = atoi(portstr);
2219         if (port <= 0 || port >= 65536) { /* 65536 == 1<<16 */
2220             return apr_pstrcat(cmd->temp_pool, "The port number \"", arg,
2221                           "\" is outside the appropriate range "
2222                           "(i.e., 1..65535).", NULL);
2223         }
2224     }
2225     else {
2226         cmd->server->server_hostname = apr_pstrdup(cmd->pool, arg);
2227         port = 0;
2228     }
2229
2230     cmd->server->port = port;
2231     return NULL;
2232 }
2233
2234 static const char *set_signature_flag(cmd_parms *cmd, void *d_,
2235                                       const char *arg)
2236 {
2237     core_dir_config *d = d_;
2238     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2239
2240     if (err != NULL) {
2241         return err;
2242     }
2243
2244     if (strcasecmp(arg, "On") == 0) {
2245         d->server_signature = srv_sig_on;
2246     }
2247     else if (strcasecmp(arg, "Off") == 0) {
2248         d->server_signature = srv_sig_off;
2249     }
2250     else if (strcasecmp(arg, "EMail") == 0) {
2251         d->server_signature = srv_sig_withmail;
2252     }
2253     else {
2254         return "ServerSignature: use one of: off | on | email";
2255     }
2256
2257     return NULL;
2258 }
2259
2260 static const char *set_server_root(cmd_parms *cmd, void *dummy,
2261                                    const char *arg)
2262 {
2263     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2264
2265     if (err != NULL) {
2266         return err;
2267     }
2268
2269     if ((apr_filepath_merge((char**)&ap_server_root, NULL, arg,
2270                             APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS)
2271         || !ap_is_directory(cmd->pool, ap_server_root)) {
2272         return "ServerRoot must be a valid directory";
2273     }
2274
2275     return NULL;
2276 }
2277
2278 static const char *set_timeout(cmd_parms *cmd, void *dummy, const char *arg)
2279 {
2280     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2281
2282     if (err != NULL) {
2283         return err;
2284     }
2285
2286     cmd->server->timeout = apr_time_from_sec(atoi(arg));
2287     return NULL;
2288 }
2289
2290 static const char *set_allow2f(cmd_parms *cmd, void *d_, int arg)
2291 {
2292     core_dir_config *d = d_;
2293     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2294
2295     if (err != NULL) {
2296         return err;
2297     }
2298
2299     d->allow_encoded_slashes = arg != 0;
2300     return NULL;
2301 }
2302
2303 static const char *set_hostname_lookups(cmd_parms *cmd, void *d_,
2304                                         const char *arg)
2305 {
2306     core_dir_config *d = d_;
2307     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2308
2309     if (err != NULL) {
2310         return err;
2311     }
2312
2313     if (!strcasecmp(arg, "on")) {
2314         d->hostname_lookups = HOSTNAME_LOOKUP_ON;
2315     }
2316     else if (!strcasecmp(arg, "off")) {
2317         d->hostname_lookups = HOSTNAME_LOOKUP_OFF;
2318     }
2319     else if (!strcasecmp(arg, "double")) {
2320         d->hostname_lookups = HOSTNAME_LOOKUP_DOUBLE;
2321     }
2322     else {
2323         return "parameter must be 'on', 'off', or 'double'";
2324     }
2325
2326     return NULL;
2327 }
2328
2329 static const char *set_serverpath(cmd_parms *cmd, void *dummy,
2330                                   const char *arg)
2331 {
2332     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2333
2334     if (err != NULL) {
2335         return err;
2336     }
2337
2338     cmd->server->path = arg;
2339     cmd->server->pathlen = (int)strlen(arg);
2340     return NULL;
2341 }
2342
2343 static const char *set_content_md5(cmd_parms *cmd, void *d_, int arg)
2344 {
2345     core_dir_config *d = d_;
2346     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2347
2348     if (err != NULL) {
2349         return err;
2350     }
2351
2352     d->content_md5 = arg != 0;
2353     return NULL;
2354 }
2355
2356 static const char *set_accept_path_info(cmd_parms *cmd, void *d_, const char *arg)
2357 {
2358     core_dir_config *d = d_;
2359
2360     if (strcasecmp(arg, "on") == 0) {
2361         d->accept_path_info = AP_REQ_ACCEPT_PATH_INFO;
2362     }
2363     else if (strcasecmp(arg, "off") == 0) {
2364         d->accept_path_info = AP_REQ_REJECT_PATH_INFO;
2365     }
2366     else if (strcasecmp(arg, "default") == 0) {
2367         d->accept_path_info = AP_REQ_DEFAULT_PATH_INFO;
2368     }
2369     else {
2370         return "AcceptPathInfo must be set to on, off or default";
2371     }
2372
2373     return NULL;
2374 }
2375
2376 static const char *set_use_canonical_name(cmd_parms *cmd, void *d_,
2377                                           const char *arg)
2378 {
2379     core_dir_config *d = d_;
2380     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2381
2382     if (err != NULL) {
2383         return err;
2384     }
2385
2386     if (strcasecmp(arg, "on") == 0) {
2387         d->use_canonical_name = USE_CANONICAL_NAME_ON;
2388     }
2389     else if (strcasecmp(arg, "off") == 0) {
2390         d->use_canonical_name = USE_CANONICAL_NAME_OFF;
2391     }
2392     else if (strcasecmp(arg, "dns") == 0) {
2393         d->use_canonical_name = USE_CANONICAL_NAME_DNS;
2394     }
2395     else {
2396         return "parameter must be 'on', 'off', or 'dns'";
2397     }
2398
2399     return NULL;
2400 }
2401
2402
2403 static const char *include_config (cmd_parms *cmd, void *dummy,
2404                                    const char *name)
2405 {
2406     ap_directive_t *conftree = NULL;
2407     const char* conffile, *error;
2408     unsigned *recursion;
2409     void *data;
2410
2411     apr_pool_userdata_get(&data, "ap_include_sentinel", cmd->pool);
2412     if (data) {
2413         recursion = data;
2414     }
2415     else {
2416         data = recursion = apr_palloc(cmd->pool, sizeof(*recursion));
2417         *recursion = 0;
2418         apr_pool_userdata_setn(data, "ap_include_sentinel", NULL, cmd->pool);
2419     }
2420
2421     if (++*recursion > AP_MAX_INCLUDE_DEPTH) {
2422         *recursion = 0;
2423         return apr_psprintf(cmd->pool, "Exceeded maximum include depth of %u. "
2424                             "You have probably a recursion somewhere.",
2425                             AP_MAX_INCLUDE_DEPTH);
2426     }
2427
2428     conffile = ap_server_root_relative(cmd->pool, name);
2429     if (!conffile) {
2430         *recursion = 0;
2431         return apr_pstrcat(cmd->pool, "Invalid Include path ", 
2432                            name, NULL);
2433     }
2434
2435     error = ap_process_resource_config(cmd->server, conffile,
2436                                        &conftree, cmd->pool, cmd->temp_pool);
2437     if (error) {
2438         *recursion = 0;
2439         return error;
2440     }
2441
2442     *(ap_directive_t **)dummy = conftree;
2443
2444     /* recursion level done */
2445     if (*recursion) {
2446         --*recursion;
2447     }
2448
2449     return NULL;
2450 }
2451
2452 static const char *set_loglevel(cmd_parms *cmd, void *dummy, const char *arg)
2453 {
2454     char *str;
2455
2456     const char *err = ap_check_cmd_context(cmd,
2457                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2458     if (err != NULL) {
2459         return err;
2460     }
2461
2462     if ((str = ap_getword_conf(cmd->pool, &arg))) {
2463         if (!strcasecmp(str, "emerg")) {
2464             cmd->server->loglevel = APLOG_EMERG;
2465         }
2466         else if (!strcasecmp(str, "alert")) {
2467             cmd->server->loglevel = APLOG_ALERT;
2468         }
2469         else if (!strcasecmp(str, "crit")) {
2470             cmd->server->loglevel = APLOG_CRIT;
2471         }
2472         else if (!strcasecmp(str, "error")) {
2473             cmd->server->loglevel = APLOG_ERR;
2474         }
2475         else if (!strcasecmp(str, "warn")) {
2476             cmd->server->loglevel = APLOG_WARNING;
2477         }
2478         else if (!strcasecmp(str, "notice")) {
2479             cmd->server->loglevel = APLOG_NOTICE;
2480         }
2481         else if (!strcasecmp(str, "info")) {
2482             cmd->server->loglevel = APLOG_INFO;
2483         }
2484         else if (!strcasecmp(str, "debug")) {
2485             cmd->server->loglevel = APLOG_DEBUG;
2486         }
2487         else {
2488             return "LogLevel requires level keyword: one of "
2489                    "emerg/alert/crit/error/warn/notice/info/debug";
2490         }
2491     }
2492     else {
2493         return "LogLevel requires level keyword";
2494     }
2495
2496     return NULL;
2497 }
2498
2499 AP_DECLARE(const char *) ap_psignature(const char *prefix, request_rec *r)
2500 {
2501     char sport[20];
2502     core_dir_config *conf;
2503
2504     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
2505                                                    &core_module);
2506     if ((conf->server_signature == srv_sig_off)
2507             || (conf->server_signature == srv_sig_unset)) {
2508         return "";
2509     }
2510
2511     apr_snprintf(sport, sizeof sport, "%u", (unsigned) ap_get_server_port(r));
2512
2513     if (conf->server_signature == srv_sig_withmail) {
2514         return apr_pstrcat(r->pool, prefix, "<address>", 
2515                            ap_get_server_version(),
2516                            " Server at <a href=\"",
2517                            ap_is_url(r->server->server_admin) ? "" : "mailto:",
2518                            ap_escape_html(r->pool, r->server->server_admin),
2519                            "\">",
2520                            ap_escape_html(r->pool, ap_get_server_name(r)),
2521                            "</a> Port ", sport,
2522                            "</address>\n", NULL);
2523     }
2524
2525     return apr_pstrcat(r->pool, prefix, "<address>", ap_get_server_version(),
2526                        " Server at ",
2527                        ap_escape_html(r->pool, ap_get_server_name(r)),
2528                        " Port ", sport,
2529                        "</address>\n", NULL);
2530 }
2531
2532 /*
2533  * Load an authorisation realm into our location configuration, applying the
2534  * usual rules that apply to realms.
2535  */
2536 static const char *set_authname(cmd_parms *cmd, void *mconfig,
2537                                 const char *word1)
2538 {
2539     core_dir_config *aconfig = (core_dir_config *)mconfig;
2540
2541     aconfig->ap_auth_name = ap_escape_quotes(cmd->pool, word1);
2542     return NULL;
2543 }
2544
2545 /*
2546  * Handle a request to include the server's OS platform in the Server
2547  * response header field (the ServerTokens directive).  Unfortunately
2548  * this requires a new global in order to communicate the setting back to
2549  * http_main so it can insert the information in the right place in the
2550  * string.
2551  */
2552
2553 static char *server_version = NULL;
2554 static int version_locked = 0;
2555
2556 enum server_token_type {
2557     SrvTk_MAJOR,        /* eg: Apache/2 */
2558     SrvTk_MINOR,        /* eg. Apache/2.0 */
2559     SrvTk_MINIMAL,      /* eg: Apache/2.0.41 */
2560     SrvTk_OS,           /* eg: Apache/2.0.41 (UNIX) */
2561     SrvTk_FULL,         /* eg: Apache/2.0.41 (UNIX) PHP/4.2.2 FooBar/1.2b */
2562     SrvTk_PRODUCT_ONLY  /* eg: Apache */
2563 };
2564 static enum server_token_type ap_server_tokens = SrvTk_FULL;
2565
2566 static apr_status_t reset_version(void *dummy)
2567 {
2568     version_locked = 0;
2569     ap_server_tokens = SrvTk_FULL;
2570     server_version = NULL;
2571     return APR_SUCCESS;
2572 }
2573
2574 AP_DECLARE(void) ap_get_server_revision(ap_version_t *version)
2575 {
2576     version->major = AP_SERVER_MAJORVERSION_NUMBER;
2577     version->minor = AP_SERVER_MINORVERSION_NUMBER;
2578     version->patch = AP_SERVER_PATCHLEVEL_NUMBER;
2579     version->add_string = AP_SERVER_ADD_STRING;
2580 }
2581
2582 AP_DECLARE(const char *) ap_get_server_version(void)
2583 {
2584     return (server_version ? server_version : AP_SERVER_BASEVERSION);
2585 }
2586
2587 AP_DECLARE(void) ap_add_version_component(apr_pool_t *pconf, const char *component)
2588 {
2589     if (! version_locked) {
2590         /*
2591          * If the version string is null, register our cleanup to reset the
2592          * pointer on pool destruction. We also know that, if NULL,
2593          * we are adding the original SERVER_BASEVERSION string.
2594          */
2595         if (server_version == NULL) {
2596             apr_pool_cleanup_register(pconf, NULL, reset_version,
2597                                       apr_pool_cleanup_null);
2598             server_version = apr_pstrdup(pconf, component);
2599         }
2600         else {
2601             /*
2602              * Tack the given component identifier to the end of
2603              * the existing string.
2604              */
2605             server_version = apr_pstrcat(pconf, server_version, " ",
2606                                          component, NULL);
2607         }
2608     }
2609 }
2610
2611 /*
2612  * This routine adds the real server base identity to the version string,
2613  * and then locks out changes until the next reconfig.
2614  */
2615 static void ap_set_version(apr_pool_t *pconf)
2616 {
2617     if (ap_server_tokens == SrvTk_PRODUCT_ONLY) {
2618         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT);
2619     }
2620     else if (ap_server_tokens == SrvTk_MINIMAL) {
2621         ap_add_version_component(pconf, AP_SERVER_BASEVERSION);
2622     }
2623     else if (ap_server_tokens == SrvTk_MINOR) {
2624         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MINORREVISION);
2625     }
2626     else if (ap_server_tokens == SrvTk_MAJOR) {
2627         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MAJORVERSION);
2628     }
2629     else {
2630         ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ")");
2631     }
2632
2633     /*
2634      * Lock the server_version string if we're not displaying
2635      * the full set of tokens
2636      */
2637     if (ap_server_tokens != SrvTk_FULL) {
2638         version_locked++;
2639     }
2640 }
2641
2642 static const char *set_serv_tokens(cmd_parms *cmd, void *dummy,
2643                                    const char *arg)
2644 {
2645     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2646
2647     if (err != NULL) {
2648         return err;
2649     }
2650
2651     if (!strcasecmp(arg, "OS")) {
2652         ap_server_tokens = SrvTk_OS;
2653     }
2654     else if (!strcasecmp(arg, "Min") || !strcasecmp(arg, "Minimal")) {
2655         ap_server_tokens = SrvTk_MINIMAL;
2656     }
2657     else if (!strcasecmp(arg, "Major")) {
2658         ap_server_tokens = SrvTk_MAJOR;
2659     }
2660     else if (!strcasecmp(arg, "Minor") ) {
2661         ap_server_tokens = SrvTk_MINOR;
2662     }
2663     else if (!strcasecmp(arg, "Prod") || !strcasecmp(arg, "ProductOnly")) {
2664         ap_server_tokens = SrvTk_PRODUCT_ONLY;
2665     }
2666     else {
2667         ap_server_tokens = SrvTk_FULL;
2668     }
2669
2670     return NULL;
2671 }
2672
2673 static const char *set_limit_req_line(cmd_parms *cmd, void *dummy,
2674                                       const char *arg)
2675 {
2676     const char *err = ap_check_cmd_context(cmd,
2677                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2678     int lim;
2679
2680     if (err != NULL) {
2681         return err;
2682     }
2683
2684     lim = atoi(arg);
2685     if (lim < 0) {
2686         return apr_pstrcat(cmd->temp_pool, "LimitRequestLine \"", arg,
2687                            "\" must be a non-negative integer", NULL);
2688     }
2689
2690     cmd->server->limit_req_line = lim;
2691     return NULL;
2692 }
2693
2694 static const char *set_limit_req_fieldsize(cmd_parms *cmd, void *dummy,
2695                                            const char *arg)
2696 {
2697     const char *err = ap_check_cmd_context(cmd,
2698                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2699     int lim;
2700
2701     if (err != NULL) {
2702         return err;
2703     }
2704
2705     lim = atoi(arg);
2706     if (lim < 0) {
2707         return apr_pstrcat(cmd->temp_pool, "LimitRequestFieldsize \"", arg,
2708                           "\" must be a non-negative integer",
2709                           NULL);
2710     }
2711
2712     cmd->server->limit_req_fieldsize = lim;
2713     return NULL;
2714 }
2715
2716 static const char *set_limit_req_fields(cmd_parms *cmd, void *dummy,
2717                                         const char *arg)
2718 {
2719     const char *err = ap_check_cmd_context(cmd,
2720                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2721     int lim;
2722
2723     if (err != NULL) {
2724         return err;
2725     }
2726
2727     lim = atoi(arg);
2728     if (lim < 0) {
2729         return apr_pstrcat(cmd->temp_pool, "LimitRequestFields \"", arg,
2730                            "\" must be a non-negative integer (0 = no limit)",
2731                            NULL);
2732     }
2733
2734     cmd->server->limit_req_fields = lim;
2735     return NULL;
2736 }
2737
2738 static const char *set_limit_req_body(cmd_parms *cmd, void *conf_,
2739                                       const char *arg)
2740 {
2741     core_dir_config *conf = conf_;
2742     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2743     char *errp;
2744
2745     if (err != NULL) {
2746         return err;
2747     }
2748
2749     if (APR_SUCCESS != apr_strtoff(&conf->limit_req_body, arg, &errp, 10)) {
2750         return "LimitRequestBody argument is not parsable.";
2751     }
2752     if (*errp || conf->limit_req_body < 0) {
2753         return "LimitRequestBody requires a non-negative integer.";
2754     }
2755
2756     return NULL;
2757 }
2758
2759 static const char *set_limit_xml_req_body(cmd_parms *cmd, void *conf_,
2760                                           const char *arg)
2761 {
2762     core_dir_config *conf = conf_;
2763     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2764
2765     if (err != NULL) {
2766         return err;
2767     }
2768
2769     conf->limit_xml_body = atol(arg);
2770     if (conf->limit_xml_body < 0)
2771         return "LimitXMLRequestBody requires a non-negative integer.";
2772
2773     return NULL;
2774 }
2775
2776 AP_DECLARE(size_t) ap_get_limit_xml_body(const request_rec *r)
2777 {
2778     core_dir_config *conf;
2779
2780     conf = ap_get_module_config(r->per_dir_config, &core_module);
2781     if (conf->limit_xml_body == AP_LIMIT_UNSET)
2782         return AP_DEFAULT_LIMIT_XML_BODY;
2783
2784     return (size_t)conf->limit_xml_body;
2785 }
2786
2787 #if !defined (RLIMIT_CPU) || !(defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)) || !defined (RLIMIT_NPROC)
2788 static const char *no_set_limit(cmd_parms *cmd, void *conf_,
2789                                 const char *arg, const char *arg2)
2790 {
2791     ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server,
2792                 "%s not supported on this platform", cmd->cmd->name);
2793
2794     return NULL;
2795 }
2796 #endif
2797
2798 #ifdef RLIMIT_CPU
2799 static const char *set_limit_cpu(cmd_parms *cmd, void *conf_,
2800                                  const char *arg, const char *arg2)
2801 {
2802     core_dir_config *conf = conf_;
2803
2804     unixd_set_rlimit(cmd, &conf->limit_cpu, arg, arg2, RLIMIT_CPU);
2805     return NULL;
2806 }
2807 #endif
2808
2809 #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)
2810 static const char *set_limit_mem(cmd_parms *cmd, void *conf_,
2811                                  const char *arg, const char * arg2)
2812 {
2813     core_dir_config *conf = conf_;
2814
2815 #if defined(RLIMIT_AS)
2816     unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2 ,RLIMIT_AS);
2817 #elif defined(RLIMIT_DATA)
2818     unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_DATA);
2819 #elif defined(RLIMIT_VMEM)
2820     unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_VMEM);
2821 #endif
2822
2823     return NULL;
2824 }
2825 #endif
2826
2827 #ifdef RLIMIT_NPROC
2828 static const char *set_limit_nproc(cmd_parms *cmd, void *conf_,
2829                                    const char *arg, const char * arg2)
2830 {
2831     core_dir_config *conf = conf_;
2832
2833     unixd_set_rlimit(cmd, &conf->limit_nproc, arg, arg2, RLIMIT_NPROC);
2834     return NULL;
2835 }
2836 #endif
2837
2838 static const char *set_recursion_limit(cmd_parms *cmd, void *dummy,
2839                                        const char *arg1, const char *arg2)
2840 {
2841     core_server_config *conf = ap_get_module_config(cmd->server->module_config,
2842                                                     &core_module);
2843     int limit = atoi(arg1);
2844
2845     if (limit <= 0) {
2846         return "The recursion limit must be greater than zero.";
2847     }
2848     if (limit < 4) {
2849         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
2850                      "Limiting internal redirects to very low numbers may "
2851                      "cause normal requests to fail.");
2852     }
2853
2854     conf->redirect_limit = limit;
2855
2856     if (arg2) {
2857         limit = atoi(arg2);
2858
2859         if (limit <= 0) {
2860             return "The recursion limit must be greater than zero.";
2861         }
2862         if (limit < 4) {
2863             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
2864                          "Limiting the subrequest depth to a very low level may"
2865                          " cause normal requests to fail.");
2866         }
2867     }
2868
2869     conf->subreq_limit = limit;
2870
2871     return NULL;
2872 }
2873
2874 static void log_backtrace(const request_rec *r)
2875 {
2876     const request_rec *top = r;
2877
2878     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
2879                   "r->uri = %s", r->uri ? r->uri : "(unexpectedly NULL)");
2880
2881     while (top && (top->prev || top->main)) {
2882         if (top->prev) {
2883             top = top->prev;
2884             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
2885                           "redirected from r->uri = %s",
2886                           top->uri ? top->uri : "(unexpectedly NULL)");
2887         }
2888
2889         if (!top->prev && top->main) {
2890             top = top->main;
2891             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
2892                           "subrequested from r->uri = %s",
2893                           top->uri ? top->uri : "(unexpectedly NULL)");
2894         }
2895     }
2896 }
2897
2898 /*
2899  * check whether redirect limit is reached
2900  */
2901 AP_DECLARE(int) ap_is_recursion_limit_exceeded(const request_rec *r)
2902 {
2903     core_server_config *conf = ap_get_module_config(r->server->module_config,
2904                                                     &core_module);
2905     const request_rec *top = r;
2906     int redirects = 0, subreqs = 0;
2907     int rlimit = conf->redirect_limit
2908                  ? conf->redirect_limit
2909                  : AP_DEFAULT_MAX_INTERNAL_REDIRECTS;
2910     int slimit = conf->subreq_limit
2911                  ? conf->subreq_limit
2912                  : AP_DEFAULT_MAX_SUBREQ_DEPTH;
2913
2914
2915     while (top->prev || top->main) {
2916         if (top->prev) {
2917             if (++redirects >= rlimit) {
2918                 /* uuh, too much. */
2919                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
2920                               "Request exceeded the limit of %d internal "
2921                               "redirects due to probable configuration error. "
2922                               "Use 'LimitInternalRecursion' to increase the "
2923                               "limit if necessary. Use 'LogLevel debug' to get "
2924                               "a backtrace.", rlimit);
2925
2926                 /* post backtrace */
2927                 log_backtrace(r);
2928
2929                 /* return failure */
2930                 return 1;
2931             }
2932
2933             top = top->prev;
2934         }
2935
2936         if (!top->prev && top->main) {
2937             if (++subreqs >= slimit) {
2938                 /* uuh, too much. */
2939                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
2940                               "Request exceeded the limit of %d subrequest "
2941                               "nesting levels due to probable confguration "
2942                               "error. Use 'LimitInternalRecursion' to increase "
2943                               "the limit if necessary. Use 'LogLevel debug' to "
2944                               "get a backtrace.", slimit);
2945
2946                 /* post backtrace */
2947                 log_backtrace(r);
2948
2949                 /* return failure */
2950                 return 1;
2951             }
2952
2953             top = top->main;
2954         }
2955     }
2956
2957     /* recursion state: ok */
2958     return 0;
2959 }
2960
2961 static const char *add_ct_output_filters(cmd_parms *cmd, void *conf_,
2962                                          const char *arg, const char *arg2)
2963 {
2964     core_dir_config *conf = conf_;
2965     ap_filter_rec_t *old, *new = NULL;
2966     const char *filter_name;
2967
2968     if (!conf->ct_output_filters) {
2969         conf->ct_output_filters = apr_hash_make(cmd->pool);
2970         old = NULL;
2971     }
2972     else {
2973         old = (ap_filter_rec_t*) apr_hash_get(conf->ct_output_filters, arg2,
2974                                               APR_HASH_KEY_STRING);
2975         /* find last entry */
2976         if (old) {
2977             while (old->next) {
2978                 old = old->next;
2979             }
2980         }
2981     }
2982
2983     while (*arg &&
2984            (filter_name = ap_getword(cmd->pool, &arg, ';')) &&
2985            strcmp(filter_name, "")) {
2986         new = apr_pcalloc(cmd->pool, sizeof(ap_filter_rec_t));
2987         new->name = filter_name;
2988
2989         /* We found something, so let's append it.  */
2990         if (old) {
2991             old->next = new;
2992         }
2993         else {
2994             apr_hash_set(conf->ct_output_filters, arg2,
2995                          APR_HASH_KEY_STRING, new);
2996         }
2997         old = new;
2998     }
2999
3000     if (!new) {
3001         return "invalid filter name";
3002     }
3003     
3004     return NULL;
3005 }
3006 /* 
3007  * Insert filters requested by the AddOutputFilterByType 
3008  * configuration directive. We cannot add filters based 
3009  * on content-type until after the handler has started 
3010  * to run. Only then do we reliably know the content-type.
3011  */
3012 void ap_add_output_filters_by_type(request_rec *r)
3013 {
3014     core_dir_config *conf;
3015     const char *ctype;
3016
3017     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
3018                                                    &core_module);
3019
3020     /* We can't do anything with proxy requests, no content-types or if
3021      * we don't have a filter configured.
3022      */
3023     if (r->proxyreq != PROXYREQ_NONE || !r->content_type ||
3024         !conf->ct_output_filters) {
3025         return;
3026     }
3027
3028     /* remove c-t decoration */
3029     ctype = ap_field_noparam(r->pool, r->content_type);
3030     if (ctype) {
3031         ap_filter_rec_t *ct_filter;
3032         ct_filter = apr_hash_get(conf->ct_output_filters, ctype,
3033                                  APR_HASH_KEY_STRING);
3034         while (ct_filter) {
3035             ap_add_output_filter(ct_filter->name, NULL, r, r->connection);
3036             ct_filter = ct_filter->next;
3037         }
3038     }
3039
3040     return;
3041 }
3042
3043 /* Note --- ErrorDocument will now work from .htaccess files.
3044  * The AllowOverride of Fileinfo allows webmasters to turn it off
3045  */
3046
3047 static const command_rec core_cmds[] = {
3048
3049 /* Old access config file commands */
3050
3051 AP_INIT_RAW_ARGS("<Directory", dirsection, NULL, RSRC_CONF,
3052   "Container for directives affecting resources located in the specified "
3053   "directories"),
3054 AP_INIT_RAW_ARGS("<Location", urlsection, NULL, RSRC_CONF,
3055   "Container for directives affecting resources accessed through the "
3056   "specified URL paths"),
3057 AP_INIT_RAW_ARGS("<VirtualHost", virtualhost_section, NULL, RSRC_CONF,
3058   "Container to map directives to a particular virtual host, takes one or "
3059   "more host addresses"),
3060 AP_INIT_RAW_ARGS("<Files", filesection, NULL, OR_ALL,
3061   "Container for directives affecting files matching specified patterns"),
3062 AP_INIT_RAW_ARGS("<Limit", ap_limit_section, NULL, OR_ALL,
3063   "Container for authentication directives when accessed using specified HTTP "
3064   "methods"),
3065 AP_INIT_RAW_ARGS("<LimitExcept", ap_limit_section, (void*)1, OR_ALL,
3066   "Container for authentication directives to be applied when any HTTP "
3067   "method other than those specified is used to access the resource"),
3068 AP_INIT_TAKE1("<IfModule", start_ifmod, NULL, EXEC_ON_READ | OR_ALL,
3069   "Container for directives based on existance of specified modules"),
3070 AP_INIT_TAKE1("<IfDefine", start_ifdefine, NULL, EXEC_ON_READ | OR_ALL,
3071   "Container for directives based on existance of command line defines"),
3072 AP_INIT_RAW_ARGS("<DirectoryMatch", dirsection, (void*)1, RSRC_CONF,
3073   "Container for directives affecting resources located in the "
3074   "specified directories"),
3075 AP_INIT_RAW_ARGS("<LocationMatch", urlsection, (void*)1, RSRC_CONF,
3076   "Container for directives affecting resources accessed through the "
3077   "specified URL paths"),
3078 AP_INIT_RAW_ARGS("<FilesMatch", filesection, (void*)1, OR_ALL,
3079   "Container for directives affecting files matching specified patterns"),
3080 AP_INIT_TAKE1("AuthType", ap_set_string_slot,
3081   (void*)APR_OFFSETOF(core_dir_config, ap_auth_type), OR_AUTHCFG,
3082   "An HTTP authorization type (e.g., \"Basic\")"),
3083 AP_INIT_TAKE1("AuthName", set_authname, NULL, OR_AUTHCFG,
3084   "The authentication realm (e.g. \"Members Only\")"),
3085 AP_INIT_RAW_ARGS("Require", require, NULL, OR_AUTHCFG,
3086   "Selects which authenticated users or groups may access a protected space"),
3087 AP_INIT_TAKE1("Satisfy", satisfy, NULL, OR_AUTHCFG,
3088   "access policy if both allow and require used ('all' or 'any')"),
3089 #ifdef GPROF
3090 AP_INIT_TAKE1("GprofDir", set_gprof_dir, NULL, RSRC_CONF,
3091   "Directory to plop gmon.out files"),
3092 #endif
3093 AP_INIT_TAKE1("AddDefaultCharset", set_add_default_charset, NULL, OR_FILEINFO,
3094   "The name of the default charset to add to any Content-Type without one or 'Off' to disable"),
3095 AP_INIT_TAKE1("AcceptPathInfo", set_accept_path_info, NULL, OR_FILEINFO,
3096   "Set to on or off for PATH_INFO to be accepted by handlers, or default for the per-handler preference"),
3097
3098 /* Old resource config file commands */
3099
3100 AP_INIT_RAW_ARGS("AccessFileName", set_access_name, NULL, RSRC_CONF,
3101   "Name(s) of per-directory config files (default: .htaccess)"),
3102 AP_INIT_TAKE1("DocumentRoot", set_document_root, NULL, RSRC_CONF,
3103   "Root directory of the document tree"),
3104 AP_INIT_TAKE2("ErrorDocument", set_error_document, NULL, OR_FILEINFO,
3105   "Change responses for HTTP errors"),
3106 AP_INIT_RAW_ARGS("AllowOverride", set_override, NULL, ACCESS_CONF,
3107   "Controls what groups of directives can be configured by per-directory "
3108   "config files"),
3109 AP_INIT_RAW_ARGS("Options", set_options, NULL, OR_OPTIONS,
3110   "Set a number of attributes for a given directory"),
3111 AP_INIT_TAKE1("DefaultType", ap_set_string_slot,
3112   (void*)APR_OFFSETOF(core_dir_config, ap_default_type),
3113   OR_FILEINFO, "the default MIME type for untypable files"),
3114 AP_INIT_RAW_ARGS("FileETag", set_etag_bits, NULL, OR_FILEINFO,
3115   "Specify components used to construct a file's ETag"),
3116 AP_INIT_TAKE1("EnableMMAP", set_enable_mmap, NULL, OR_FILEINFO,
3117   "Controls whether memory-mapping may be used to read files"),
3118 AP_INIT_TAKE1("EnableSendfile", set_enable_sendfile, NULL, OR_FILEINFO,
3119   "Controls whether sendfile may be used to transmit files"),
3120
3121 /* Old server config file commands */
3122
3123 AP_INIT_TAKE1("Port", ap_set_deprecated, NULL, RSRC_CONF,
3124   "Port was replaced with Listen in Apache 2.0"),
3125 AP_INIT_TAKE1("HostnameLookups", set_hostname_lookups, NULL,
3126   ACCESS_CONF|RSRC_CONF,
3127   "\"on\" to enable, \"off\" to disable reverse DNS lookups, or \"double\" to "
3128   "enable double-reverse DNS lookups"),
3129 AP_INIT_TAKE1("ServerAdmin", set_server_string_slot,
3130   (void *)APR_OFFSETOF(server_rec, server_admin), RSRC_CONF,
3131   "The email address of the server administrator"),
3132 AP_INIT_TAKE1("ServerName", server_hostname_port, NULL, RSRC_CONF,
3133   "The hostname and port of the server"),
3134 AP_INIT_TAKE1("ServerSignature", set_signature_flag, NULL, OR_ALL,
3135   "En-/disable server signature (on|off|email)"),
3136 AP_INIT_TAKE1("ServerRoot", set_server_root, NULL, RSRC_CONF | EXEC_ON_READ,
3137   "Common directory of server-related files (logs, confs, etc.)"),
3138 AP_INIT_TAKE1("ErrorLog", set_server_string_slot,
3139   (void *)APR_OFFSETOF(server_rec, error_fname), RSRC_CONF,
3140   "The filename of the error log"),
3141 AP_INIT_RAW_ARGS("ServerAlias", set_server_alias, NULL, RSRC_CONF,
3142   "A name or names alternately used to access the server"),
3143 AP_INIT_TAKE1("ServerPath", set_serverpath, NULL, RSRC_CONF,
3144   "The pathname the server can be reached at"),
3145 AP_INIT_TAKE1("Timeout", set_timeout, NULL, RSRC_CONF,
3146   "Timeout duration (sec)"),
3147 AP_INIT_FLAG("ContentDigest", set_content_md5, NULL, OR_OPTIONS,
3148   "whether or not to send a Content-MD5 header with each request"),
3149 AP_INIT_TAKE1("UseCanonicalName", set_use_canonical_name, NULL,
3150   RSRC_CONF|ACCESS_CONF,
3151   "How to work out the ServerName : Port when constructing URLs"),
3152 /* TODO: RlimitFoo should all be part of mod_cgi, not in the core */
3153 /* TODO: ListenBacklog in MPM */
3154 AP_INIT_TAKE1("Include", include_config, NULL,
3155   (RSRC_CONF | ACCESS_CONF | EXEC_ON_READ),
3156   "Name of the config file to be included"),
3157 AP_INIT_TAKE1("LogLevel", set_loglevel, NULL, RSRC_CONF,
3158   "Level of verbosity in error logging"),
3159 AP_INIT_TAKE1("NameVirtualHost", ap_set_name_virtual_host, NULL, RSRC_CONF,
3160   "A numeric IP address:port, or the name of a host"),
3161 AP_INIT_TAKE1("ServerTokens", set_serv_tokens, NULL, RSRC_CONF,
3162   "Determine tokens displayed in the Server: header - Min(imal), OS or Full"),
3163 AP_INIT_TAKE1("LimitRequestLine", set_limit_req_line, NULL, RSRC_CONF,
3164   "Limit on maximum size of an HTTP request line"),
3165 AP_INIT_TAKE1("LimitRequestFieldsize", set_limit_req_fieldsize, NULL,
3166   RSRC_CONF,
3167   "Limit on maximum size of an HTTP request header field"),
3168 AP_INIT_TAKE1("LimitRequestFields", set_limit_req_fields, NULL, RSRC_CONF,
3169   "Limit (0 = unlimited) on max number of header fields in a request message"),
3170 AP_INIT_TAKE1("LimitRequestBody", set_limit_req_body,
3171   (void*)APR_OFFSETOF(core_dir_config, limit_req_body), OR_ALL,
3172   "Limit (in bytes) on maximum size of request message body"),
3173 AP_INIT_TAKE1("LimitXMLRequestBody", set_limit_xml_req_body, NULL, OR_ALL,
3174               "Limit (in bytes) on maximum size of an XML-based request "
3175               "body"),
3176
3177 /* System Resource Controls */
3178 #ifdef RLIMIT_CPU
3179 AP_INIT_TAKE12("RLimitCPU", set_limit_cpu,
3180   (void*)APR_OFFSETOF(core_dir_config, limit_cpu),
3181   OR_ALL, "Soft/hard limits for max CPU usage in seconds"),
3182 #else
3183 AP_INIT_TAKE12("RLimitCPU", no_set_limit, NULL,
3184   OR_ALL, "Soft/hard limits for max CPU usage in seconds"),
3185 #endif
3186 #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined (RLIMIT_AS)
3187 AP_INIT_TAKE12("RLimitMEM", set_limit_mem,
3188   (void*)APR_OFFSETOF(core_dir_config, limit_mem),
3189   OR_ALL, "Soft/hard limits for max memory usage per process"),
3190 #else
3191 AP_INIT_TAKE12("RLimitMEM", no_set_limit, NULL,
3192   OR_ALL, "Soft/hard limits for max memory usage per process"),
3193 #endif
3194 #ifdef RLIMIT_NPROC
3195 AP_INIT_TAKE12("RLimitNPROC", set_limit_nproc,
3196   (void*)APR_OFFSETOF(core_dir_config, limit_nproc),
3197   OR_ALL, "soft/hard limits for max number of processes per uid"),
3198 #else
3199 AP_INIT_TAKE12("RLimitNPROC", no_set_limit, NULL,
3200    OR_ALL, "soft/hard limits for max number of processes per uid"),
3201 #endif
3202
3203 /* internal recursion stopper */
3204 AP_INIT_TAKE12("LimitInternalRecursion", set_recursion_limit, NULL, RSRC_CONF,
3205               "maximum recursion depth of internal redirects and subrequests"),
3206
3207 AP_INIT_TAKE1("ForceType", ap_set_string_slot_lower,
3208        (void *)APR_OFFSETOF(core_dir_config, mime_type), OR_FILEINFO,
3209      "a mime type that overrides other configured type"),
3210 AP_INIT_TAKE1("SetHandler", ap_set_string_slot_lower,
3211        (void *)APR_OFFSETOF(core_dir_config, handler), OR_FILEINFO,
3212    "a handler name that overrides any other configured handler"),
3213 AP_INIT_TAKE1("SetOutputFilter", ap_set_string_slot,
3214        (void *)APR_OFFSETOF(core_dir_config, output_filters), OR_FILEINFO,
3215    "filter (or ; delimited list of filters) to be run on the request content"),
3216 AP_INIT_TAKE1("SetInputFilter", ap_set_string_slot,
3217        (void *)APR_OFFSETOF(core_dir_config, input_filters), OR_FILEINFO,
3218    "filter (or ; delimited list of filters) to be run on the request body"),
3219 AP_INIT_ITERATE2("AddOutputFilterByType", add_ct_output_filters,
3220        (void *)APR_OFFSETOF(core_dir_config, ct_output_filters), OR_FILEINFO,
3221      "output filter name followed by one or more content-types"),
3222 AP_INIT_FLAG("AllowEncodedSlashes", set_allow2f, NULL, RSRC_CONF,
3223              "Allow URLs containing '/' encoded as '%2F'"),
3224
3225 /*
3226  * These are default configuration directives that mpms can/should
3227  * pay attention to. If an mpm wishes to use these, they should
3228  * #defined them in mpm.h.
3229  */
3230 #ifdef AP_MPM_WANT_SET_PIDFILE
3231 AP_INIT_TAKE1("PidFile",  ap_mpm_set_pidfile, NULL, RSRC_CONF,
3232               "A file for logging the server process ID"),
3233 #endif
3234 #ifdef AP_MPM_WANT_SET_SCOREBOARD
3235 AP_INIT_TAKE1("ScoreBoardFile", ap_mpm_set_scoreboard, NULL, RSRC_CONF,
3236               "A file for Apache to maintain runtime process management information"),
3237 #endif
3238 #ifdef AP_MPM_WANT_SET_LOCKFILE
3239 AP_INIT_TAKE1("LockFile",  ap_mpm_set_lockfile, NULL, RSRC_CONF,
3240               "The lockfile used when Apache needs to lock the accept() call"),
3241 #endif
3242 #ifdef AP_MPM_WANT_SET_MAX_REQUESTS
3243 AP_INIT_TAKE1("MaxRequestsPerChild", ap_mpm_set_max_requests, NULL, RSRC_CONF,
3244               "Maximum number of requests a particular child serves before dying."),
3245 #endif
3246 #ifdef AP_MPM_WANT_SET_COREDUMPDIR
3247 AP_INIT_TAKE1("CoreDumpDirectory", ap_mpm_set_coredumpdir, NULL, RSRC_CONF,
3248               "The location of the directory Apache changes to before dumping core"),
3249 #endif
3250 #ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
3251 AP_INIT_TAKE1("AcceptMutex", ap_mpm_set_accept_lock_mech, NULL, RSRC_CONF,
3252               ap_valid_accept_mutex_string),
3253 #endif
3254 #ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
3255 AP_INIT_TAKE1("MaxMemFree", ap_mpm_set_max_mem_free, NULL, RSRC_CONF,
3256               "Maximum number of 1k blocks a particular childs allocator may hold."),
3257 #endif
3258 #ifdef AP_MPM_WANT_SET_STACKSIZE
3259 AP_INIT_TAKE1("ThreadStackSize", ap_mpm_set_thread_stacksize, NULL, RSRC_CONF,
3260               "Size in bytes of stack used by threads handling client connections"),
3261 #endif
3262 #if AP_ENABLE_EXCEPTION_HOOK
3263 AP_INIT_TAKE1("EnableExceptionHook", ap_mpm_set_exception_hook, NULL, RSRC_CONF,
3264               "Controls whether exception hook may be called after a crash"),
3265 #endif
3266 { NULL }
3267 };
3268
3269 /*****************************************************************
3270  *
3271  * Core handlers for various phases of server operation...
3272  */
3273
3274 AP_DECLARE_NONSTD(int) ap_core_translate(request_rec *r)
3275 {
3276     void *sconf = r->server->module_config;
3277     core_server_config *conf = ap_get_module_config(sconf, &core_module);
3278     apr_status_t rv;
3279
3280     /* XXX this seems too specific, this should probably become
3281      * some general-case test
3282      */
3283     if (r->proxyreq) {
3284         return HTTP_FORBIDDEN;
3285     }
3286     if (!r->uri || ((r->uri[0] != '/') && strcmp(r->uri, "*"))) {
3287         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3288                      "Invalid URI in request %s", r->the_request);
3289         return HTTP_BAD_REQUEST;
3290     }
3291
3292     if (r->server->path
3293         && !strncmp(r->uri, r->server->path, r->server->pathlen)
3294         && (r->server->path[r->server->pathlen - 1] == '/'
3295             || r->uri[r->server->pathlen] == '/'
3296             || r->uri[r->server->pathlen] == '\0')) 
3297     {
3298         /* skip all leading /'s (e.g. http://localhost///foo) 
3299          * so we are looking at only the relative path.
3300          */
3301         char *path = r->uri + r->server->pathlen;
3302         while (*path == '/') {
3303             ++path;
3304         }
3305         if ((rv = apr_filepath_merge(&r->filename, conf->ap_document_root, path,
3306                                      APR_FILEPATH_TRUENAME
3307                                    | APR_FILEPATH_SECUREROOT, r->pool))
3308                     != APR_SUCCESS) {
3309             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
3310                          "Cannot map %s to file", r->the_request);
3311             return HTTP_FORBIDDEN;
3312         }
3313         r->canonical_filename = r->filename;
3314     }
3315     else {
3316         /*
3317          * Make sure that we do not mess up the translation by adding two
3318          * /'s in a row.  This happens under windows when the document
3319          * root ends with a /
3320          */
3321         /* skip all leading /'s (e.g. http://localhost///foo) 
3322          * so we are looking at only the relative path.
3323          */
3324         char *path = r->uri;
3325         while (*path == '/') {
3326             ++path;
3327         }
3328         if ((rv = apr_filepath_merge(&r->filename, conf->ap_document_root, path,
3329                                      APR_FILEPATH_TRUENAME
3330                                    | APR_FILEPATH_SECUREROOT, r->pool))
3331                     != APR_SUCCESS) {
3332             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
3333                          "Cannot map %s to file", r->the_request);
3334             return HTTP_FORBIDDEN;
3335         }
3336         r->canonical_filename = r->filename;
3337     }
3338
3339     return OK;
3340 }
3341
3342 /*****************************************************************
3343  *
3344  * Test the filesystem name through directory_walk and file_walk
3345  */
3346 static int core_map_to_storage(request_rec *r)
3347 {
3348     int access_status;
3349
3350     if ((access_status = ap_directory_walk(r))) {
3351         return access_status;
3352     }
3353
3354     if ((access_status = ap_file_walk(r))) {
3355         return access_status;
3356     }
3357
3358     return OK;
3359 }
3360
3361
3362 static int do_nothing(request_rec *r) { return OK; }
3363
3364
3365 static int core_override_type(request_rec *r)
3366 {
3367     core_dir_config *conf =
3368         (core_dir_config *)ap_get_module_config(r->per_dir_config,
3369                                                 &core_module);
3370
3371     /* Check for overrides with ForceType / SetHandler
3372      */
3373     if (conf->mime_type && strcmp(conf->mime_type, "none"))
3374         ap_set_content_type(r, (char*) conf->mime_type);
3375
3376     if (conf->handler && strcmp(conf->handler, "none"))
3377         r->handler = conf->handler;
3378
3379     /* Deal with the poor soul who is trying to force path_info to be
3380      * accepted within the core_handler, where they will let the subreq
3381      * address its contents.  This is toggled by the user in the very
3382      * beginning of the fixup phase, so modules should override the user's
3383      * discretion in their own module fixup phase.  It is tristate, if
3384      * the user doesn't specify, the result is 2 (which the module may
3385      * interpret to its own customary behavior.)  It won't be touched
3386      * if the value is no longer undefined (2), so any module changing
3387      * the value prior to the fixup phase OVERRIDES the user's choice.
3388      */
3389     if ((r->used_path_info == AP_REQ_DEFAULT_PATH_INFO)
3390         && (conf->accept_path_info != 3)) {
3391         r->used_path_info = conf->accept_path_info;
3392     }
3393
3394     return OK;
3395 }
3396
3397 static int default_handler(request_rec *r)
3398 {
3399     conn_rec *c = r->connection;
3400     apr_bucket_brigade *bb;
3401     apr_bucket *e;
3402     core_dir_config *d;
3403     int errstatus;
3404     apr_file_t *fd = NULL;
3405     apr_status_t status;
3406     /* XXX if/when somebody writes a content-md5 filter we either need to
3407      *     remove this support or coordinate when to use the filter vs.
3408      *     when to use this code
3409      *     The current choice of when to compute the md5 here matches the 1.3
3410      *     support fairly closely (unlike 1.3, we don't handle computing md5
3411      *     when the charset is translated).
3412      */
3413     int bld_content_md5;
3414
3415     d = (core_dir_config *)ap_get_module_config(r->per_dir_config,
3416                                                 &core_module);
3417     bld_content_md5 = (d->content_md5 & 1)
3418                       && r->output_filters->frec->ftype != AP_FTYPE_RESOURCE;
3419
3420     ap_allow_standard_methods(r, MERGE_ALLOW, M_GET, M_OPTIONS, M_POST, -1);
3421
3422     /* If filters intend to consume the request body, they must
3423      * register an InputFilter to slurp the contents of the POST
3424      * data from the POST input stream.  It no longer exists when
3425      * the output filters are invoked by the default handler.
3426      */
3427     if ((errstatus = ap_discard_request_body(r)) != OK) {
3428         return errstatus;
3429     }
3430
3431     if (r->method_number == M_GET || r->method_number == M_POST) {
3432         if (r->finfo.filetype == 0) {
3433             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3434                           "File does not exist: %s", r->filename);
3435             return HTTP_NOT_FOUND;
3436         }
3437
3438         /* Don't try to serve a dir.  Some OSs do weird things with
3439          * raw I/O on a dir.
3440          */
3441         if (r->finfo.filetype == APR_DIR) {
3442             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3443                           "Attempt to serve directory: %s", r->filename);
3444             return HTTP_NOT_FOUND;
3445         }
3446
3447         if ((r->used_path_info != AP_REQ_ACCEPT_PATH_INFO) &&
3448             r->path_info && *r->path_info)
3449         {
3450             /* default to reject */
3451             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3452                           "File does not exist: %s",
3453                           apr_pstrcat(r->pool, r->filename, r->path_info, NULL));
3454             return HTTP_NOT_FOUND;
3455         }
3456
3457         /* We understood the (non-GET) method, but it might not be legal for
3458            this particular resource. Check to see if the 'deliver_script'
3459            flag is set. If so, then we go ahead and deliver the file since
3460            it isn't really content (only GET normally returns content).
3461
3462            Note: based on logic further above, the only possible non-GET
3463            method at this point is POST. In the future, we should enable
3464            script delivery for all methods.  */
3465         if (r->method_number != M_GET) {
3466             core_request_config *req_cfg;
3467
3468             req_cfg = ap_get_module_config(r->request_config, &core_module);
3469             if (!req_cfg->deliver_script) {
3470                 /* The flag hasn't been set for this request. Punt. */
3471                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3472                               "This resource does not accept the %s method.",
3473                               r->method);
3474                 return HTTP_METHOD_NOT_ALLOWED;
3475             }
3476         }
3477
3478
3479         if ((status = apr_file_open(&fd, r->filename, APR_READ | APR_BINARY
3480 #if APR_HAS_SENDFILE
3481                             | ((d->enable_sendfile == ENABLE_SENDFILE_OFF) 
3482                                                 ? 0 : APR_SENDFILE_ENABLED)
3483 #endif
3484                                     , 0, r->pool)) != APR_SUCCESS) {
3485             ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
3486                           "file permissions deny server access: %s", r->filename);
3487             return HTTP_FORBIDDEN;
3488         }
3489
3490         ap_update_mtime(r, r->finfo.mtime);
3491         ap_set_last_modified(r);
3492         ap_set_etag(r);
3493         apr_table_setn(r->headers_out, "Accept-Ranges", "bytes");
3494         ap_set_content_length(r, r->finfo.size);
3495         if ((errstatus = ap_meets_conditions(r)) != OK) {
3496             apr_file_close(fd);
3497             return errstatus;
3498         }
3499
3500         if (bld_content_md5) {
3501             apr_table_setn(r->headers_out, "Content-MD5",
3502                            ap_md5digest(r->pool, fd));
3503         }
3504
3505         bb = apr_brigade_create(r->pool, c->bucket_alloc);
3506
3507         /* For platforms where the size of the file may be larger than
3508          * that which can be stored in a single bucket (where the
3509          * length field is an apr_size_t), split it into several
3510          * buckets: */
3511         if (sizeof(apr_off_t) > sizeof(apr_size_t) 
3512             && r->finfo.size > AP_MAX_SENDFILE) {
3513             apr_off_t fsize = r->finfo.size;
3514             e = apr_bucket_file_create(fd, 0, AP_MAX_SENDFILE, r->pool,
3515                                        c->bucket_alloc);
3516             while (fsize > AP_MAX_SENDFILE) {
3517                 apr_bucket *ce;
3518                 apr_bucket_copy(e, &ce);
3519                 APR_BRIGADE_INSERT_TAIL(bb, ce);
3520                 e->start += AP_MAX_SENDFILE;
3521                 fsize -= AP_MAX_SENDFILE;
3522             }
3523             e->length = (apr_size_t)fsize; /* Resize just the last bucket */
3524         }
3525         else
3526             e = apr_bucket_file_create(fd, 0, (apr_size_t)r->finfo.size,
3527                                        r->pool, c->bucket_alloc);
3528
3529 #if APR_HAS_MMAP
3530         if (d->enable_mmap == ENABLE_MMAP_OFF) {
3531             (void)apr_bucket_file_enable_mmap(e, 0);
3532         }
3533 #endif
3534         APR_BRIGADE_INSERT_TAIL(bb, e);
3535         e = apr_bucket_eos_create(c->bucket_alloc);
3536         APR_BRIGADE_INSERT_TAIL(bb, e);
3537
3538         return ap_pass_brigade(r->output_filters, bb);
3539     }
3540     else {              /* unusual method (not GET or POST) */
3541         if (r->method_number == M_INVALID) {
3542             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3543                           "Invalid method in request %s", r->the_request);
3544             return HTTP_NOT_IMPLEMENTED;
3545         }
3546
3547         if (r->method_number == M_OPTIONS) {
3548             return ap_send_http_options(r);
3549         }
3550         return HTTP_METHOD_NOT_ALLOWED;
3551     }
3552 }
3553
3554 /* Optional function coming from mod_logio, used for logging of output
3555  * traffic
3556  */
3557 APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *logio_add_bytes_out;
3558
3559 static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
3560 {
3561     logio_add_bytes_out = APR_RETRIEVE_OPTIONAL_FN(ap_logio_add_bytes_out);
3562     ident_lookup = APR_RETRIEVE_OPTIONAL_FN(ap_ident_lookup);
3563
3564     ap_set_version(pconf);
3565     ap_setup_make_content_type(pconf);
3566     return OK;
3567 }
3568
3569 static void core_insert_filter(request_rec *r)
3570 {
3571     core_dir_config *conf = (core_dir_config *)
3572                             ap_get_module_config(r->per_dir_config,
3573                                                  &core_module);
3574     const char *filter, *filters = conf->output_filters;
3575
3576     if (filters) {
3577         while (*filters && (filter = ap_getword(r->pool, &filters, ';'))) {
3578             ap_add_output_filter(filter, NULL, r, r->connection);
3579         }
3580     }
3581
3582     filters = conf->input_filters;
3583     if (filters) {
3584         while (*filters && (filter = ap_getword(r->pool, &filters, ';'))) {
3585             ap_add_input_filter(filter, NULL, r, r->connection);
3586         }
3587     }
3588 }
3589
3590 static apr_size_t num_request_notes = AP_NUM_STD_NOTES;
3591
3592 static apr_status_t reset_request_notes(void *dummy)
3593 {
3594     num_request_notes = AP_NUM_STD_NOTES;
3595     return APR_SUCCESS;
3596 }
3597
3598 AP_DECLARE(apr_size_t) ap_register_request_note(void)
3599 {
3600     apr_pool_cleanup_register(apr_hook_global_pool, NULL, reset_request_notes,
3601                               apr_pool_cleanup_null);
3602     return num_request_notes++;
3603 }
3604
3605 AP_DECLARE(void **) ap_get_request_note(request_rec *r, apr_size_t note_num)
3606 {
3607     core_request_config *req_cfg;
3608
3609     if (note_num >= num_request_notes) {
3610         return NULL;
3611     }
3612
3613     req_cfg = (core_request_config *)
3614         ap_get_module_config(r->request_config, &core_module);
3615
3616     if (!req_cfg) {
3617         return NULL;
3618     }
3619
3620     return &(req_cfg->notes[note_num]);
3621 }
3622
3623 static int core_create_req(request_rec *r)
3624 {
3625     /* Alloc the config struct and the array of request notes in
3626      * a single block for efficiency
3627      */
3628     core_request_config *req_cfg;
3629
3630     req_cfg = apr_pcalloc(r->pool, sizeof(core_request_config) +
3631                           sizeof(void *) * num_request_notes);
3632     req_cfg->notes = (void **)((char *)req_cfg + sizeof(core_request_config));
3633
3634     /* ### temporarily enable script delivery as the default */
3635     req_cfg->deliver_script = 1;
3636
3637     if (r->main) {
3638         core_request_config *main_req_cfg = (core_request_config *)
3639             ap_get_module_config(r->main->request_config, &core_module);
3640         req_cfg->bb = main_req_cfg->bb;
3641     }
3642     else {
3643         req_cfg->bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
3644         if (!r->prev) {
3645             ap_add_input_filter_handle(ap_net_time_filter_handle,
3646                                        NULL, r, r->connection);
3647         }
3648     }
3649
3650     ap_set_module_config(r->request_config, &core_module, req_cfg);
3651
3652     /* Begin by presuming any module can make its own path_info assumptions,
3653      * until some module interjects and changes the value.
3654      */
3655     r->used_path_info = AP_REQ_DEFAULT_PATH_INFO;
3656
3657     return OK;
3658 }
3659
3660 static int core_create_proxy_req(request_rec *r, request_rec *pr)
3661 {
3662     return core_create_req(pr);
3663 }
3664
3665 static conn_rec *core_create_conn(apr_pool_t *ptrans, server_rec *server,
3666                                   apr_socket_t *csd, long id, void *sbh,
3667                                   apr_bucket_alloc_t *alloc)
3668 {
3669     apr_status_t rv;
3670     conn_rec *c = (conn_rec *) apr_pcalloc(ptrans, sizeof(conn_rec));
3671
3672     c->sbh = sbh;
3673     (void)ap_update_child_status(c->sbh, SERVER_BUSY_READ, (request_rec *)NULL);
3674
3675     /* Got a connection structure, so initialize what fields we can
3676      * (the rest are zeroed out by pcalloc).
3677      */
3678     c->conn_config = ap_create_conn_config(ptrans);
3679     c->notes = apr_table_make(ptrans, 5);
3680
3681     c->pool = ptrans;
3682     if ((rv = apr_socket_addr_get(&c->local_addr, APR_LOCAL, csd))
3683         != APR_SUCCESS) {
3684         ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
3685                      "apr_socket_addr_get(APR_LOCAL)");
3686         apr_socket_close(csd);
3687         return NULL;
3688     }
3689
3690     apr_sockaddr_ip_get(&c->local_ip, c->local_addr);
3691     if ((rv = apr_socket_addr_get(&c->remote_addr, APR_REMOTE, csd))
3692         != APR_SUCCESS) {
3693         ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
3694                      "apr_socket_addr_get(APR_REMOTE)");
3695         apr_socket_close(csd);
3696         return NULL;
3697     }
3698
3699     apr_sockaddr_ip_get(&c->remote_ip, c->remote_addr);
3700     c->base_server = server;
3701
3702     c->id = id;
3703     c->bucket_alloc = alloc;
3704
3705     return c;
3706 }
3707
3708 static int core_pre_connection(conn_rec *c, void *csd)
3709 {
3710     core_net_rec *net = apr_palloc(c->pool, sizeof(*net));
3711
3712 #ifdef AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
3713     apr_status_t rv;
3714
3715     /* The Nagle algorithm says that we should delay sending partial
3716      * packets in hopes of getting more data.  We don't want to do
3717      * this; we are not telnet.  There are bad interactions between
3718      * persistent connections and Nagle's algorithm that have very severe
3719      * performance penalties.  (Failing to disable Nagle is not much of a
3720      * problem with simple HTTP.)
3721      */
3722     rv = apr_socket_opt_set(csd, APR_TCP_NODELAY, 1);
3723     if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
3724         /* expected cause is that the client disconnected already,
3725          * hence the debug level
3726          */
3727         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c,
3728                       "apr_socket_opt_set(APR_TCP_NODELAY)");
3729     }
3730 #endif
3731     net->c = c;
3732     net->in_ctx = NULL;
3733     net->out_ctx = NULL;
3734     net->client_socket = csd;
3735
3736     ap_set_module_config(net->c->conn_config, &core_module, csd);
3737     ap_add_input_filter_handle(ap_core_input_filter_handle, net, NULL, net->c);
3738     ap_add_output_filter_handle(ap_core_output_filter_handle, net, NULL, net->c);
3739     return DONE;
3740 }
3741
3742 static void register_hooks(apr_pool_t *p)
3743 {
3744     /* create_connection and install_transport_filters are
3745      * hooks that should always be APR_HOOK_REALLY_LAST to give other
3746      * modules the opportunity to install alternate network transports
3747      * and stop other functions from being run.
3748      */
3749     ap_hook_create_connection(core_create_conn, NULL, NULL,
3750                               APR_HOOK_REALLY_LAST);
3751     ap_hook_pre_connection(core_pre_connection, NULL, NULL,
3752                            APR_HOOK_REALLY_LAST);
3753
3754     ap_hook_post_config(core_post_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
3755     ap_hook_translate_name(ap_core_translate,NULL,NULL,APR_HOOK_REALLY_LAST);
3756     ap_hook_map_to_storage(core_map_to_storage,NULL,NULL,APR_HOOK_REALLY_LAST);
3757     ap_hook_open_logs(ap_open_logs,NULL,NULL,APR_HOOK_REALLY_FIRST);
3758     ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST);
3759     /* FIXME: I suspect we can eliminate the need for these do_nothings - Ben */
3760     ap_hook_type_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);
3761     ap_hook_fixups(core_override_type,NULL,NULL,APR_HOOK_REALLY_FIRST);
3762     ap_hook_access_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);
3763     ap_hook_create_request(core_create_req, NULL, NULL, APR_HOOK_MIDDLE);
3764     APR_OPTIONAL_HOOK(proxy, create_req, core_create_proxy_req, NULL, NULL,
3765                       APR_HOOK_MIDDLE);
3766     ap_hook_pre_mpm(ap_create_scoreboard, NULL, NULL, APR_HOOK_MIDDLE);
3767
3768     /* register the core's insert_filter hook and register core-provided
3769      * filters
3770      */
3771     ap_hook_insert_filter(core_insert_filter, NULL, NULL, APR_HOOK_MIDDLE);
3772
3773     ap_core_input_filter_handle =
3774         ap_register_input_filter("CORE_IN", ap_core_input_filter,
3775                                  NULL, AP_FTYPE_NETWORK);
3776     ap_net_time_filter_handle =
3777         ap_register_input_filter("NET_TIME", ap_net_time_filter,
3778                                  NULL, AP_FTYPE_PROTOCOL);
3779     ap_content_length_filter_handle =
3780         ap_register_output_filter("CONTENT_LENGTH", ap_content_length_filter,
3781                                   NULL, AP_FTYPE_PROTOCOL);
3782     ap_core_output_filter_handle =
3783         ap_register_output_filter("CORE", ap_core_output_filter,
3784                                   NULL, AP_FTYPE_NETWORK);
3785     ap_subreq_core_filter_handle =
3786         ap_register_output_filter("SUBREQ_CORE", ap_sub_req_output_filter,
3787                                   NULL, AP_FTYPE_CONTENT_SET);
3788     ap_old_write_func =
3789         ap_register_output_filter("OLD_WRITE", ap_old_write_filter,
3790                                   NULL, AP_FTYPE_RESOURCE - 10);
3791 }
3792
3793 AP_DECLARE_DATA module core_module = {
3794     STANDARD20_MODULE_STUFF,
3795     create_core_dir_config,       /* create per-directory config structure */
3796     merge_core_dir_configs,       /* merge per-directory config structures */
3797     create_core_server_config,    /* create per-server config structure */
3798     merge_core_server_configs,    /* merge per-server config structures */
3799     core_cmds,                    /* command apr_table_t */
3800     register_hooks                /* register hooks */
3801 };
3802