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