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