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