]> granicus.if.org Git - apache/blob - server/core.c
rebuild
[apache] / server / core.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr.h"
18 #include "apr_strings.h"
19 #include "apr_lib.h"
20 #include "apr_fnmatch.h"
21 #include "apr_hash.h"
22 #include "apr_thread_proc.h"    /* for RLIMIT stuff */
23 #include "apr_random.h"
24
25 #define APR_WANT_IOVEC
26 #define APR_WANT_STRFUNC
27 #define APR_WANT_MEMFUNC
28 #include "apr_want.h"
29
30 #include "ap_config.h"
31 #include "httpd.h"
32 #include "http_config.h"
33 #include "http_core.h"
34 #include "http_protocol.h" /* For index_of_response().  Grump. */
35 #include "http_request.h"
36 #include "http_vhost.h"
37 #include "http_main.h"     /* For the default_handler below... */
38 #include "http_log.h"
39 #include "util_md5.h"
40 #include "http_connection.h"
41 #include "apr_buckets.h"
42 #include "util_filter.h"
43 #include "util_ebcdic.h"
44 #include "util_mutex.h"
45 #include "util_time.h"
46 #include "mpm_common.h"
47 #include "scoreboard.h"
48 #include "mod_core.h"
49 #include "mod_proxy.h"
50 #include "ap_listen.h"
51 #include "ap_provider.h"
52
53 #include "mod_so.h" /* for ap_find_loaded_module_symbol */
54
55 #if defined(RLIMIT_CPU) || defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS) || defined (RLIMIT_NPROC)
56 #include "unixd.h"
57 #endif
58 #if APR_HAVE_UNISTD_H
59 #include <unistd.h>
60 #endif
61
62 /* LimitRequestBody handling */
63 #define AP_LIMIT_REQ_BODY_UNSET         ((apr_off_t) -1)
64 #define AP_DEFAULT_LIMIT_REQ_BODY       ((apr_off_t) 0)
65
66 /* LimitXMLRequestBody handling */
67 #define AP_LIMIT_UNSET                  ((long) -1)
68 #define AP_DEFAULT_LIMIT_XML_BODY       ((apr_size_t)1000000)
69
70 #define AP_MIN_SENDFILE_BYTES           (256)
71
72 /* maximum include nesting level */
73 #ifndef AP_MAX_INCLUDE_DEPTH
74 #define AP_MAX_INCLUDE_DEPTH            (128)
75 #endif
76
77 /* valid in core-conf, but not in runtime r->used_path_info */
78 #define AP_ACCEPT_PATHINFO_UNSET 3
79
80 #define AP_CONTENT_MD5_OFF   0
81 #define AP_CONTENT_MD5_ON    1
82 #define AP_CONTENT_MD5_UNSET 2
83
84 APR_HOOK_STRUCT(
85     APR_HOOK_LINK(get_mgmt_items)
86     APR_HOOK_LINK(insert_network_bucket)
87 )
88
89 AP_IMPLEMENT_HOOK_RUN_ALL(int, get_mgmt_items,
90                           (apr_pool_t *p, const char *val, apr_hash_t *ht),
91                           (p, val, ht), OK, DECLINED)
92
93 AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, insert_network_bucket,
94                             (conn_rec *c, apr_bucket_brigade *bb,
95                              apr_socket_t *socket),
96                             (c, bb, socket), AP_DECLINED)
97
98 /* Server core module... This module provides support for really basic
99  * server operations, including options and commands which control the
100  * operation of other modules.  Consider this the bureaucracy module.
101  *
102  * The core module also defines handlers, etc., to handle just enough
103  * to allow a server with the core module ONLY to actually serve documents.
104  *
105  * This file could almost be mod_core.c, except for the stuff which affects
106  * the http_conf_globals.
107  */
108
109 /* we know core's module_index is 0 */
110 #undef APLOG_MODULE_INDEX
111 #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
112
113 /* Handles for core filters */
114 AP_DECLARE_DATA ap_filter_rec_t *ap_subreq_core_filter_handle;
115 AP_DECLARE_DATA ap_filter_rec_t *ap_request_core_filter_handle;
116 AP_DECLARE_DATA ap_filter_rec_t *ap_core_output_filter_handle;
117 AP_DECLARE_DATA ap_filter_rec_t *ap_content_length_filter_handle;
118 AP_DECLARE_DATA ap_filter_rec_t *ap_core_input_filter_handle;
119
120 /* Provide ap_document_root_check storage and default value = true */
121 AP_DECLARE_DATA int ap_document_root_check = 1;
122
123 /* magic pointer for ErrorDocument xxx "default" */
124 static char errordocument_default;
125
126 static apr_array_header_t *saved_server_config_defines = NULL;
127 static apr_table_t *server_config_defined_vars = NULL;
128
129 AP_DECLARE_DATA int ap_main_state = AP_SQ_MS_INITIAL_STARTUP;
130 AP_DECLARE_DATA int ap_run_mode = AP_SQ_RM_UNKNOWN;
131 AP_DECLARE_DATA int ap_config_generation = 0;
132
133 typedef struct {
134     apr_ipsubnet_t *subnet;
135     struct ap_logconf log;
136 } conn_log_config;
137
138 static void *create_core_dir_config(apr_pool_t *a, char *dir)
139 {
140     core_dir_config *conf;
141
142     conf = (core_dir_config *)apr_pcalloc(a, sizeof(core_dir_config));
143
144     /* conf->r and conf->d[_*] are initialized by dirsection() or left NULL */
145
146     conf->opts = dir ? OPT_UNSET : OPT_UNSET|OPT_SYM_LINKS;
147     conf->opts_add = conf->opts_remove = OPT_NONE;
148     conf->override = OR_UNSET|OR_NONE;
149     conf->override_opts = OPT_UNSET | OPT_ALL | OPT_SYM_OWNER | OPT_MULTI;
150
151     conf->content_md5 = AP_CONTENT_MD5_UNSET;
152     conf->accept_path_info = AP_ACCEPT_PATHINFO_UNSET;
153
154     conf->use_canonical_name = USE_CANONICAL_NAME_UNSET;
155     conf->use_canonical_phys_port = USE_CANONICAL_PHYS_PORT_UNSET;
156
157     conf->hostname_lookups = HOSTNAME_LOOKUP_UNSET;
158
159     /*
160      * left as NULL (we use apr_pcalloc):
161      * conf->limit_cpu = NULL;
162      * conf->limit_mem = NULL;
163      * conf->limit_nproc = NULL;
164      * conf->sec_file = NULL;
165      * conf->sec_if   = NULL;
166      */
167
168     conf->limit_req_body = AP_LIMIT_REQ_BODY_UNSET;
169     conf->limit_xml_body = AP_LIMIT_UNSET;
170
171     conf->server_signature = srv_sig_unset;
172
173     conf->add_default_charset = ADD_DEFAULT_CHARSET_UNSET;
174     conf->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
175
176     /* Overriding all negotiation
177      * Set NULL by apr_pcalloc:
178      * conf->mime_type = NULL;
179      * conf->handler = NULL;
180      * conf->output_filters = NULL;
181      * conf->input_filters = NULL;
182      */
183
184     /*
185      * Flag for use of inodes in ETags.
186      */
187     conf->etag_bits = ETAG_UNSET;
188     conf->etag_add = ETAG_UNSET;
189     conf->etag_remove = ETAG_UNSET;
190
191     conf->enable_mmap = ENABLE_MMAP_UNSET;
192     conf->enable_sendfile = ENABLE_SENDFILE_UNSET;
193     conf->allow_encoded_slashes = 0;
194     conf->decode_encoded_slashes = 0;
195
196     conf->max_ranges = AP_MAXRANGES_UNSET;
197     conf->max_overlaps = AP_MAXRANGES_UNSET;
198     conf->max_reversals = AP_MAXRANGES_UNSET;
199
200     conf->cgi_pass_auth = AP_CGI_PASS_AUTH_UNSET;
201     conf->qualify_redirect_url = AP_CORE_CONFIG_UNSET; 
202
203     return (void *)conf;
204 }
205
206 static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv)
207 {
208     core_dir_config *base = (core_dir_config *)basev;
209     core_dir_config *new = (core_dir_config *)newv;
210     core_dir_config *conf;
211
212     /* Create this conf by duplicating the base, replacing elements
213      * (or creating copies for merging) where new-> values exist.
214      */
215     conf = (core_dir_config *)apr_pmemdup(a, base, sizeof(core_dir_config));
216
217     conf->d = new->d;
218     conf->d_is_fnmatch = new->d_is_fnmatch;
219     conf->d_components = new->d_components;
220     conf->r = new->r;
221     conf->refs = new->refs;
222     conf->condition = new->condition;
223
224     if (new->opts & OPT_UNSET) {
225         /* there was no explicit setting of new->opts, so we merge
226          * preserve the invariant (opts_add & opts_remove) == 0
227          */
228         conf->opts_add = (conf->opts_add & ~new->opts_remove) | new->opts_add;
229         conf->opts_remove = (conf->opts_remove & ~new->opts_add)
230                             | new->opts_remove;
231         conf->opts = (conf->opts & ~conf->opts_remove) | conf->opts_add;
232
233         /* If Includes was enabled with exec in the base config, but
234          * was enabled without exec in the new config, then disable
235          * exec in the merged set. */
236         if (((base->opts & (OPT_INCLUDES|OPT_INC_WITH_EXEC))
237              == (OPT_INCLUDES|OPT_INC_WITH_EXEC))
238             && ((new->opts & (OPT_INCLUDES|OPT_INC_WITH_EXEC))
239                 == OPT_INCLUDES)) {
240             conf->opts &= ~OPT_INC_WITH_EXEC;
241         }
242     }
243     else {
244         /* otherwise we just copy, because an explicit opts setting
245          * overrides all earlier +/- modifiers
246          */
247         conf->opts = new->opts;
248         conf->opts_add = new->opts_add;
249         conf->opts_remove = new->opts_remove;
250     }
251
252     if (!(new->override & OR_UNSET)) {
253         conf->override = new->override;
254     }
255
256     if (!(new->override_opts & OPT_UNSET)) {
257         conf->override_opts = new->override_opts;
258     }
259
260     if (new->override_list != NULL) {
261         conf->override_list = new->override_list;
262     }
263
264     if (conf->response_code_exprs == NULL) {
265         conf->response_code_exprs = new->response_code_exprs;
266     }
267     else if (new->response_code_exprs != NULL) {
268         conf->response_code_exprs = apr_hash_overlay(a,
269                 new->response_code_exprs, conf->response_code_exprs);
270     }
271     /* Otherwise we simply use the base->response_code_exprs array
272      */
273
274     if (new->hostname_lookups != HOSTNAME_LOOKUP_UNSET) {
275         conf->hostname_lookups = new->hostname_lookups;
276     }
277
278     if (new->content_md5 != AP_CONTENT_MD5_UNSET) {
279         conf->content_md5 = new->content_md5;
280     }
281
282     if (new->accept_path_info != AP_ACCEPT_PATHINFO_UNSET) {
283         conf->accept_path_info = new->accept_path_info;
284     }
285
286     if (new->use_canonical_name != USE_CANONICAL_NAME_UNSET) {
287         conf->use_canonical_name = new->use_canonical_name;
288     }
289
290     if (new->use_canonical_phys_port != USE_CANONICAL_PHYS_PORT_UNSET) {
291         conf->use_canonical_phys_port = new->use_canonical_phys_port;
292     }
293
294 #ifdef RLIMIT_CPU
295     if (new->limit_cpu) {
296         conf->limit_cpu = new->limit_cpu;
297     }
298 #endif
299
300 #if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
301     if (new->limit_mem) {
302         conf->limit_mem = new->limit_mem;
303     }
304 #endif
305
306 #ifdef RLIMIT_NPROC
307     if (new->limit_nproc) {
308         conf->limit_nproc = new->limit_nproc;
309     }
310 #endif
311
312     if (new->limit_req_body != AP_LIMIT_REQ_BODY_UNSET) {
313         conf->limit_req_body = new->limit_req_body;
314     }
315
316     if (new->limit_xml_body != AP_LIMIT_UNSET)
317         conf->limit_xml_body = new->limit_xml_body;
318
319     if (!conf->sec_file) {
320         conf->sec_file = new->sec_file;
321     }
322     else if (new->sec_file) {
323         /* If we merge, the merge-result must have its own array
324          */
325         conf->sec_file = apr_array_append(a, base->sec_file, new->sec_file);
326     }
327     /* Otherwise we simply use the base->sec_file array
328      */
329
330     if (!conf->sec_if) {
331         conf->sec_if = new->sec_if;
332     }
333     else if (new->sec_if) {
334         /* If we merge, the merge-result must have its own array
335          */
336         conf->sec_if = apr_array_append(a, base->sec_if, new->sec_if);
337     }
338     /* Otherwise we simply use the base->sec_if array
339      */
340
341     if (new->server_signature != srv_sig_unset) {
342         conf->server_signature = new->server_signature;
343     }
344
345     if (new->add_default_charset != ADD_DEFAULT_CHARSET_UNSET) {
346         conf->add_default_charset = new->add_default_charset;
347         conf->add_default_charset_name = new->add_default_charset_name;
348     }
349
350     /* Overriding all negotiation
351      */
352     if (new->mime_type) {
353         conf->mime_type = new->mime_type;
354     }
355
356     if (new->handler) {
357         conf->handler = new->handler;
358     }
359     if (new->expr_handler) {
360         conf->expr_handler = new->expr_handler;
361     }
362
363     if (new->output_filters) {
364         conf->output_filters = new->output_filters;
365     }
366
367     if (new->input_filters) {
368         conf->input_filters = new->input_filters;
369     }
370
371     /*
372      * Now merge the setting of the FileETag directive.
373      */
374     if (new->etag_bits == ETAG_UNSET) {
375         conf->etag_add =
376             (conf->etag_add & (~ new->etag_remove)) | new->etag_add;
377         conf->etag_remove =
378             (conf->etag_remove & (~ new->etag_add)) | new->etag_remove;
379         conf->etag_bits =
380             (conf->etag_bits & (~ conf->etag_remove)) | conf->etag_add;
381     }
382     else {
383         conf->etag_bits = new->etag_bits;
384         conf->etag_add = new->etag_add;
385         conf->etag_remove = new->etag_remove;
386     }
387
388     if (conf->etag_bits != ETAG_NONE) {
389         conf->etag_bits &= (~ ETAG_NONE);
390     }
391
392     if (new->enable_mmap != ENABLE_MMAP_UNSET) {
393         conf->enable_mmap = new->enable_mmap;
394     }
395
396     if (new->enable_sendfile != ENABLE_SENDFILE_UNSET) {
397         conf->enable_sendfile = new->enable_sendfile;
398     }
399
400     if (new->allow_encoded_slashes_set) {
401         conf->allow_encoded_slashes = new->allow_encoded_slashes;
402     }
403     if (new->decode_encoded_slashes_set) {
404         conf->decode_encoded_slashes = new->decode_encoded_slashes;
405     }
406
407     if (new->log) {
408         if (!conf->log) {
409             conf->log = new->log;
410         }
411         else {
412             conf->log = ap_new_log_config(a, new->log);
413             ap_merge_log_config(base->log, conf->log);
414         }
415     }
416
417     conf->max_ranges = new->max_ranges != AP_MAXRANGES_UNSET ? new->max_ranges : base->max_ranges;
418     conf->max_overlaps = new->max_overlaps != AP_MAXRANGES_UNSET ? new->max_overlaps : base->max_overlaps;
419     conf->max_reversals = new->max_reversals != AP_MAXRANGES_UNSET ? new->max_reversals : base->max_reversals;
420
421     conf->cgi_pass_auth = new->cgi_pass_auth != AP_CGI_PASS_AUTH_UNSET ? new->cgi_pass_auth : base->cgi_pass_auth;
422
423     if (new->cgi_var_rules) {
424         if (!conf->cgi_var_rules) {
425             conf->cgi_var_rules = new->cgi_var_rules;
426         }
427         else {
428             conf->cgi_var_rules = apr_hash_overlay(a, new->cgi_var_rules, conf->cgi_var_rules);
429         }
430     }
431
432     AP_CORE_MERGE_FLAG(qualify_redirect_url, conf, base, new);
433
434     return (void*)conf;
435 }
436
437 #if APR_HAS_SO_ACCEPTFILTER
438 #ifndef ACCEPT_FILTER_NAME
439 #define ACCEPT_FILTER_NAME "httpready"
440 #ifdef __FreeBSD_version
441 #if __FreeBSD_version < 411000 /* httpready broken before 4.1.1 */
442 #undef ACCEPT_FILTER_NAME
443 #define ACCEPT_FILTER_NAME "dataready"
444 #endif
445 #endif
446 #endif
447 #endif
448
449 static void *create_core_server_config(apr_pool_t *a, server_rec *s)
450 {
451     core_server_config *conf;
452     int is_virtual = s->is_virtual;
453
454     conf = (core_server_config *)apr_pcalloc(a, sizeof(core_server_config));
455
456     /* global-default / global-only settings */
457
458     if (!is_virtual) {
459         conf->ap_document_root = DOCUMENT_LOCATION;
460         conf->access_name = DEFAULT_ACCESS_FNAME;
461
462         /* A mapping only makes sense in the global context */
463         conf->accf_map = apr_table_make(a, 5);
464 #if APR_HAS_SO_ACCEPTFILTER
465         apr_table_setn(conf->accf_map, "http", ACCEPT_FILTER_NAME);
466         apr_table_setn(conf->accf_map, "https", "dataready");
467 #else
468         apr_table_setn(conf->accf_map, "http", "data");
469         apr_table_setn(conf->accf_map, "https", "data");
470 #endif
471     }
472     /* pcalloc'ed - we have NULL's/0's
473     else ** is_virtual ** {
474         conf->ap_document_root = NULL;
475         conf->access_name = NULL;
476         conf->accf_map = NULL;
477     }
478      */
479
480     /* initialization, no special case for global context */
481
482     conf->sec_dir = apr_array_make(a, 40, sizeof(ap_conf_vector_t *));
483     conf->sec_url = apr_array_make(a, 40, sizeof(ap_conf_vector_t *));
484
485     /* pcalloc'ed - we have NULL's/0's
486     conf->gprof_dir = NULL;
487
488     ** recursion stopper; 0 == unset
489     conf->redirect_limit = 0;
490     conf->subreq_limit = 0;
491
492     conf->protocol = NULL;
493      */
494
495     conf->trace_enable = AP_TRACE_UNSET;
496
497     conf->protocols = apr_array_make(a, 5, sizeof(const char *));
498     conf->protocols_honor_order = -1;
499     conf->async_filter = 0;
500
501     return (void *)conf;
502 }
503
504 static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
505 {
506     core_server_config *base = (core_server_config *)basev;
507     core_server_config *virt = (core_server_config *)virtv;
508     core_server_config *conf = (core_server_config *)
509                                apr_pmemdup(p, base, sizeof(core_server_config));
510
511     if (virt->ap_document_root)
512         conf->ap_document_root = virt->ap_document_root;
513
514     if (virt->access_name)
515         conf->access_name = virt->access_name;
516
517     /* XXX optimize to keep base->sec_ pointers if virt->sec_ array is empty */
518     conf->sec_dir = apr_array_append(p, base->sec_dir, virt->sec_dir);
519     conf->sec_url = apr_array_append(p, base->sec_url, virt->sec_url);
520
521     if (virt->redirect_limit)
522         conf->redirect_limit = virt->redirect_limit;
523
524     if (virt->subreq_limit)
525         conf->subreq_limit = virt->subreq_limit;
526
527     if (virt->trace_enable != AP_TRACE_UNSET)
528         conf->trace_enable = virt->trace_enable;
529
530     if (virt->http09_enable != AP_HTTP09_UNSET)
531         conf->http09_enable = virt->http09_enable;
532
533     if (virt->http_conformance != AP_HTTP_CONFORMANCE_UNSET)
534         conf->http_conformance = virt->http_conformance;
535
536     if (virt->http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_UNSET)
537         conf->http_cl_head_zero = virt->http_cl_head_zero;
538
539     if (virt->http_expect_strict != AP_HTTP_EXPECT_STRICT_UNSET)
540         conf->http_expect_strict = virt->http_expect_strict;
541
542     /* no action for virt->accf_map, not allowed per-vhost */
543
544     if (virt->protocol)
545         conf->protocol = virt->protocol;
546
547     if (virt->gprof_dir)
548         conf->gprof_dir = virt->gprof_dir;
549
550     if (virt->error_log_format)
551         conf->error_log_format = virt->error_log_format;
552
553     if (virt->error_log_conn)
554         conf->error_log_conn = virt->error_log_conn;
555
556     if (virt->error_log_req)
557         conf->error_log_req = virt->error_log_req;
558
559     if (virt->conn_log_level) {
560         if (!conf->conn_log_level) {
561             conf->conn_log_level = virt->conn_log_level;
562         }
563         else {
564             /* apr_array_append actually creates a new array */
565             conf->conn_log_level = apr_array_append(p, conf->conn_log_level,
566                                                     virt->conn_log_level);
567         }
568     }
569
570     conf->merge_trailers = (virt->merge_trailers != AP_MERGE_TRAILERS_UNSET)
571                            ? virt->merge_trailers
572                            : base->merge_trailers;
573
574     conf->protocols = ((virt->protocols->nelts > 0) ?
575                        virt->protocols : base->protocols);
576     conf->protocols_honor_order = ((virt->protocols_honor_order < 0) ?
577                                        base->protocols_honor_order :
578                                        virt->protocols_honor_order);
579     conf->async_filter = ((virt->async_filter_set) ?
580                                        virt->async_filter :
581                                        base->async_filter);
582     conf->async_filter_set = base->async_filter_set || virt->async_filter_set;
583
584     return conf;
585 }
586
587 /* Add per-directory configuration entry (for <directory> section);
588  * these are part of the core server config.
589  */
590
591 AP_CORE_DECLARE(void) ap_add_per_dir_conf(server_rec *s, void *dir_config)
592 {
593     core_server_config *sconf = ap_get_core_module_config(s->module_config);
594     void **new_space = (void **)apr_array_push(sconf->sec_dir);
595
596     *new_space = dir_config;
597 }
598
599 AP_CORE_DECLARE(void) ap_add_per_url_conf(server_rec *s, void *url_config)
600 {
601     core_server_config *sconf = ap_get_core_module_config(s->module_config);
602     void **new_space = (void **)apr_array_push(sconf->sec_url);
603
604     *new_space = url_config;
605 }
606
607 AP_CORE_DECLARE(void) ap_add_file_conf(apr_pool_t *p, core_dir_config *conf,
608                                        void *url_config)
609 {
610     void **new_space;
611
612     if (!conf->sec_file)
613         conf->sec_file = apr_array_make(p, 2, sizeof(ap_conf_vector_t *));
614
615     new_space = (void **)apr_array_push(conf->sec_file);
616     *new_space = url_config;
617 }
618
619 AP_CORE_DECLARE(const char *) ap_add_if_conf(apr_pool_t *p,
620                                              core_dir_config *conf,
621                                              void *if_config)
622 {
623     void **new_space;
624     core_dir_config *new = ap_get_module_config(if_config, &core_module);
625
626     if (!conf->sec_if) {
627         conf->sec_if = apr_array_make(p, 2, sizeof(ap_conf_vector_t *));
628     }
629     if (new->condition_ifelse & AP_CONDITION_ELSE) {
630         int have_if = 0;
631         if (conf->sec_if->nelts > 0) {
632             core_dir_config *last;
633             ap_conf_vector_t *lastelt = APR_ARRAY_IDX(conf->sec_if,
634                                                       conf->sec_if->nelts - 1,
635                                                       ap_conf_vector_t *);
636             last = ap_get_module_config(lastelt, &core_module);
637             if (last->condition_ifelse & AP_CONDITION_IF)
638                 have_if = 1;
639         }
640         if (!have_if)
641             return "<Else> or <ElseIf> section without previous <If> or "
642                    "<ElseIf> section in same scope";
643     }
644
645     new_space = (void **)apr_array_push(conf->sec_if);
646     *new_space = if_config;
647     return NULL;
648 }
649
650
651 /* We need to do a stable sort, qsort isn't stable.  So to make it stable
652  * we'll be maintaining the original index into the list, and using it
653  * as the minor key during sorting.  The major key is the number of
654  * components (where the root component is zero).
655  */
656 struct reorder_sort_rec {
657     ap_conf_vector_t *elt;
658     int orig_index;
659 };
660
661 static int reorder_sorter(const void *va, const void *vb)
662 {
663     const struct reorder_sort_rec *a = va;
664     const struct reorder_sort_rec *b = vb;
665     core_dir_config *core_a;
666     core_dir_config *core_b;
667
668     core_a = ap_get_core_module_config(a->elt);
669     core_b = ap_get_core_module_config(b->elt);
670
671     /* a regex always sorts after a non-regex
672      */
673     if (!core_a->r && core_b->r) {
674         return -1;
675     }
676     else if (core_a->r && !core_b->r) {
677         return 1;
678     }
679
680     /* we always sort next by the number of components
681      */
682     if (core_a->d_components < core_b->d_components) {
683         return -1;
684     }
685     else if (core_a->d_components > core_b->d_components) {
686         return 1;
687     }
688
689     /* They have the same number of components, we now have to compare
690      * the minor key to maintain the original order (from the config.)
691      */
692     return a->orig_index - b->orig_index;
693 }
694
695 void ap_core_reorder_directories(apr_pool_t *p, server_rec *s)
696 {
697     core_server_config *sconf;
698     apr_array_header_t *sec_dir;
699     struct reorder_sort_rec *sortbin;
700     int nelts;
701     ap_conf_vector_t **elts;
702     int i;
703     apr_pool_t *tmp;
704
705     sconf = ap_get_core_module_config(s->module_config);
706     sec_dir = sconf->sec_dir;
707     nelts = sec_dir->nelts;
708     elts = (ap_conf_vector_t **)sec_dir->elts;
709
710     if (!nelts) {
711         /* simple case of already being sorted... */
712         /* We're not checking this condition to be fast... we're checking
713          * it to avoid trying to palloc zero bytes, which can trigger some
714          * memory debuggers to barf
715          */
716         return;
717     }
718
719     /* we have to allocate tmp space to do a stable sort */
720     apr_pool_create(&tmp, p);
721     sortbin = apr_palloc(tmp, sec_dir->nelts * sizeof(*sortbin));
722     for (i = 0; i < nelts; ++i) {
723         sortbin[i].orig_index = i;
724         sortbin[i].elt = elts[i];
725     }
726
727     qsort(sortbin, nelts, sizeof(*sortbin), reorder_sorter);
728
729     /* and now copy back to the original array */
730     for (i = 0; i < nelts; ++i) {
731         elts[i] = sortbin[i].elt;
732     }
733
734     apr_pool_destroy(tmp);
735 }
736
737 /*****************************************************************
738  *
739  * There are some elements of the core config structures in which
740  * other modules have a legitimate interest (this is ugly, but necessary
741  * to preserve NCSA back-compatibility).  So, we have a bunch of accessors
742  * here...
743  */
744
745 AP_DECLARE(int) ap_allow_options(request_rec *r)
746 {
747     core_dir_config *conf =
748       (core_dir_config *)ap_get_core_module_config(r->per_dir_config);
749
750     return conf->opts;
751 }
752
753 AP_DECLARE(int) ap_allow_overrides(request_rec *r)
754 {
755     core_dir_config *conf;
756     conf = (core_dir_config *)ap_get_core_module_config(r->per_dir_config);
757
758     return conf->override;
759 }
760
761 /*
762  * Optional function coming from mod_authn_core, used for
763  * retrieving the type of autorization
764  */
765 static APR_OPTIONAL_FN_TYPE(authn_ap_auth_type) *authn_ap_auth_type;
766
767 AP_DECLARE(const char *) ap_auth_type(request_rec *r)
768 {
769     if (authn_ap_auth_type) {
770         return authn_ap_auth_type(r);
771     }
772     return NULL;
773 }
774
775 /*
776  * Optional function coming from mod_authn_core, used for
777  * retrieving the authorization realm
778  */
779 static APR_OPTIONAL_FN_TYPE(authn_ap_auth_name) *authn_ap_auth_name;
780
781 AP_DECLARE(const char *) ap_auth_name(request_rec *r)
782 {
783     if (authn_ap_auth_name) {
784         return authn_ap_auth_name(r);
785     }
786     return NULL;
787 }
788
789 /*
790  * Optional function coming from mod_access_compat, used to determine how
791    access control interacts with authentication/authorization
792  */
793 static APR_OPTIONAL_FN_TYPE(access_compat_ap_satisfies) *access_compat_ap_satisfies;
794
795 AP_DECLARE(int) ap_satisfies(request_rec *r)
796 {
797     if (access_compat_ap_satisfies) {
798         return access_compat_ap_satisfies(r);
799     }
800     return SATISFY_NOSPEC;
801 }
802
803 AP_DECLARE(const char *) ap_document_root(request_rec *r) /* Don't use this! */
804 {
805     core_server_config *sconf;
806     core_request_config *rconf = ap_get_core_module_config(r->request_config);
807     if (rconf->document_root)
808         return rconf->document_root;
809     sconf = ap_get_core_module_config(r->server->module_config);
810     return sconf->ap_document_root;
811 }
812
813 AP_DECLARE(const char *) ap_context_prefix(request_rec *r)
814 {
815     core_request_config *conf = ap_get_core_module_config(r->request_config);
816     if (conf->context_prefix)
817         return conf->context_prefix;
818     else
819         return "";
820 }
821
822 AP_DECLARE(const char *) ap_context_document_root(request_rec *r)
823 {
824     core_request_config *conf = ap_get_core_module_config(r->request_config);
825     if (conf->context_document_root)
826         return conf->context_document_root;
827     else
828         return ap_document_root(r);
829 }
830
831 AP_DECLARE(void) ap_set_document_root(request_rec *r, const char *document_root)
832 {
833     core_request_config *conf = ap_get_core_module_config(r->request_config);
834     conf->document_root = document_root;
835 }
836
837 AP_DECLARE(void) ap_set_context_info(request_rec *r, const char *context_prefix,
838                                      const char *context_document_root)
839 {
840     core_request_config *conf = ap_get_core_module_config(r->request_config);
841     if (context_prefix)
842         conf->context_prefix = context_prefix;
843     if (context_document_root)
844         conf->context_document_root = context_document_root;
845 }
846
847 /* Should probably just get rid of this... the only code that cares is
848  * part of the core anyway (and in fact, it isn't publicised to other
849  * modules).
850  */
851
852 char *ap_response_code_string(request_rec *r, int error_index)
853 {
854     core_dir_config *dirconf;
855     core_request_config *reqconf = ap_get_core_module_config(r->request_config);
856     const char *err;
857     const char *response;
858     ap_expr_info_t *expr;
859
860     /* check for string registered via ap_custom_response() first */
861     if (reqconf->response_code_strings != NULL
862             && reqconf->response_code_strings[error_index] != NULL) {
863         return reqconf->response_code_strings[error_index];
864     }
865
866     /* check for string specified via ErrorDocument */
867     dirconf = ap_get_core_module_config(r->per_dir_config);
868
869     if (!dirconf->response_code_exprs) {
870         return NULL;
871     }
872
873     expr = apr_hash_get(dirconf->response_code_exprs, &error_index,
874             sizeof(error_index));
875     if (!expr) {
876         return NULL;
877     }
878
879     /* special token to indicate revert back to default */
880     if ((char *) expr == &errordocument_default) {
881         return NULL;
882     }
883
884     err = NULL;
885     response = ap_expr_str_exec(r, expr, &err);
886     if (err) {
887         ap_log_rerror(
888                 APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02841) "core: ErrorDocument: can't "
889                 "evaluate require expression: %s", err);
890         return NULL;
891     }
892
893     /* alas, duplication required as we return not-const */
894     return apr_pstrdup(r->pool, response);
895 }
896
897
898 /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
899 static APR_INLINE int do_double_reverse (int double_reverse,
900                                          const char *remote_host,
901                                          apr_sockaddr_t *client_addr,
902                                          apr_pool_t *pool)
903 {
904     apr_sockaddr_t *sa;
905     apr_status_t rv;
906
907     if (double_reverse) {
908         /* already done */
909         return double_reverse;
910     }
911
912     if (remote_host == NULL || remote_host[0] == '\0') {
913         /* single reverse failed, so don't bother */
914         return -1;
915     }
916
917     rv = apr_sockaddr_info_get(&sa, remote_host, APR_UNSPEC, 0, 0, pool);
918     if (rv == APR_SUCCESS) {
919         while (sa) {
920             if (apr_sockaddr_equal(sa, client_addr)) {
921                 return 1;
922             }
923
924             sa = sa->next;
925         }
926     }
927
928     return -1;
929 }
930
931 AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config,
932                                             int type, int *str_is_ip)
933 {
934     int hostname_lookups;
935     int ignored_str_is_ip;
936
937     if (!str_is_ip) { /* caller doesn't want to know */
938         str_is_ip = &ignored_str_is_ip;
939     }
940     *str_is_ip = 0;
941
942     /* If we haven't checked the host name, and we want to */
943     if (dir_config) {
944         hostname_lookups = ((core_dir_config *)ap_get_core_module_config(dir_config))
945                            ->hostname_lookups;
946
947         if (hostname_lookups == HOSTNAME_LOOKUP_UNSET) {
948             hostname_lookups = HOSTNAME_LOOKUP_OFF;
949         }
950     }
951     else {
952         /* the default */
953         hostname_lookups = HOSTNAME_LOOKUP_OFF;
954     }
955
956     if (type != REMOTE_NOLOOKUP
957         && conn->remote_host == NULL
958         && (type == REMOTE_DOUBLE_REV
959         || hostname_lookups != HOSTNAME_LOOKUP_OFF)) {
960
961         if (apr_getnameinfo(&conn->remote_host, conn->client_addr, 0)
962             == APR_SUCCESS) {
963             ap_str_tolower(conn->remote_host);
964
965             if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) {
966                 conn->double_reverse = do_double_reverse(conn->double_reverse,
967                                                          conn->remote_host,
968                                                          conn->client_addr,
969                                                          conn->pool);
970                 if (conn->double_reverse != 1) {
971                     conn->remote_host = NULL;
972                 }
973             }
974         }
975
976         /* if failed, set it to the NULL string to indicate error */
977         if (conn->remote_host == NULL) {
978             conn->remote_host = "";
979         }
980     }
981
982     if (type == REMOTE_DOUBLE_REV) {
983         conn->double_reverse = do_double_reverse(conn->double_reverse,
984                                                  conn->remote_host,
985                                                  conn->client_addr, conn->pool);
986         if (conn->double_reverse == -1) {
987             return NULL;
988         }
989     }
990
991     /*
992      * Return the desired information; either the remote DNS name, if found,
993      * or either NULL (if the hostname was requested) or the IP address
994      * (if any identifier was requested).
995      */
996     if (conn->remote_host != NULL && conn->remote_host[0] != '\0') {
997         return conn->remote_host;
998     }
999     else {
1000         if (type == REMOTE_HOST || type == REMOTE_DOUBLE_REV) {
1001             return NULL;
1002         }
1003         else {
1004             *str_is_ip = 1;
1005             return conn->client_ip;
1006         }
1007     }
1008 }
1009
1010 AP_DECLARE(const char *) ap_get_useragent_host(request_rec *r,
1011                                                int type, int *str_is_ip)
1012 {
1013     conn_rec *conn = r->connection;
1014     int hostname_lookups;
1015     int ignored_str_is_ip;
1016
1017     if (r->useragent_addr == conn->client_addr) {
1018         return ap_get_remote_host(conn, r->per_dir_config, type, str_is_ip);
1019     }
1020
1021     if (!str_is_ip) { /* caller doesn't want to know */
1022         str_is_ip = &ignored_str_is_ip;
1023     }
1024     *str_is_ip = 0;
1025
1026     hostname_lookups = ((core_dir_config *)
1027                         ap_get_core_module_config(r->per_dir_config))
1028                             ->hostname_lookups;
1029     if (hostname_lookups == HOSTNAME_LOOKUP_UNSET) {
1030         hostname_lookups = HOSTNAME_LOOKUP_OFF;
1031     }
1032
1033     if (type != REMOTE_NOLOOKUP
1034         && r->useragent_host == NULL
1035         && (type == REMOTE_DOUBLE_REV
1036         || hostname_lookups != HOSTNAME_LOOKUP_OFF)) {
1037
1038         if (apr_getnameinfo(&r->useragent_host, r->useragent_addr, 0)
1039             == APR_SUCCESS) {
1040             ap_str_tolower(r->useragent_host);
1041
1042             if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) {
1043                 r->double_reverse = do_double_reverse(r->double_reverse,
1044                                                       r->useragent_host,
1045                                                       r->useragent_addr,
1046                                                       r->pool);
1047                 if (r->double_reverse != 1) {
1048                     r->useragent_host = NULL;
1049                 }
1050             }
1051         }
1052
1053         /* if failed, set it to the NULL string to indicate error */
1054         if (r->useragent_host == NULL) {
1055             r->useragent_host = "";
1056         }
1057     }
1058
1059     if (type == REMOTE_DOUBLE_REV) {
1060         r->double_reverse = do_double_reverse(r->double_reverse,
1061                                               r->useragent_host,
1062                                               r->useragent_addr, r->pool);
1063         if (r->double_reverse == -1) {
1064             return NULL;
1065         }
1066     }
1067
1068     /*
1069      * Return the desired information; either the remote DNS name, if found,
1070      * or either NULL (if the hostname was requested) or the IP address
1071      * (if any identifier was requested).
1072      */
1073     if (r->useragent_host != NULL && r->useragent_host[0] != '\0') {
1074         return r->useragent_host;
1075     }
1076     else {
1077         if (type == REMOTE_HOST || type == REMOTE_DOUBLE_REV) {
1078             return NULL;
1079         }
1080         else {
1081             *str_is_ip = 1;
1082             return r->useragent_ip;
1083         }
1084     }
1085 }
1086
1087 /*
1088  * Optional function coming from mod_ident, used for looking up ident user
1089  */
1090 static APR_OPTIONAL_FN_TYPE(ap_ident_lookup) *ident_lookup;
1091
1092 AP_DECLARE(const char *) ap_get_remote_logname(request_rec *r)
1093 {
1094     if (r->connection->remote_logname != NULL) {
1095         return r->connection->remote_logname;
1096     }
1097
1098     if (ident_lookup) {
1099         return ident_lookup(r);
1100     }
1101
1102     return NULL;
1103 }
1104
1105 /* There are two options regarding what the "name" of a server is.  The
1106  * "canonical" name as defined by ServerName and Port, or the "client's
1107  * name" as supplied by a possible Host: header or full URI.
1108  *
1109  * The DNS option to UseCanonicalName causes this routine to do a
1110  * reverse lookup on the local IP address of the connection and use
1111  * that for the ServerName. This makes its value more reliable while
1112  * at the same time allowing Demon's magic virtual hosting to work.
1113  * The assumption is that DNS lookups are sufficiently quick...
1114  * -- fanf 1998-10-03
1115  */
1116 AP_DECLARE(const char *) ap_get_server_name(request_rec *r)
1117 {
1118     conn_rec *conn = r->connection;
1119     core_dir_config *d;
1120     const char *retval;
1121
1122     d = (core_dir_config *)ap_get_core_module_config(r->per_dir_config);
1123
1124     switch (d->use_canonical_name) {
1125         case USE_CANONICAL_NAME_ON:
1126             retval = r->server->server_hostname;
1127             break;
1128         case USE_CANONICAL_NAME_DNS:
1129             if (conn->local_host == NULL) {
1130                 if (apr_getnameinfo(&conn->local_host,
1131                                 conn->local_addr, 0) != APR_SUCCESS)
1132                     conn->local_host = apr_pstrdup(conn->pool,
1133                                                r->server->server_hostname);
1134                 else {
1135                     ap_str_tolower(conn->local_host);
1136                 }
1137             }
1138             retval = conn->local_host;
1139             break;
1140         case USE_CANONICAL_NAME_OFF:
1141         case USE_CANONICAL_NAME_UNSET:
1142             retval = r->hostname ? r->hostname : r->server->server_hostname;
1143             break;
1144         default:
1145             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00109)
1146                          "ap_get_server_name: Invalid UCN Option somehow");
1147             retval = "localhost";
1148             break;
1149     }
1150     return retval;
1151 }
1152
1153 /*
1154  * Get the current server name from the request for the purposes
1155  * of using in a URL.  If the server name is an IPv6 literal
1156  * address, it will be returned in URL format (e.g., "[fe80::1]").
1157  */
1158 AP_DECLARE(const char *) ap_get_server_name_for_url(request_rec *r)
1159 {
1160     const char *plain_server_name = ap_get_server_name(r);
1161
1162 #if APR_HAVE_IPV6
1163     if (ap_strchr_c(plain_server_name, ':')) { /* IPv6 literal? */
1164         return apr_pstrcat(r->pool, "[", plain_server_name, "]", NULL);
1165     }
1166 #endif
1167     return plain_server_name;
1168 }
1169
1170 AP_DECLARE(apr_port_t) ap_get_server_port(const request_rec *r)
1171 {
1172     apr_port_t port;
1173     core_dir_config *d =
1174       (core_dir_config *)ap_get_core_module_config(r->per_dir_config);
1175
1176     switch (d->use_canonical_name) {
1177         case USE_CANONICAL_NAME_OFF:
1178         case USE_CANONICAL_NAME_DNS:
1179         case USE_CANONICAL_NAME_UNSET:
1180             if (d->use_canonical_phys_port == USE_CANONICAL_PHYS_PORT_ON)
1181                 port = r->parsed_uri.port_str ? r->parsed_uri.port :
1182                        r->connection->local_addr->port ? r->connection->local_addr->port :
1183                        r->server->port ? r->server->port :
1184                        ap_default_port(r);
1185             else /* USE_CANONICAL_PHYS_PORT_OFF or USE_CANONICAL_PHYS_PORT_UNSET */
1186                 port = r->parsed_uri.port_str ? r->parsed_uri.port :
1187                        r->server->port ? r->server->port :
1188                        ap_default_port(r);
1189             break;
1190         case USE_CANONICAL_NAME_ON:
1191             /* With UseCanonicalName on (and in all versions prior to 1.3)
1192              * Apache will use the hostname and port specified in the
1193              * ServerName directive to construct a canonical name for the
1194              * server. (If no port was specified in the ServerName
1195              * directive, Apache uses the port supplied by the client if
1196              * any is supplied, and finally the default port for the protocol
1197              * used.
1198              */
1199             if (d->use_canonical_phys_port == USE_CANONICAL_PHYS_PORT_ON)
1200                 port = r->server->port ? r->server->port :
1201                        r->connection->local_addr->port ? r->connection->local_addr->port :
1202                        ap_default_port(r);
1203             else /* USE_CANONICAL_PHYS_PORT_OFF or USE_CANONICAL_PHYS_PORT_UNSET */
1204                 port = r->server->port ? r->server->port :
1205                        ap_default_port(r);
1206             break;
1207         default:
1208             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00110)
1209                          "ap_get_server_port: Invalid UCN Option somehow");
1210             port = ap_default_port(r);
1211             break;
1212     }
1213
1214     return port;
1215 }
1216
1217 AP_DECLARE(char *) ap_construct_url(apr_pool_t *p, const char *uri,
1218                                     request_rec *r)
1219 {
1220     unsigned port = ap_get_server_port(r);
1221     const char *host = ap_get_server_name_for_url(r);
1222
1223     if (ap_is_default_port(port, r)) {
1224         return apr_pstrcat(p, ap_http_scheme(r), "://", host, uri, NULL);
1225     }
1226
1227     return apr_psprintf(p, "%s://%s:%u%s", ap_http_scheme(r), host, port, uri);
1228 }
1229
1230 AP_DECLARE(apr_off_t) ap_get_limit_req_body(const request_rec *r)
1231 {
1232     core_dir_config *d =
1233       (core_dir_config *)ap_get_core_module_config(r->per_dir_config);
1234
1235     if (d->limit_req_body == AP_LIMIT_REQ_BODY_UNSET) {
1236         return AP_DEFAULT_LIMIT_REQ_BODY;
1237     }
1238
1239     return d->limit_req_body;
1240 }
1241
1242
1243 /*****************************************************************
1244  *
1245  * Commands... this module handles almost all of the NCSA httpd.conf
1246  * commands, but most of the old srm.conf is in the modules.
1247  */
1248
1249
1250 /* returns a parent if it matches the given directive */
1251 static const ap_directive_t * find_parent(const ap_directive_t *dirp,
1252                                           const char *what)
1253 {
1254     while (dirp->parent != NULL) {
1255         dirp = dirp->parent;
1256
1257         /* ### it would be nice to have atom-ized directives */
1258         if (ap_casecmpstr(dirp->directive, what) == 0)
1259             return dirp;
1260     }
1261
1262     return NULL;
1263 }
1264
1265 AP_DECLARE(const char *) ap_check_cmd_context(cmd_parms *cmd,
1266                                               unsigned forbidden)
1267 {
1268     const char *gt = (cmd->cmd->name[0] == '<'
1269                       && cmd->cmd->name[strlen(cmd->cmd->name)-1] != '>')
1270                          ? ">" : "";
1271     const ap_directive_t *found;
1272
1273     if ((forbidden & NOT_IN_VIRTUALHOST) && cmd->server->is_virtual) {
1274         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1275                            " cannot occur within <VirtualHost> section", NULL);
1276     }
1277
1278     if ((forbidden & (NOT_IN_LIMIT | NOT_IN_DIR_LOC_FILE))
1279         && cmd->limited != -1) {
1280         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1281                            " cannot occur within <Limit> or <LimitExcept> "
1282                            "section", NULL);
1283     }
1284
1285     if ((forbidden & NOT_IN_HTACCESS) && (cmd->pool == cmd->temp_pool)) {
1286          return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1287                             " cannot occur within htaccess files", NULL);
1288     }
1289
1290     if ((forbidden & NOT_IN_DIR_LOC_FILE) == NOT_IN_DIR_LOC_FILE) {
1291         if (cmd->path != NULL) {
1292             return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1293                             " cannot occur within <Directory/Location/Files> "
1294                             "section", NULL);
1295         }
1296         if (cmd->cmd->req_override & EXEC_ON_READ) {
1297             /* EXEC_ON_READ must be NOT_IN_DIR_LOC_FILE, if not, it will
1298              * (deliberately) segfault below in the individual tests...
1299              */
1300             return NULL;
1301         }
1302     }
1303
1304     if (((forbidden & NOT_IN_DIRECTORY)
1305          && ((found = find_parent(cmd->directive, "<Directory"))
1306              || (found = find_parent(cmd->directive, "<DirectoryMatch"))))
1307         || ((forbidden & NOT_IN_LOCATION)
1308             && ((found = find_parent(cmd->directive, "<Location"))
1309                 || (found = find_parent(cmd->directive, "<LocationMatch"))))
1310         || ((forbidden & NOT_IN_FILES)
1311             && ((found = find_parent(cmd->directive, "<Files"))
1312                 || (found = find_parent(cmd->directive, "<FilesMatch"))
1313                 || (found = find_parent(cmd->directive, "<If"))
1314                 || (found = find_parent(cmd->directive, "<ElseIf"))
1315                 || (found = find_parent(cmd->directive, "<Else"))))) {
1316         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1317                            " cannot occur within ", found->directive,
1318                            "> section", NULL);
1319     }
1320
1321     return NULL;
1322 }
1323
1324 static const char *set_access_name(cmd_parms *cmd, void *dummy,
1325                                    const char *arg)
1326 {
1327     void *sconf = cmd->server->module_config;
1328     core_server_config *conf = ap_get_core_module_config(sconf);
1329
1330     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
1331     if (err != NULL) {
1332         return err;
1333     }
1334
1335     conf->access_name = apr_pstrdup(cmd->pool, arg);
1336     return NULL;
1337 }
1338
1339 AP_DECLARE(const char *) ap_resolve_env(apr_pool_t *p, const char * word)
1340 {
1341 # define SMALL_EXPANSION 5
1342     struct sll {
1343         struct sll *next;
1344         const char *string;
1345         apr_size_t len;
1346     } *result, *current, sresult[SMALL_EXPANSION];
1347     char *res_buf, *cp;
1348     const char *s, *e, *ep;
1349     unsigned spc;
1350     apr_size_t outlen;
1351
1352     s = ap_strchr_c(word, '$');
1353     if (!s) {
1354         return word;
1355     }
1356
1357     /* well, actually something to do */
1358     ep = word + strlen(word);
1359     spc = 0;
1360     result = current = &(sresult[spc++]);
1361     current->next = NULL;
1362     current->string = word;
1363     current->len = s - word;
1364     outlen = current->len;
1365
1366     do {
1367         /* prepare next entry */
1368         if (current->len) {
1369             current->next = (spc < SMALL_EXPANSION)
1370                             ? &(sresult[spc++])
1371                             : (struct sll *)apr_palloc(p,
1372                                                        sizeof(*current->next));
1373             current = current->next;
1374             current->next = NULL;
1375             current->len = 0;
1376         }
1377
1378         if (*s == '$') {
1379             if (s[1] == '{' && (e = ap_strchr_c(s+2, '}'))) {
1380                 char *name = apr_pstrmemdup(p, s+2, e-s-2);
1381                 word = NULL;
1382                 if (server_config_defined_vars)
1383                     word = apr_table_get(server_config_defined_vars, name);
1384                 if (!word)
1385                     word = getenv(name);
1386                 if (word) {
1387                     current->string = word;
1388                     current->len = strlen(word);
1389                     outlen += current->len;
1390                 }
1391                 else {
1392                     if (ap_strchr(name, ':') == 0)
1393                         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(00111)
1394                                      "Config variable ${%s} is not defined",
1395                                      name);
1396                     current->string = s;
1397                     current->len = e - s + 1;
1398                     outlen += current->len;
1399                 }
1400                 s = e + 1;
1401             }
1402             else {
1403                 current->string = s++;
1404                 current->len = 1;
1405                 ++outlen;
1406             }
1407         }
1408         else {
1409             word = s;
1410             s = ap_strchr_c(s, '$');
1411             current->string = word;
1412             current->len = s ? s - word : ep - word;
1413             outlen += current->len;
1414         }
1415     } while (s && *s);
1416
1417     /* assemble result */
1418     res_buf = cp = apr_palloc(p, outlen + 1);
1419     do {
1420         if (result->len) {
1421             memcpy(cp, result->string, result->len);
1422             cp += result->len;
1423         }
1424         result = result->next;
1425     } while (result);
1426     res_buf[outlen] = '\0';
1427
1428     return res_buf;
1429 }
1430
1431 static int reset_config_defines(void *dummy)
1432 {
1433     ap_server_config_defines = saved_server_config_defines;
1434     saved_server_config_defines = NULL;
1435     server_config_defined_vars = NULL;
1436     return OK;
1437 }
1438
1439 /*
1440  * Make sure we can revert the effects of Define/UnDefine when restarting.
1441  * This function must be called once per loading of the config, before
1442  * ap_server_config_defines is changed. This may be during reading of the
1443  * config, which is even before the pre_config hook is run (due to
1444  * EXEC_ON_READ for Define/UnDefine).
1445  */
1446 static void init_config_defines(apr_pool_t *pconf)
1447 {
1448     saved_server_config_defines = ap_server_config_defines;
1449     /* Use apr_array_copy instead of apr_array_copy_hdr because it does not
1450      * protect from the way unset_define removes entries.
1451      */
1452     ap_server_config_defines = apr_array_copy(pconf, ap_server_config_defines);
1453 }
1454
1455 static const char *set_define(cmd_parms *cmd, void *dummy,
1456                               const char *name, const char *value)
1457 {
1458     if (cmd->parent && ap_casecmpstr(cmd->parent->directive, "<VirtualHost")) {
1459         return apr_pstrcat(cmd->pool, cmd->cmd->name, " is not valid in ",
1460                                       cmd->parent->directive, " context", NULL);
1461     }
1462
1463     if (ap_strchr_c(name, ':') != NULL) {
1464         return "Variable name must not contain ':'";
1465     }
1466
1467     if (!saved_server_config_defines) {
1468         init_config_defines(cmd->pool);
1469     }
1470     if (!ap_exists_config_define(name)) {
1471         const char **newv = (const char **)apr_array_push(ap_server_config_defines);
1472         *newv = name;
1473     }
1474     if (value) {
1475         if (!server_config_defined_vars) {
1476             server_config_defined_vars = apr_table_make(cmd->pool, 5);
1477         }
1478         apr_table_setn(server_config_defined_vars, name, value);
1479     }
1480
1481     return NULL;
1482 }
1483
1484 static const char *unset_define(cmd_parms *cmd, void *dummy,
1485                                 const char *name)
1486 {
1487     int i;
1488     char **defines;
1489     if (cmd->parent && ap_casecmpstr(cmd->parent->directive, "<VirtualHost")) {
1490         return apr_pstrcat(cmd->pool, cmd->cmd->name, " is not valid in ",
1491                                       cmd->parent->directive, " context", NULL);
1492     }
1493
1494     if (ap_strchr_c(name, ':') != NULL) {
1495         return "Variable name must not contain ':'";
1496     }
1497
1498     if (!saved_server_config_defines) {
1499         init_config_defines(cmd->pool);
1500     }
1501
1502     defines = (char **)ap_server_config_defines->elts;
1503     for (i = 0; i < ap_server_config_defines->nelts; i++) {
1504         if (strcmp(defines[i], name) == 0) {
1505             defines[i] = *(char **)apr_array_pop(ap_server_config_defines);
1506             break;
1507         }
1508     }
1509
1510     if (server_config_defined_vars) {
1511         apr_table_unset(server_config_defined_vars, name);
1512     }
1513
1514     return NULL;
1515 }
1516
1517 static const char *generate_message(cmd_parms *cmd, void *dummy,
1518                                     const char *arg)
1519 {
1520     /* cast with 64-bit warning avoidance */
1521     int level = (cmd->info==(void*)APLOG_ERR)? APLOG_ERR: APLOG_WARNING;
1522     char * msg;
1523
1524     /* get position information from wherever we can? */
1525     ap_configfile_t * cf = cmd->config_file;
1526     ap_directive_t const * ed1 = cmd->directive;
1527     ap_directive_t const * ed2 = cmd->err_directive;
1528
1529     /* expect an argument */
1530     if (!arg || !*arg) {
1531         return "The Error or Warning directive was used with no message.";
1532     }
1533
1534     /* set message, strip off quotes if necessary */
1535     msg = (char *)arg;
1536     if (*arg == '"' || *arg == '\'') {
1537         apr_size_t len = strlen(arg);
1538         char last = *(arg + len - 1);
1539
1540         if (*arg == last) {
1541             msg = apr_pstrndup(cmd->pool, arg + 1, len - 2);
1542         }
1543     }
1544
1545     /* generate error or warning with a configuration file position.
1546      * the log is displayed on the terminal as no log file is opened yet.
1547      */
1548     ap_log_error(APLOG_MARK, level, 0, NULL,
1549                  "%s on line %d of %s", msg,
1550                  cf? cf->line_number:
1551                    ed1? ed1->line_num:
1552                      ed2? ed2->line_num: -1,
1553                  cf? cf->name:
1554                    ed1? ed1->filename:
1555                      ed2? ed2->filename: "<UNKNOWN>");
1556
1557     /* message displayed above, return will stop configuration processing */
1558     return level==APLOG_ERR?
1559         "Configuration processing stopped by Error directive": NULL;
1560 }
1561
1562 #ifdef GPROF
1563 static const char *set_gprof_dir(cmd_parms *cmd, void *dummy, const char *arg)
1564 {
1565     void *sconf = cmd->server->module_config;
1566     core_server_config *conf = ap_get_core_module_config(sconf);
1567
1568     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
1569     if (err != NULL) {
1570         return err;
1571     }
1572
1573     conf->gprof_dir = arg;
1574     return NULL;
1575 }
1576 #endif /*GPROF*/
1577
1578 static const char *set_add_default_charset(cmd_parms *cmd,
1579                                            void *d_, const char *arg)
1580 {
1581     core_dir_config *d = d_;
1582
1583     if (!ap_casecmpstr(arg, "Off")) {
1584        d->add_default_charset = ADD_DEFAULT_CHARSET_OFF;
1585     }
1586     else if (!ap_casecmpstr(arg, "On")) {
1587        d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
1588        d->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
1589     }
1590     else {
1591        d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
1592        d->add_default_charset_name = arg;
1593     }
1594
1595     return NULL;
1596 }
1597
1598 static const char *set_document_root(cmd_parms *cmd, void *dummy,
1599                                      const char *arg)
1600 {
1601     void *sconf = cmd->server->module_config;
1602     core_server_config *conf = ap_get_core_module_config(sconf);
1603
1604     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
1605     if (err != NULL) {
1606         return err;
1607     }
1608
1609     /* When ap_document_root_check is false; skip all the stuff below */
1610     if (!ap_document_root_check) {
1611        conf->ap_document_root = arg;
1612        return NULL;
1613     }
1614
1615     /* Make it absolute, relative to ServerRoot */
1616     arg = ap_server_root_relative(cmd->pool, arg);
1617     if (arg == NULL) {
1618         return "DocumentRoot must be a directory";
1619     }
1620
1621     /* TODO: ap_configtestonly */
1622     if (apr_filepath_merge((char**)&conf->ap_document_root, NULL, arg,
1623                            APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS
1624         || !ap_is_directory(cmd->temp_pool, arg)) {
1625         if (cmd->server->is_virtual) {
1626             ap_log_perror(APLOG_MARK, APLOG_STARTUP, 0,
1627                           cmd->pool, APLOGNO(00112)
1628                           "Warning: DocumentRoot [%s] does not exist",
1629                           arg);
1630             conf->ap_document_root = arg;
1631         }
1632         else {
1633             return apr_psprintf(cmd->pool, 
1634                                 "DocumentRoot '%s' is not a directory, or is not readable",
1635                                 arg);
1636         }
1637     }
1638     return NULL;
1639 }
1640
1641 AP_DECLARE(void) ap_custom_response(request_rec *r, int status,
1642                                     const char *string)
1643 {
1644     core_request_config *conf = ap_get_core_module_config(r->request_config);
1645     int idx;
1646
1647     if (conf->response_code_strings == NULL) {
1648         conf->response_code_strings =
1649             apr_pcalloc(r->pool,
1650                         sizeof(*conf->response_code_strings) * RESPONSE_CODES);
1651     }
1652
1653     idx = ap_index_of_response(status);
1654
1655     conf->response_code_strings[idx] =
1656        ((ap_is_url(string) || (*string == '/')) && (*string != '"')) ?
1657        apr_pstrdup(r->pool, string) : apr_pstrcat(r->pool, "\"", string, NULL);
1658 }
1659
1660 static const char *set_error_document(cmd_parms *cmd, void *conf_,
1661                                       const char *errno_str, const char *msg)
1662 {
1663     core_dir_config *conf = conf_;
1664     int error_number, index_number, idx500;
1665     enum { MSG, LOCAL_PATH, REMOTE_PATH } what = MSG;
1666
1667     /* 1st parameter should be a 3 digit number, which we recognize;
1668      * convert it into an array index
1669      */
1670     error_number = atoi(errno_str);
1671     idx500 = ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR);
1672
1673     if (error_number == HTTP_INTERNAL_SERVER_ERROR) {
1674         index_number = idx500;
1675     }
1676     else if ((index_number = ap_index_of_response(error_number)) == idx500) {
1677         return apr_pstrcat(cmd->pool, "Unsupported HTTP response code ",
1678                            errno_str, NULL);
1679     }
1680
1681     /* Heuristic to determine second argument. */
1682     if (ap_strchr_c(msg,' '))
1683         what = MSG;
1684     else if (msg[0] == '/')
1685         what = LOCAL_PATH;
1686     else if (ap_is_url(msg))
1687         what = REMOTE_PATH;
1688     else
1689         what = MSG;
1690
1691     /* The entry should be ignored if it is a full URL for a 401 error */
1692
1693     if (error_number == 401 && what == REMOTE_PATH) {
1694         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, cmd->server, APLOGNO(00113)
1695                      "%s:%d cannot use a full URL in a 401 ErrorDocument "
1696                      "directive --- ignoring!", cmd->directive->filename, cmd->directive->line_num);
1697     }
1698     else { /* Store it... */
1699         if (conf->response_code_exprs == NULL) {
1700             conf->response_code_exprs = apr_hash_make(cmd->pool);
1701         }
1702
1703         if (ap_casecmpstr(msg, "default") == 0) {
1704             /* special case: ErrorDocument 404 default restores the
1705              * canned server error response
1706              */
1707             apr_hash_set(conf->response_code_exprs,
1708                     apr_pmemdup(cmd->pool, &index_number, sizeof(index_number)),
1709                     sizeof(index_number), &errordocument_default);
1710         }
1711         else {
1712             ap_expr_info_t *expr;
1713             const char *expr_err = NULL;
1714
1715             /* hack. Prefix a " if it is a msg; as that is what
1716              * http_protocol.c relies on to distinguish between
1717              * a msg and a (local) path.
1718              */
1719             const char *response =
1720                     (what == MSG) ? apr_pstrcat(cmd->pool, "\"", msg, NULL) :
1721                             apr_pstrdup(cmd->pool, msg);
1722
1723             expr = ap_expr_parse_cmd(cmd, response, AP_EXPR_FLAG_STRING_RESULT,
1724                     &expr_err, NULL);
1725
1726             if (expr_err) {
1727                 return apr_pstrcat(cmd->temp_pool,
1728                                    "Cannot parse expression in ErrorDocument: ",
1729                                    expr_err, NULL);
1730             }
1731
1732             apr_hash_set(conf->response_code_exprs,
1733                     apr_pmemdup(cmd->pool, &index_number, sizeof(index_number)),
1734                     sizeof(index_number), expr);
1735
1736         }
1737     }
1738
1739     return NULL;
1740 }
1741
1742 static const char *set_allow_opts(cmd_parms *cmd, allow_options_t *opts,
1743                                   const char *l)
1744 {
1745     allow_options_t opt;
1746     int first = 1;
1747
1748     char *w, *p = (char *) l;
1749     char *tok_state;
1750
1751     while ((w = apr_strtok(p, ",", &tok_state)) != NULL) {
1752
1753         if (first) {
1754             p = NULL;
1755             *opts = OPT_NONE;
1756             first = 0;
1757         }
1758
1759         if (!ap_casecmpstr(w, "Indexes")) {
1760             opt = OPT_INDEXES;
1761         }
1762         else if (!ap_casecmpstr(w, "Includes")) {
1763             /* If Includes is permitted, both Includes and
1764              * IncludesNOEXEC may be changed. */
1765             opt = (OPT_INCLUDES | OPT_INC_WITH_EXEC);
1766         }
1767         else if (!ap_casecmpstr(w, "IncludesNOEXEC")) {
1768             opt = OPT_INCLUDES;
1769         }
1770         else if (!ap_casecmpstr(w, "FollowSymLinks")) {
1771             opt = OPT_SYM_LINKS;
1772         }
1773         else if (!ap_casecmpstr(w, "SymLinksIfOwnerMatch")) {
1774             opt = OPT_SYM_OWNER;
1775         }
1776         else if (!ap_casecmpstr(w, "ExecCGI")) {
1777             opt = OPT_EXECCGI;
1778         }
1779         else if (!ap_casecmpstr(w, "MultiViews")) {
1780             opt = OPT_MULTI;
1781         }
1782         else if (!ap_casecmpstr(w, "RunScripts")) { /* AI backcompat. Yuck */
1783             opt = OPT_MULTI|OPT_EXECCGI;
1784         }
1785         else if (!ap_casecmpstr(w, "None")) {
1786             opt = OPT_NONE;
1787         }
1788         else if (!ap_casecmpstr(w, "All")) {
1789             opt = OPT_ALL;
1790         }
1791         else {
1792             return apr_pstrcat(cmd->pool, "Illegal option ", w, NULL);
1793         }
1794
1795         *opts |= opt;
1796     }
1797
1798     (*opts) &= (~OPT_UNSET);
1799
1800     return NULL;
1801 }
1802
1803 static const char *set_override(cmd_parms *cmd, void *d_, const char *l)
1804 {
1805     core_dir_config *d = d_;
1806     char *w;
1807     char *k, *v;
1808     const char *err;
1809
1810     /* Throw a warning if we're in <Location> or <Files> */
1811     if (ap_check_cmd_context(cmd, NOT_IN_LOCATION | NOT_IN_FILES)) {
1812         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(00114)
1813                      "Useless use of AllowOverride in line %d of %s.",
1814                      cmd->directive->line_num, cmd->directive->filename);
1815     }
1816     if ((err = ap_check_cmd_context(cmd, NOT_IN_HTACCESS)) != NULL)
1817         return err;
1818
1819     d->override = OR_NONE;
1820     while (l[0]) {
1821         w = ap_getword_conf(cmd->temp_pool, &l);
1822
1823         k = w;
1824         v = strchr(k, '=');
1825         if (v) {
1826                 *v++ = '\0';
1827         }
1828
1829         if (!ap_casecmpstr(w, "Limit")) {
1830             d->override |= OR_LIMIT;
1831         }
1832         else if (!ap_casecmpstr(k, "Options")) {
1833             d->override |= OR_OPTIONS;
1834             if (v)
1835                 set_allow_opts(cmd, &(d->override_opts), v);
1836             else
1837                 d->override_opts = OPT_ALL;
1838         }
1839         else if (!ap_casecmpstr(w, "FileInfo")) {
1840             d->override |= OR_FILEINFO;
1841         }
1842         else if (!ap_casecmpstr(w, "AuthConfig")) {
1843             d->override |= OR_AUTHCFG;
1844         }
1845         else if (!ap_casecmpstr(w, "Indexes")) {
1846             d->override |= OR_INDEXES;
1847         }
1848         else if (!ap_casecmpstr(w, "Nonfatal")) {
1849             if (!ap_casecmpstr(v, "Override")) {
1850                 d->override |= NONFATAL_OVERRIDE;
1851             }
1852             else if (!ap_casecmpstr(v, "Unknown")) {
1853                 d->override |= NONFATAL_UNKNOWN;
1854             }
1855             else if (!ap_casecmpstr(v, "All")) {
1856                 d->override |= NONFATAL_ALL;
1857             }
1858         }
1859         else if (!ap_casecmpstr(w, "None")) {
1860             d->override = OR_NONE;
1861         }
1862         else if (!ap_casecmpstr(w, "All")) {
1863             d->override = OR_ALL;
1864         }
1865         else {
1866             return apr_pstrcat(cmd->pool, "Illegal override option ", w, NULL);
1867         }
1868
1869         d->override &= ~OR_UNSET;
1870     }
1871
1872     return NULL;
1873 }
1874
1875 static const char *set_cgi_pass_auth(cmd_parms *cmd, void *d_, int flag)
1876 {
1877     core_dir_config *d = d_;
1878
1879     d->cgi_pass_auth = flag ? AP_CGI_PASS_AUTH_ON : AP_CGI_PASS_AUTH_OFF;
1880
1881     return NULL;
1882 }
1883
1884 static const char *set_cgi_var(cmd_parms *cmd, void *d_,
1885                                const char *var, const char *rule_)
1886 {
1887     core_dir_config *d = d_;
1888     char *rule = apr_pstrdup(cmd->pool, rule_);
1889
1890     ap_str_tolower(rule);
1891
1892     if (!strcmp(var, "REQUEST_URI")) {
1893         if (strcmp(rule, "current-uri") && strcmp(rule, "original-uri")) {
1894             return "Valid rules for REQUEST_URI are 'current-uri' and 'original-uri'";
1895         }
1896     }
1897     else {
1898         return apr_pstrcat(cmd->pool, "Unrecognized CGI variable: \"",
1899                            var, "\"", NULL);
1900     }
1901
1902     if (!d->cgi_var_rules) {
1903         d->cgi_var_rules = apr_hash_make(cmd->pool);
1904     }
1905     apr_hash_set(d->cgi_var_rules, var, APR_HASH_KEY_STRING, rule);
1906     return NULL;
1907 }
1908
1909 static const char *set_qualify_redirect_url(cmd_parms *cmd, void *d_, int flag)
1910 {
1911     core_dir_config *d = d_;
1912
1913     d->qualify_redirect_url = flag ? AP_CORE_CONFIG_ON : AP_CORE_CONFIG_OFF;
1914
1915     return NULL;
1916 }
1917
1918 static const char *set_override_list(cmd_parms *cmd, void *d_, int argc, char *const argv[])
1919 {
1920     core_dir_config *d = d_;
1921     int i;
1922     const char *err;
1923
1924     /* Throw a warning if we're in <Location> or <Files> */
1925     if (ap_check_cmd_context(cmd, NOT_IN_LOCATION | NOT_IN_FILES)) {
1926         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(00115)
1927                      "Useless use of AllowOverrideList at %s:%d",
1928                      cmd->directive->filename, cmd->directive->line_num);
1929     }
1930     if ((err = ap_check_cmd_context(cmd, NOT_IN_HTACCESS)) != NULL)
1931         return err;
1932
1933     d->override_list = apr_table_make(cmd->pool, argc);
1934
1935     for (i = 0; i < argc; i++) {
1936         if (!ap_casecmpstr(argv[i], "None")) {
1937             if (argc != 1) {
1938                 return "'None' not allowed with other directives in "
1939                        "AllowOverrideList";
1940             }
1941             return NULL;
1942         }
1943         else {
1944             const command_rec *result = NULL;
1945             module *mod = ap_top_module;
1946
1947             result = ap_find_command_in_modules(argv[i], &mod);
1948             if (result == NULL) {
1949                 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
1950                              APLOGNO(00116) "Discarding unrecognized "
1951                              "directive `%s' in AllowOverrideList at %s:%d",
1952                              argv[i], cmd->directive->filename,
1953                              cmd->directive->line_num);
1954                 continue;
1955             }
1956             else if ((result->req_override & (OR_ALL|ACCESS_CONF)) == 0) {
1957                 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
1958                              APLOGNO(02304) "Discarding directive `%s' not "
1959                              "allowed in AllowOverrideList at %s:%d",
1960                              argv[i], cmd->directive->filename,
1961                              cmd->directive->line_num);
1962                 continue;
1963             }
1964             else {
1965                 apr_table_setn(d->override_list, argv[i], "1");
1966             }
1967         }
1968     }
1969
1970     return NULL;
1971 }
1972
1973 static const char *set_options(cmd_parms *cmd, void *d_, const char *l)
1974 {
1975     core_dir_config *d = d_;
1976     allow_options_t opt;
1977     int first = 1;
1978     int merge = 0;
1979     int all_none = 0;
1980     char action;
1981
1982     while (l[0]) {
1983         char *w = ap_getword_conf(cmd->temp_pool, &l);
1984         action = '\0';
1985
1986         if (*w == '+' || *w == '-') {
1987             action = *(w++);
1988             if (!merge && !first && !all_none) {
1989                 return "Either all Options must start with + or -, or no Option may.";
1990             }
1991             merge = 1;
1992         }
1993         else if (first) {
1994             d->opts = OPT_NONE;
1995         }
1996         else if (merge) {
1997             return "Either all Options must start with + or -, or no Option may.";
1998         }
1999
2000         if (!ap_casecmpstr(w, "Indexes")) {
2001             opt = OPT_INDEXES;
2002         }
2003         else if (!ap_casecmpstr(w, "Includes")) {
2004             opt = (OPT_INCLUDES | OPT_INC_WITH_EXEC);
2005         }
2006         else if (!ap_casecmpstr(w, "IncludesNOEXEC")) {
2007             opt = OPT_INCLUDES;
2008         }
2009         else if (!ap_casecmpstr(w, "FollowSymLinks")) {
2010             opt = OPT_SYM_LINKS;
2011         }
2012         else if (!ap_casecmpstr(w, "SymLinksIfOwnerMatch")) {
2013             opt = OPT_SYM_OWNER;
2014         }
2015         else if (!ap_casecmpstr(w, "ExecCGI")) {
2016             opt = OPT_EXECCGI;
2017         }
2018         else if (!ap_casecmpstr(w, "MultiViews")) {
2019             opt = OPT_MULTI;
2020         }
2021         else if (!ap_casecmpstr(w, "RunScripts")) { /* AI backcompat. Yuck */
2022             opt = OPT_MULTI|OPT_EXECCGI;
2023         }
2024         else if (!ap_casecmpstr(w, "None")) {
2025             if (!first) {
2026                 return "'Options None' must be the first Option given.";
2027             }
2028             else if (merge) { /* Only works since None may not follow any other option. */
2029                 return "You may not use 'Options +None' or 'Options -None'.";
2030             }
2031             opt = OPT_NONE;
2032             all_none = 1;
2033         }
2034         else if (!ap_casecmpstr(w, "All")) {
2035             if (!first) {
2036                 return "'Options All' must be the first option given.";
2037             }
2038             else if (merge) { /* Only works since All may not follow any other option. */
2039                 return "You may not use 'Options +All' or 'Options -All'.";
2040             }
2041             opt = OPT_ALL;
2042             all_none = 1;
2043         }
2044         else {
2045             return apr_pstrcat(cmd->pool, "Illegal option ", w, NULL);
2046         }
2047
2048         if ( (cmd->override_opts & opt) != opt ) {
2049             return apr_pstrcat(cmd->pool, "Option ", w, " not allowed here", NULL);
2050         }
2051         else if (action == '-') {
2052             /* we ensure the invariant (d->opts_add & d->opts_remove) == 0 */
2053             d->opts_remove |= opt;
2054             d->opts_add &= ~opt;
2055             d->opts &= ~opt;
2056         }
2057         else if (action == '+') {
2058             d->opts_add |= opt;
2059             d->opts_remove &= ~opt;
2060             d->opts |= opt;
2061         }
2062         else {
2063             d->opts |= opt;
2064         }
2065
2066         first = 0;
2067     }
2068
2069     return NULL;
2070 }
2071
2072 static const char *set_default_type(cmd_parms *cmd, void *d_,
2073                                    const char *arg)
2074 {
2075     if (ap_casecmpstr(arg, "off") != 0 && ap_casecmpstr(arg, "none") != 0) {
2076         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(00117)
2077               "Ignoring deprecated use of DefaultType in line %d of %s.",
2078                      cmd->directive->line_num, cmd->directive->filename);
2079     }
2080
2081     return NULL;
2082 }
2083
2084 static const char *set_sethandler(cmd_parms *cmd,
2085                                      void *d_,
2086                                      const char *arg_)
2087 {
2088     core_dir_config *dirconf = d_;
2089     const char *err;
2090     dirconf->expr_handler = ap_expr_parse_cmd(cmd, arg_,
2091                                           AP_EXPR_FLAG_STRING_RESULT,
2092                                           &err, NULL);
2093     if (err) {
2094         return apr_pstrcat(cmd->pool,
2095                 "Can't parse expression : ", err, NULL);
2096     }
2097     return NULL;
2098 }
2099
2100 /*
2101  * Note what data should be used when forming file ETag values.
2102  * It would be nicer to do this as an ITERATE, but then we couldn't
2103  * remember the +/- state properly.
2104  */
2105 static const char *set_etag_bits(cmd_parms *cmd, void *mconfig,
2106                                  const char *args_p)
2107 {
2108     core_dir_config *cfg;
2109     etag_components_t bit;
2110     char action;
2111     char *token;
2112     const char *args;
2113     int valid;
2114     int first;
2115     int explicit;
2116
2117     cfg = (core_dir_config *)mconfig;
2118
2119     args = args_p;
2120     first = 1;
2121     explicit = 0;
2122     while (args[0] != '\0') {
2123         action = '*';
2124         bit = ETAG_UNSET;
2125         valid = 1;
2126         token = ap_getword_conf(cmd->temp_pool, &args);
2127         if ((*token == '+') || (*token == '-')) {
2128             action = *token;
2129             token++;
2130         }
2131         else {
2132             /*
2133              * The occurrence of an absolute setting wipes
2134              * out any previous relative ones.  The first such
2135              * occurrence forgets any inherited ones, too.
2136              */
2137             if (first) {
2138                 cfg->etag_bits = ETAG_UNSET;
2139                 cfg->etag_add = ETAG_UNSET;
2140                 cfg->etag_remove = ETAG_UNSET;
2141                 first = 0;
2142             }
2143         }
2144
2145         if (ap_casecmpstr(token, "None") == 0) {
2146             if (action != '*') {
2147                 valid = 0;
2148             }
2149             else {
2150                 cfg->etag_bits = bit = ETAG_NONE;
2151                 explicit = 1;
2152             }
2153         }
2154         else if (ap_casecmpstr(token, "All") == 0) {
2155             if (action != '*') {
2156                 valid = 0;
2157             }
2158             else {
2159                 explicit = 1;
2160                 cfg->etag_bits = bit = ETAG_ALL;
2161             }
2162         }
2163         else if (ap_casecmpstr(token, "Size") == 0) {
2164             bit = ETAG_SIZE;
2165         }
2166         else if ((ap_casecmpstr(token, "LMTime") == 0)
2167                  || (ap_casecmpstr(token, "MTime") == 0)
2168                  || (ap_casecmpstr(token, "LastModified") == 0)) {
2169             bit = ETAG_MTIME;
2170         }
2171         else if (ap_casecmpstr(token, "INode") == 0) {
2172             bit = ETAG_INODE;
2173         }
2174         else {
2175             return apr_pstrcat(cmd->pool, "Unknown keyword '",
2176                                token, "' for ", cmd->cmd->name,
2177                                " directive", NULL);
2178         }
2179
2180         if (! valid) {
2181             return apr_pstrcat(cmd->pool, cmd->cmd->name, " keyword '",
2182                                token, "' cannot be used with '+' or '-'",
2183                                NULL);
2184         }
2185
2186         if (action == '+') {
2187             /*
2188              * Make sure it's in the 'add' list and absent from the
2189              * 'subtract' list.
2190              */
2191             cfg->etag_add |= bit;
2192             cfg->etag_remove &= (~ bit);
2193         }
2194         else if (action == '-') {
2195             cfg->etag_remove |= bit;
2196             cfg->etag_add &= (~ bit);
2197         }
2198         else {
2199             /*
2200              * Non-relative values wipe out any + or - values
2201              * accumulated so far.
2202              */
2203             cfg->etag_bits |= bit;
2204             cfg->etag_add = ETAG_UNSET;
2205             cfg->etag_remove = ETAG_UNSET;
2206             explicit = 1;
2207         }
2208     }
2209
2210     /*
2211      * Any setting at all will clear the 'None' and 'Unset' bits.
2212      */
2213
2214     if (cfg->etag_add != ETAG_UNSET) {
2215         cfg->etag_add &= (~ ETAG_UNSET);
2216     }
2217
2218     if (cfg->etag_remove != ETAG_UNSET) {
2219         cfg->etag_remove &= (~ ETAG_UNSET);
2220     }
2221
2222     if (explicit) {
2223         cfg->etag_bits &= (~ ETAG_UNSET);
2224
2225         if ((cfg->etag_bits & ETAG_NONE) != ETAG_NONE) {
2226             cfg->etag_bits &= (~ ETAG_NONE);
2227         }
2228     }
2229
2230     return NULL;
2231 }
2232
2233 static const char *set_enable_mmap(cmd_parms *cmd, void *d_,
2234                                    const char *arg)
2235 {
2236     core_dir_config *d = d_;
2237
2238     if (ap_casecmpstr(arg, "on") == 0) {
2239         d->enable_mmap = ENABLE_MMAP_ON;
2240     }
2241     else if (ap_casecmpstr(arg, "off") == 0) {
2242         d->enable_mmap = ENABLE_MMAP_OFF;
2243     }
2244     else {
2245         return "parameter must be 'on' or 'off'";
2246     }
2247
2248     return NULL;
2249 }
2250
2251 static const char *set_enable_sendfile(cmd_parms *cmd, void *d_,
2252                                    const char *arg)
2253 {
2254     core_dir_config *d = d_;
2255
2256     if (ap_casecmpstr(arg, "on") == 0) {
2257         d->enable_sendfile = ENABLE_SENDFILE_ON;
2258     }
2259     else if (ap_casecmpstr(arg, "off") == 0) {
2260         d->enable_sendfile = ENABLE_SENDFILE_OFF;
2261     }
2262     else {
2263         return "parameter must be 'on' or 'off'";
2264     }
2265
2266     return NULL;
2267 }
2268
2269
2270 /*
2271  * Report a missing-'>' syntax error.
2272  */
2273 static char *unclosed_directive(cmd_parms *cmd)
2274 {
2275     return apr_pstrcat(cmd->pool, cmd->cmd->name,
2276                        "> directive missing closing '>'", NULL);
2277 }
2278
2279 /*
2280  * Report a missing args in '<Foo >' syntax error.
2281  */
2282 static char *missing_container_arg(cmd_parms *cmd)
2283 {
2284     return apr_pstrcat(cmd->pool, cmd->cmd->name,
2285                        "> directive requires additional arguments", NULL);
2286 }
2287
2288 AP_CORE_DECLARE_NONSTD(const char *) ap_limit_section(cmd_parms *cmd,
2289                                                       void *dummy,
2290                                                       const char *arg)
2291 {
2292     const char *endp = ap_strrchr_c(arg, '>');
2293     const char *limited_methods;
2294     void *tog = cmd->cmd->cmd_data;
2295     apr_int64_t limited = 0;
2296     apr_int64_t old_limited = cmd->limited;
2297     const char *errmsg;
2298
2299     if (endp == NULL) {
2300         return unclosed_directive(cmd);
2301     }
2302
2303     limited_methods = apr_pstrmemdup(cmd->temp_pool, arg, endp - arg);
2304
2305     if (!limited_methods[0]) {
2306         return missing_container_arg(cmd);
2307     }
2308
2309     while (limited_methods[0]) {
2310         char *method = ap_getword_conf(cmd->temp_pool, &limited_methods);
2311         int methnum;
2312
2313         /* check for builtin or module registered method number */
2314         methnum = ap_method_number_of(method);
2315
2316         if (methnum == M_TRACE && !tog) {
2317             return "TRACE cannot be controlled by <Limit>, see TraceEnable";
2318         }
2319         else if (methnum == M_INVALID) {
2320             /* method has not been registered yet, but resource restriction
2321              * is always checked before method handling, so register it.
2322              */
2323             methnum = ap_method_register(cmd->pool,
2324                                          apr_pstrdup(cmd->pool, method));
2325         }
2326
2327         limited |= (AP_METHOD_BIT << methnum);
2328     }
2329
2330     /* Killing two features with one function,
2331      * if (tog == NULL) <Limit>, else <LimitExcept>
2332      */
2333     limited = tog ? ~limited : limited;
2334
2335     if (!(old_limited & limited)) {
2336         return apr_pstrcat(cmd->pool, cmd->cmd->name,
2337                            "> directive excludes all methods", NULL);
2338     }
2339     else if ((old_limited & limited) == old_limited) {
2340         return apr_pstrcat(cmd->pool, cmd->cmd->name,
2341                            "> directive specifies methods already excluded",
2342                            NULL);
2343     }
2344
2345     cmd->limited &= limited;
2346
2347     errmsg = ap_walk_config(cmd->directive->first_child, cmd, cmd->context);
2348
2349     cmd->limited = old_limited;
2350
2351     return errmsg;
2352 }
2353
2354 /* XXX: Bogus - need to do this differently (at least OS2/Netware suffer
2355  * the same problem!!!
2356  * We use this in <DirectoryMatch> and <FilesMatch>, to ensure that
2357  * people don't get bitten by wrong-cased regex matches
2358  */
2359
2360 #ifdef WIN32
2361 #define USE_ICASE AP_REG_ICASE
2362 #else
2363 #define USE_ICASE 0
2364 #endif
2365
2366 static const char *dirsection(cmd_parms *cmd, void *mconfig, const char *arg)
2367 {
2368     const char *errmsg;
2369     const char *endp = ap_strrchr_c(arg, '>');
2370     int old_overrides = cmd->override;
2371     char *old_path = cmd->path;
2372     core_dir_config *conf;
2373     ap_conf_vector_t *new_dir_conf = ap_create_per_dir_config(cmd->pool);
2374     ap_regex_t *r = NULL;
2375     const command_rec *thiscmd = cmd->cmd;
2376
2377     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
2378     if (err != NULL) {
2379         return err;
2380     }
2381
2382     if (endp == NULL) {
2383         return unclosed_directive(cmd);
2384     }
2385
2386     arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
2387
2388     if (!arg[0]) {
2389         return missing_container_arg(cmd);
2390     }
2391
2392     cmd->path = ap_getword_conf(cmd->pool, &arg);
2393     cmd->override = OR_ALL|ACCESS_CONF;
2394
2395     if (!strcmp(cmd->path, "~")) {
2396         cmd->path = ap_getword_conf(cmd->pool, &arg);
2397         if (!cmd->path)
2398             return "<Directory ~ > block must specify a path";
2399         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
2400         if (!r) {
2401             return "Regex could not be compiled";
2402         }
2403     }
2404     else if (thiscmd->cmd_data) { /* <DirectoryMatch> */
2405         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
2406         if (!r) {
2407             return "Regex could not be compiled";
2408         }
2409     }
2410     else if (!strcmp(cmd->path, "/") == 0)
2411     {
2412         char *newpath;
2413
2414         /*
2415          * Ensure that the pathname is canonical, and append the trailing /
2416          */
2417         apr_status_t rv = apr_filepath_merge(&newpath, NULL, cmd->path,
2418                                              APR_FILEPATH_TRUENAME, cmd->pool);
2419         if (rv != APR_SUCCESS && rv != APR_EPATHWILD) {
2420             return apr_pstrcat(cmd->pool, "<Directory \"", cmd->path,
2421                                "\"> path is invalid.", NULL);
2422         }
2423
2424         cmd->path = newpath;
2425         if (cmd->path[strlen(cmd->path) - 1] != '/')
2426             cmd->path = apr_pstrcat(cmd->pool, cmd->path, "/", NULL);
2427     }
2428
2429     /* initialize our config and fetch it */
2430     conf = ap_set_config_vectors(cmd->server, new_dir_conf, cmd->path,
2431                                  &core_module, cmd->pool);
2432
2433     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_dir_conf);
2434     if (errmsg != NULL)
2435         return errmsg;
2436
2437     conf->r = r;
2438     conf->d = cmd->path;
2439     conf->d_is_fnmatch = (apr_fnmatch_test(conf->d) != 0);
2440
2441     if (r) {
2442         conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *));
2443         ap_regname(r, conf->refs, AP_REG_MATCH, 1);
2444     }
2445
2446     /* Make this explicit - the "/" root has 0 elements, that is, we
2447      * will always merge it, and it will always sort and merge first.
2448      * All others are sorted and tested by the number of slashes.
2449      */
2450     if (strcmp(conf->d, "/") == 0)
2451         conf->d_components = 0;
2452     else
2453         conf->d_components = ap_count_dirs(conf->d);
2454
2455     ap_add_per_dir_conf(cmd->server, new_dir_conf);
2456
2457     if (*arg != '\0') {
2458         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
2459                            "> arguments not (yet) supported.", NULL);
2460     }
2461
2462     cmd->path = old_path;
2463     cmd->override = old_overrides;
2464
2465     return NULL;
2466 }
2467
2468 static const char *urlsection(cmd_parms *cmd, void *mconfig, const char *arg)
2469 {
2470     const char *errmsg;
2471     const char *endp = ap_strrchr_c(arg, '>');
2472     int old_overrides = cmd->override;
2473     char *old_path = cmd->path;
2474     core_dir_config *conf;
2475     ap_regex_t *r = NULL;
2476     const command_rec *thiscmd = cmd->cmd;
2477     ap_conf_vector_t *new_url_conf = ap_create_per_dir_config(cmd->pool);
2478     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
2479     if (err != NULL) {
2480         return err;
2481     }
2482
2483     if (endp == NULL) {
2484         return unclosed_directive(cmd);
2485     }
2486
2487     arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
2488
2489     if (!arg[0]) {
2490         return missing_container_arg(cmd);
2491     }
2492
2493     cmd->path = ap_getword_conf(cmd->pool, &arg);
2494     cmd->override = OR_ALL|ACCESS_CONF;
2495
2496     if (thiscmd->cmd_data) { /* <LocationMatch> */
2497         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED);
2498         if (!r) {
2499             return "Regex could not be compiled";
2500         }
2501     }
2502     else if (!strcmp(cmd->path, "~")) {
2503         cmd->path = ap_getword_conf(cmd->pool, &arg);
2504         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED);
2505         if (!r) {
2506             return "Regex could not be compiled";
2507         }
2508     }
2509
2510     /* initialize our config and fetch it */
2511     conf = ap_set_config_vectors(cmd->server, new_url_conf, cmd->path,
2512                                  &core_module, cmd->pool);
2513
2514     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_url_conf);
2515     if (errmsg != NULL)
2516         return errmsg;
2517
2518     conf->d = apr_pstrdup(cmd->pool, cmd->path);     /* No mangling, please */
2519     conf->d_is_fnmatch = apr_fnmatch_test(conf->d) != 0;
2520     conf->r = r;
2521
2522     if (r) {
2523         conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *));
2524         ap_regname(r, conf->refs, AP_REG_MATCH, 1);
2525     }
2526
2527     ap_add_per_url_conf(cmd->server, new_url_conf);
2528
2529     if (*arg != '\0') {
2530         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
2531                            "> arguments not (yet) supported.", NULL);
2532     }
2533
2534     cmd->path = old_path;
2535     cmd->override = old_overrides;
2536
2537     return NULL;
2538 }
2539
2540 static const char *filesection(cmd_parms *cmd, void *mconfig, const char *arg)
2541 {
2542     const char *errmsg;
2543     const char *endp = ap_strrchr_c(arg, '>');
2544     int old_overrides = cmd->override;
2545     char *old_path = cmd->path;
2546     core_dir_config *conf;
2547     ap_regex_t *r = NULL;
2548     const command_rec *thiscmd = cmd->cmd;
2549     ap_conf_vector_t *new_file_conf = ap_create_per_dir_config(cmd->pool);
2550     const char *err = ap_check_cmd_context(cmd,
2551                                            NOT_IN_LOCATION | NOT_IN_LIMIT);
2552
2553     if (err != NULL) {
2554         return err;
2555     }
2556
2557     if (endp == NULL) {
2558         return unclosed_directive(cmd);
2559     }
2560
2561     arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
2562
2563     if (!arg[0]) {
2564         return missing_container_arg(cmd);
2565     }
2566
2567     cmd->path = ap_getword_conf(cmd->pool, &arg);
2568     /* Only if not an .htaccess file */
2569     if (!old_path) {
2570         cmd->override = OR_ALL|ACCESS_CONF;
2571     }
2572
2573     if (thiscmd->cmd_data) { /* <FilesMatch> */
2574         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
2575         if (!r) {
2576             return "Regex could not be compiled";
2577         }
2578     }
2579     else if (!strcmp(cmd->path, "~")) {
2580         cmd->path = ap_getword_conf(cmd->pool, &arg);
2581         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
2582         if (!r) {
2583             return "Regex could not be compiled";
2584         }
2585     }
2586     else {
2587         char *newpath;
2588         /* Ensure that the pathname is canonical, but we
2589          * can't test the case/aliases without a fixed path */
2590         if (apr_filepath_merge(&newpath, "", cmd->path,
2591                                0, cmd->pool) != APR_SUCCESS)
2592                 return apr_pstrcat(cmd->pool, "<Files \"", cmd->path,
2593                                "\"> is invalid.", NULL);
2594         cmd->path = newpath;
2595     }
2596
2597     /* initialize our config and fetch it */
2598     conf = ap_set_config_vectors(cmd->server, new_file_conf, cmd->path,
2599                                  &core_module, cmd->pool);
2600
2601     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_file_conf);
2602     if (errmsg != NULL)
2603         return errmsg;
2604
2605     conf->d = cmd->path;
2606     conf->d_is_fnmatch = apr_fnmatch_test(conf->d) != 0;
2607     conf->r = r;
2608
2609     if (r) {
2610         conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *));
2611         ap_regname(r, conf->refs, AP_REG_MATCH, 1);
2612     }
2613
2614     ap_add_file_conf(cmd->pool, (core_dir_config *)mconfig, new_file_conf);
2615
2616     if (*arg != '\0') {
2617         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
2618                            "> arguments not (yet) supported.", NULL);
2619     }
2620
2621     cmd->path = old_path;
2622     cmd->override = old_overrides;
2623
2624     return NULL;
2625 }
2626
2627 #define COND_IF      ((void *)1)
2628 #define COND_ELSE    ((void *)2)
2629 #define COND_ELSEIF  ((void *)3)
2630
2631 static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg)
2632 {
2633     const char *errmsg;
2634     const char *endp = ap_strrchr_c(arg, '>');
2635     int old_overrides = cmd->override;
2636     char *old_path = cmd->path;
2637     core_dir_config *conf;
2638     const command_rec *thiscmd = cmd->cmd;
2639     ap_conf_vector_t *new_if_conf = ap_create_per_dir_config(cmd->pool);
2640     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2641     const char *condition;
2642     const char *expr_err;
2643
2644     if (err != NULL) {
2645         return err;
2646     }
2647
2648     if (endp == NULL) {
2649         return unclosed_directive(cmd);
2650     }
2651
2652     arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
2653
2654     /*
2655      * Set a dummy value so that other directives notice that they are inside
2656      * a config section.
2657      */
2658     cmd->path = "*If";
2659     /* Only if not an .htaccess file */
2660     if (!old_path) {
2661         cmd->override = OR_ALL|ACCESS_CONF;
2662     }
2663
2664     /* initialize our config and fetch it */
2665     conf = ap_set_config_vectors(cmd->server, new_if_conf, cmd->path,
2666                                  &core_module, cmd->pool);
2667
2668     if (cmd->cmd->cmd_data == COND_IF)
2669         conf->condition_ifelse = AP_CONDITION_IF;
2670     else if (cmd->cmd->cmd_data == COND_ELSEIF)
2671         conf->condition_ifelse = AP_CONDITION_ELSEIF;
2672     else if (cmd->cmd->cmd_data == COND_ELSE)
2673         conf->condition_ifelse = AP_CONDITION_ELSE;
2674     else
2675         ap_assert(0);
2676
2677     if (conf->condition_ifelse == AP_CONDITION_ELSE) {
2678         if (arg[0])
2679             return "<Else> does not take an argument";
2680     }
2681     else {
2682         if (!arg[0])
2683             return missing_container_arg(cmd);
2684         condition = ap_getword_conf(cmd->pool, &arg);
2685         conf->condition = ap_expr_parse_cmd(cmd, condition, 0, &expr_err, NULL);
2686         if (expr_err)
2687             return apr_psprintf(cmd->pool, "Cannot parse condition clause: %s",
2688                                 expr_err);
2689     }
2690
2691     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_if_conf);
2692     if (errmsg != NULL)
2693         return errmsg;
2694
2695     conf->d = cmd->path;
2696     conf->d_is_fnmatch = 0;
2697     conf->r = NULL;
2698
2699     errmsg = ap_add_if_conf(cmd->pool, (core_dir_config *)mconfig, new_if_conf);
2700     if (errmsg != NULL)
2701         return errmsg;
2702
2703     if (*arg != '\0') {
2704         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
2705                            "> arguments not supported.", NULL);
2706     }
2707
2708     cmd->path = old_path;
2709     cmd->override = old_overrides;
2710
2711     return NULL;
2712 }
2713
2714 static module *find_module(server_rec *s, const char *name)
2715 {
2716     module *found = ap_find_linked_module(name);
2717
2718     /* search prelinked stuff */
2719     if (!found) {
2720         ap_module_symbol_t *current = ap_prelinked_module_symbols;
2721
2722         for (; current->name; ++current) {
2723             if (!strcmp(current->name, name)) {
2724                 found = current->modp;
2725                 break;
2726             }
2727         }
2728     }
2729
2730     /* search dynamic stuff */
2731     if (!found) {
2732         APR_OPTIONAL_FN_TYPE(ap_find_loaded_module_symbol) *check_symbol =
2733             APR_RETRIEVE_OPTIONAL_FN(ap_find_loaded_module_symbol);
2734
2735         if (check_symbol) {
2736             /*
2737              * There are two phases where calling ap_find_loaded_module_symbol
2738              * is problematic:
2739              *
2740              * During reading of the config, ap_server_conf is invalid but s
2741              * points to the main server config, if passed from cmd->server
2742              * of an EXEC_ON_READ directive.
2743              *
2744              * During config parsing, s may be a virtual host that would cause
2745              * a segfault in mod_so if passed to ap_find_loaded_module_symbol,
2746              * because mod_so's server config for vhosts is initialized later.
2747              * But ap_server_conf is already set at this time.
2748              *
2749              * Therefore we use s if it is not virtual and ap_server_conf if
2750              * s is virtual.
2751              */
2752             found = check_symbol(s->is_virtual ? ap_server_conf : s, name);
2753         }
2754     }
2755
2756     return found;
2757 }
2758
2759
2760 static const char *start_ifmod(cmd_parms *cmd, void *mconfig, const char *arg)
2761 {
2762     const char *endp = ap_strrchr_c(arg, '>');
2763     int not = (arg[0] == '!');
2764     module *found;
2765
2766     if (endp == NULL) {
2767         return unclosed_directive(cmd);
2768     }
2769
2770     arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
2771
2772     if (not) {
2773         arg++;
2774     }
2775
2776     if (!arg[0]) {
2777         return missing_container_arg(cmd);
2778     }
2779
2780     found = find_module(cmd->server, arg);
2781
2782     if ((!not && found) || (not && !found)) {
2783         ap_directive_t *parent = NULL;
2784         ap_directive_t *current = NULL;
2785         const char *retval;
2786
2787         retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd,
2788                                       &current, &parent, "<IfModule");
2789         *(ap_directive_t **)mconfig = current;
2790         return retval;
2791     }
2792     else {
2793         *(ap_directive_t **)mconfig = NULL;
2794         return ap_soak_end_container(cmd, "<IfModule");
2795     }
2796 }
2797
2798 AP_DECLARE(int) ap_exists_config_define(const char *name)
2799 {
2800     return ap_array_str_contains(ap_server_config_defines, name);
2801 }
2802
2803 static const char *start_ifdefine(cmd_parms *cmd, void *dummy, const char *arg)
2804 {
2805     const char *endp;
2806     int defined;
2807     int not = 0;
2808
2809     endp = ap_strrchr_c(arg, '>');
2810     if (endp == NULL) {
2811         return unclosed_directive(cmd);
2812     }
2813
2814     arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
2815
2816     if (arg[0] == '!') {
2817         not = 1;
2818         arg++;
2819     }
2820
2821     if (!arg[0]) {
2822         return missing_container_arg(cmd);
2823     }
2824
2825     defined = ap_exists_config_define(arg);
2826     if ((!not && defined) || (not && !defined)) {
2827         ap_directive_t *parent = NULL;
2828         ap_directive_t *current = NULL;
2829         const char *retval;
2830
2831         retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd,
2832                                       &current, &parent, "<IfDefine");
2833         *(ap_directive_t **)dummy = current;
2834         return retval;
2835     }
2836     else {
2837         *(ap_directive_t **)dummy = NULL;
2838         return ap_soak_end_container(cmd, "<IfDefine");
2839     }
2840 }
2841
2842 /* httpd.conf commands... beginning with the <VirtualHost> business */
2843
2844 static const char *virtualhost_section(cmd_parms *cmd, void *dummy,
2845                                        const char *arg)
2846 {
2847     server_rec *main_server = cmd->server, *s;
2848     const char *errmsg;
2849     const char *endp = ap_strrchr_c(arg, '>');
2850     apr_pool_t *p = cmd->pool;
2851
2852     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2853     if (err != NULL) {
2854         return err;
2855     }
2856
2857     if (endp == NULL) {
2858         return unclosed_directive(cmd);
2859     }
2860
2861     arg = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
2862
2863     if (!arg[0]) {
2864         return missing_container_arg(cmd);
2865     }
2866
2867     /* FIXME: There's another feature waiting to happen here -- since you
2868         can now put multiple addresses/names on a single <VirtualHost>
2869         you might want to use it to group common definitions and then
2870         define other "subhosts" with their individual differences.  But
2871         personally I'd rather just do it with a macro preprocessor. -djg */
2872     if (main_server->is_virtual) {
2873         return "<VirtualHost> doesn't nest!";
2874     }
2875
2876     errmsg = ap_init_virtual_host(p, arg, main_server, &s);
2877     if (errmsg) {
2878         return errmsg;
2879     }
2880
2881     s->next = main_server->next;
2882     main_server->next = s;
2883
2884     s->defn_name = cmd->directive->filename;
2885     s->defn_line_number = cmd->directive->line_num;
2886
2887     cmd->server = s;
2888
2889     errmsg = ap_walk_config(cmd->directive->first_child, cmd,
2890                             s->lookup_defaults);
2891
2892     cmd->server = main_server;
2893
2894     return errmsg;
2895 }
2896
2897 static const char *set_server_alias(cmd_parms *cmd, void *dummy,
2898                                     const char *arg)
2899 {
2900     if (!cmd->server->names) {
2901         return "ServerAlias only used in <VirtualHost>";
2902     }
2903
2904     while (*arg) {
2905         char **item, *name = ap_getword_conf(cmd->pool, &arg);
2906
2907         if (ap_is_matchexp(name)) {
2908             item = (char **)apr_array_push(cmd->server->wild_names);
2909         }
2910         else {
2911             item = (char **)apr_array_push(cmd->server->names);
2912         }
2913
2914         *item = name;
2915     }
2916
2917     return NULL;
2918 }
2919
2920 static const char *set_accf_map(cmd_parms *cmd, void *dummy,
2921                                 const char *iproto, const char* iaccf)
2922 {
2923     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2924     core_server_config *conf =
2925         ap_get_core_module_config(cmd->server->module_config);
2926     char* proto;
2927     char* accf;
2928     if (err != NULL) {
2929         return err;
2930     }
2931
2932     proto = apr_pstrdup(cmd->pool, iproto);
2933     ap_str_tolower(proto);
2934     accf = apr_pstrdup(cmd->pool, iaccf);
2935     ap_str_tolower(accf);
2936     apr_table_setn(conf->accf_map, proto, accf);
2937
2938     return NULL;
2939 }
2940
2941 AP_DECLARE(const char*) ap_get_server_protocol(server_rec* s)
2942 {
2943     core_server_config *conf = ap_get_core_module_config(s->module_config);
2944     return conf->protocol;
2945 }
2946
2947 AP_DECLARE(void) ap_set_server_protocol(server_rec* s, const char* proto)
2948 {
2949     core_server_config *conf = ap_get_core_module_config(s->module_config);
2950     conf->protocol = proto;
2951 }
2952
2953 static const char *set_protocol(cmd_parms *cmd, void *dummy,
2954                                 const char *arg)
2955 {
2956     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
2957     core_server_config *conf =
2958         ap_get_core_module_config(cmd->server->module_config);
2959     char* proto;
2960
2961     if (err != NULL) {
2962         return err;
2963     }
2964
2965     proto = apr_pstrdup(cmd->pool, arg);
2966     ap_str_tolower(proto);
2967     conf->protocol = proto;
2968
2969     return NULL;
2970 }
2971
2972 static const char *set_server_string_slot(cmd_parms *cmd, void *dummy,
2973                                           const char *arg)
2974 {
2975     /* This one's pretty generic... */
2976
2977     int offset = (int)(long)cmd->info;
2978     char *struct_ptr = (char *)cmd->server;
2979
2980     const char *err = ap_check_cmd_context(cmd,
2981                                            NOT_IN_DIR_LOC_FILE);
2982     if (err != NULL) {
2983         return err;
2984     }
2985
2986     *(const char **)(struct_ptr + offset) = arg;
2987     return NULL;
2988 }
2989
2990 /*
2991  * The ServerName directive takes one argument with format
2992  * [scheme://]fully-qualified-domain-name[:port], for instance
2993  * ServerName www.example.com
2994  * ServerName www.example.com:80
2995  * ServerName https://www.example.com:443
2996  */
2997
2998 static const char *server_hostname_port(cmd_parms *cmd, void *dummy, const char *arg)
2999 {
3000     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
3001     const char *portstr, *part;
3002     char *scheme;
3003     int port;
3004
3005     if (err != NULL) {
3006         return err;
3007     }
3008
3009     if (apr_fnmatch_test(arg))
3010         return apr_pstrcat(cmd->temp_pool, "Invalid ServerName \"", arg,
3011                 "\" use ServerAlias to set multiple server names.", NULL);
3012
3013     part = ap_strstr_c(arg, "://");
3014
3015     if (part) {
3016       scheme = apr_pstrndup(cmd->pool, arg, part - arg);
3017       ap_str_tolower(scheme);
3018       cmd->server->server_scheme = (const char *)scheme;
3019       part += 3;
3020     } else {
3021       part = arg;
3022     }
3023
3024     portstr = ap_strchr_c(part, ':');
3025     if (portstr) {
3026         cmd->server->server_hostname = apr_pstrndup(cmd->pool, part,
3027                                                     portstr - part);
3028         portstr++;
3029         port = atoi(portstr);
3030         if (port <= 0 || port >= 65536) { /* 65536 == 1<<16 */
3031             return apr_pstrcat(cmd->temp_pool, "The port number \"", arg,
3032                           "\" is outside the appropriate range "
3033                           "(i.e., 1..65535).", NULL);
3034         }
3035     }
3036     else {
3037         cmd->server->server_hostname = apr_pstrdup(cmd->pool, part);
3038         port = 0;
3039     }
3040
3041     cmd->server->port = port;
3042     return NULL;
3043 }
3044
3045 static const char *set_signature_flag(cmd_parms *cmd, void *d_,
3046                                       const char *arg)
3047 {
3048     core_dir_config *d = d_;
3049
3050     if (ap_casecmpstr(arg, "On") == 0) {
3051         d->server_signature = srv_sig_on;
3052     }
3053     else if (ap_casecmpstr(arg, "Off") == 0) {
3054         d->server_signature = srv_sig_off;
3055     }
3056     else if (ap_casecmpstr(arg, "EMail") == 0) {
3057         d->server_signature = srv_sig_withmail;
3058     }
3059     else {
3060         return "ServerSignature: use one of: off | on | email";
3061     }
3062
3063     return NULL;
3064 }
3065
3066 static const char *set_server_root(cmd_parms *cmd, void *dummy,
3067                                    const char *arg)
3068 {
3069     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3070
3071     if (err != NULL) {
3072         return err;
3073     }
3074
3075     if ((apr_filepath_merge((char**)&ap_server_root, NULL, arg,
3076                             APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS)
3077         || !ap_is_directory(cmd->temp_pool, ap_server_root)) {
3078         return "ServerRoot must be a valid directory";
3079     }
3080
3081     return NULL;
3082 }
3083
3084 static const char *set_runtime_dir(cmd_parms *cmd, void *dummy, const char *arg)
3085 {
3086     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3087
3088     if (err != NULL) {
3089         return err;
3090     }
3091
3092     if ((apr_filepath_merge((char**)&ap_runtime_dir, NULL,
3093                             ap_server_root_relative(cmd->temp_pool, arg),
3094                             APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS)
3095         || !ap_is_directory(cmd->temp_pool, ap_runtime_dir)) {
3096         return "DefaultRuntimeDir must be a valid directory, absolute or relative to ServerRoot";
3097     }
3098
3099     return NULL;
3100 }
3101
3102 static const char *set_timeout(cmd_parms *cmd, void *dummy, const char *arg)
3103 {
3104     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
3105
3106     if (err != NULL) {
3107         return err;
3108     }
3109
3110     cmd->server->timeout = apr_time_from_sec(atoi(arg));
3111     return NULL;
3112 }
3113
3114 static const char *set_allow2f(cmd_parms *cmd, void *d_, const char *arg)
3115 {
3116     core_dir_config *d = d_;
3117
3118     if (0 == ap_casecmpstr(arg, "on")) {
3119         d->allow_encoded_slashes = 1;
3120         d->decode_encoded_slashes = 1; /* for compatibility with 2.0 & 2.2 */
3121     } else if (0 == ap_casecmpstr(arg, "off")) {
3122         d->allow_encoded_slashes = 0;
3123         d->decode_encoded_slashes = 0;
3124     } else if (0 == ap_casecmpstr(arg, "nodecode")) {
3125         d->allow_encoded_slashes = 1;
3126         d->decode_encoded_slashes = 0;
3127     } else {
3128         return apr_pstrcat(cmd->pool,
3129                            cmd->cmd->name, " must be On, Off, or NoDecode",
3130                            NULL);
3131     }
3132
3133     d->allow_encoded_slashes_set = 1;
3134     d->decode_encoded_slashes_set = 1;
3135
3136     return NULL;
3137 }
3138
3139 static const char *set_hostname_lookups(cmd_parms *cmd, void *d_,
3140                                         const char *arg)
3141 {
3142     core_dir_config *d = d_;
3143
3144     if (!ap_casecmpstr(arg, "on")) {
3145         d->hostname_lookups = HOSTNAME_LOOKUP_ON;
3146     }
3147     else if (!ap_casecmpstr(arg, "off")) {
3148         d->hostname_lookups = HOSTNAME_LOOKUP_OFF;
3149     }
3150     else if (!ap_casecmpstr(arg, "double")) {
3151         d->hostname_lookups = HOSTNAME_LOOKUP_DOUBLE;
3152     }
3153     else {
3154         return "parameter must be 'on', 'off', or 'double'";
3155     }
3156
3157     return NULL;
3158 }
3159
3160 static const char *set_serverpath(cmd_parms *cmd, void *dummy,
3161                                   const char *arg)
3162 {
3163     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
3164
3165     if (err != NULL) {
3166         return err;
3167     }
3168
3169     cmd->server->path = arg;
3170     cmd->server->pathlen = (int)strlen(arg);
3171     return NULL;
3172 }
3173
3174 static const char *set_content_md5(cmd_parms *cmd, void *d_, int arg)
3175 {
3176     core_dir_config *d = d_;
3177
3178     d->content_md5 = arg ? AP_CONTENT_MD5_ON : AP_CONTENT_MD5_OFF;
3179     return NULL;
3180 }
3181
3182 static const char *set_accept_path_info(cmd_parms *cmd, void *d_, const char *arg)
3183 {
3184     core_dir_config *d = d_;
3185
3186     if (ap_casecmpstr(arg, "on") == 0) {
3187         d->accept_path_info = AP_REQ_ACCEPT_PATH_INFO;
3188     }
3189     else if (ap_casecmpstr(arg, "off") == 0) {
3190         d->accept_path_info = AP_REQ_REJECT_PATH_INFO;
3191     }
3192     else if (ap_casecmpstr(arg, "default") == 0) {
3193         d->accept_path_info = AP_REQ_DEFAULT_PATH_INFO;
3194     }
3195     else {
3196         return "AcceptPathInfo must be set to on, off or default";
3197     }
3198
3199     return NULL;
3200 }
3201
3202 static const char *set_use_canonical_name(cmd_parms *cmd, void *d_,
3203                                           const char *arg)
3204 {
3205     core_dir_config *d = d_;
3206
3207     if (ap_casecmpstr(arg, "on") == 0) {
3208         d->use_canonical_name = USE_CANONICAL_NAME_ON;
3209     }
3210     else if (ap_casecmpstr(arg, "off") == 0) {
3211         d->use_canonical_name = USE_CANONICAL_NAME_OFF;
3212     }
3213     else if (ap_casecmpstr(arg, "dns") == 0) {
3214         d->use_canonical_name = USE_CANONICAL_NAME_DNS;
3215     }
3216     else {
3217         return "parameter must be 'on', 'off', or 'dns'";
3218     }
3219
3220     return NULL;
3221 }
3222
3223 static const char *set_use_canonical_phys_port(cmd_parms *cmd, void *d_,
3224                                           const char *arg)
3225 {
3226     core_dir_config *d = d_;
3227
3228     if (ap_casecmpstr(arg, "on") == 0) {
3229         d->use_canonical_phys_port = USE_CANONICAL_PHYS_PORT_ON;
3230     }
3231     else if (ap_casecmpstr(arg, "off") == 0) {
3232         d->use_canonical_phys_port = USE_CANONICAL_PHYS_PORT_OFF;
3233     }
3234     else {
3235         return "parameter must be 'on' or 'off'";
3236     }
3237
3238     return NULL;
3239 }
3240
3241 static const char *include_config (cmd_parms *cmd, void *dummy,
3242                                    const char *name)
3243 {
3244     ap_directive_t *conftree = NULL;
3245     const char *conffile, *error;
3246     unsigned *recursion;
3247     int optional = cmd->cmd->cmd_data ? 1 : 0;
3248     void *data;
3249
3250     apr_pool_userdata_get(&data, "ap_include_sentinel", cmd->pool);
3251     if (data) {
3252         recursion = data;
3253     }
3254     else {
3255         data = recursion = apr_palloc(cmd->pool, sizeof(*recursion));
3256         *recursion = 0;
3257         apr_pool_userdata_setn(data, "ap_include_sentinel", NULL, cmd->pool);
3258     }
3259
3260     if (++*recursion > AP_MAX_INCLUDE_DEPTH) {
3261         *recursion = 0;
3262         return apr_psprintf(cmd->pool, "Exceeded maximum include depth of %u, "
3263                             "There appears to be a recursion.",
3264                             AP_MAX_INCLUDE_DEPTH);
3265     }
3266
3267     conffile = ap_server_root_relative(cmd->pool, name);
3268     if (!conffile) {
3269         *recursion = 0;
3270         return apr_pstrcat(cmd->pool, "Invalid Include path ",
3271                            name, NULL);
3272     }
3273
3274     error = ap_process_fnmatch_configs(cmd->server, conffile, &conftree,
3275                                        cmd->pool, cmd->temp_pool,
3276                                        optional);
3277     if (error) {
3278         *recursion = 0;
3279         return error;
3280     }
3281
3282     *(ap_directive_t **)dummy = conftree;
3283
3284     /* recursion level done */
3285     if (*recursion) {
3286         --*recursion;
3287     }
3288
3289     return NULL;
3290 }
3291
3292 static const char *update_loglevel(cmd_parms *cmd, struct ap_logconf *log,
3293                                    const char *arg)
3294 {
3295     const char *level_str, *err;
3296     module *module;
3297     int level;
3298
3299     level_str = ap_strrchr_c(arg, ':');
3300
3301     if (level_str == NULL) {
3302         err = ap_parse_log_level(arg, &log->level);
3303         if (err != NULL)
3304             return err;
3305         ap_reset_module_loglevels(log, APLOG_NO_MODULE);
3306         ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, cmd->server,
3307                      "Setting %s for all modules to %s", cmd->cmd->name, arg);
3308         return NULL;
3309     }
3310
3311     arg = apr_pstrmemdup(cmd->temp_pool, arg, level_str - arg);
3312     level_str++;
3313     if (!*level_str) {
3314         return apr_psprintf(cmd->temp_pool, "Module specifier '%s' must be "
3315                             "followed by a log level keyword", arg);
3316     }
3317
3318     err = ap_parse_log_level(level_str, &level);
3319     if (err != NULL)
3320         return apr_psprintf(cmd->temp_pool, "%s:%s: %s", arg, level_str, err);
3321
3322     if ((module = find_module(cmd->server, arg)) == NULL) {
3323         char *name = apr_psprintf(cmd->temp_pool, "%s_module", arg);
3324         ap_log_error(APLOG_MARK, APLOG_TRACE6, 0, cmd->server,
3325                      "Cannot find module '%s', trying '%s'", arg, name);
3326         module = find_module(cmd->server, name);
3327     }
3328
3329     if (module == NULL) {
3330         return apr_psprintf(cmd->temp_pool, "Cannot find module %s", arg);
3331     }
3332
3333     ap_set_module_loglevel(cmd->pool, log, module->module_index, level);
3334     ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, cmd->server,
3335                  "Setting %s for module %s to %s", cmd->cmd->name,
3336                  module->name, level_str);
3337
3338     return NULL;
3339 }
3340
3341 static const char *set_loglevel(cmd_parms *cmd, void *config_, const char *arg)
3342 {
3343     struct ap_logconf *log;
3344
3345     if (cmd->path) {
3346         core_dir_config *dconf = config_;
3347         if (!dconf->log) {
3348             dconf->log = ap_new_log_config(cmd->pool, NULL);
3349         }
3350         log = dconf->log;
3351     }
3352     else {
3353         log = &cmd->server->log;
3354     }
3355
3356     if (arg == NULL)
3357         return "LogLevel requires level keyword or module loglevel specifier";
3358
3359     return update_loglevel(cmd, log, arg);
3360 }
3361
3362 static const char *set_loglevel_override(cmd_parms *cmd, void *d_, int argc,
3363                                          char *const argv[])
3364 {
3365     core_server_config *sconf;
3366     conn_log_config *entry;
3367     int ret, i;
3368     const char *addr, *mask, *err;
3369
3370     if (argc < 2)
3371         return "LogLevelOverride requires at least two arguments";
3372
3373     entry = apr_pcalloc(cmd->pool, sizeof(conn_log_config));
3374     sconf = ap_get_core_module_config(cmd->server->module_config);
3375     if (!sconf->conn_log_level)
3376         sconf->conn_log_level = apr_array_make(cmd->pool, 4, sizeof(entry));
3377     APR_ARRAY_PUSH(sconf->conn_log_level, conn_log_config *) = entry;
3378
3379     addr = argv[0];
3380     mask = ap_strchr_c(addr, '/');
3381     if (mask) {
3382         addr = apr_pstrmemdup(cmd->temp_pool, addr, mask - addr);
3383         mask++;
3384     }
3385     ret = apr_ipsubnet_create(&entry->subnet, addr, mask, cmd->pool);
3386     if (ret != APR_SUCCESS)
3387         return "parsing of subnet/netmask failed";
3388
3389     for (i = 1; i < argc; i++) {
3390         if ((err = update_loglevel(cmd, &entry->log, argv[i])) != NULL)
3391             return err;
3392     }
3393     return NULL;
3394 }
3395
3396 AP_DECLARE(const char *) ap_psignature(const char *prefix, request_rec *r)
3397 {
3398     char sport[20];
3399     core_dir_config *conf;
3400
3401     conf = (core_dir_config *)ap_get_core_module_config(r->per_dir_config);
3402     if ((conf->server_signature == srv_sig_off)
3403             || (conf->server_signature == srv_sig_unset)) {
3404         return "";
3405     }
3406
3407     apr_snprintf(sport, sizeof sport, "%u", (unsigned) ap_get_server_port(r));
3408
3409     if (conf->server_signature == srv_sig_withmail) {
3410         return apr_pstrcat(r->pool, prefix, "<address>",
3411                            ap_get_server_banner(),
3412                            " Server at <a href=\"",
3413                            ap_is_url(r->server->server_admin) ? "" : "mailto:",
3414                            ap_escape_html(r->pool, r->server->server_admin),
3415                            "\">",
3416                            ap_escape_html(r->pool, ap_get_server_name(r)),
3417                            "</a> Port ", sport,
3418                            "</address>\n", NULL);
3419     }
3420
3421     return apr_pstrcat(r->pool, prefix, "<address>", ap_get_server_banner(),
3422                        " Server at ",
3423                        ap_escape_html(r->pool, ap_get_server_name(r)),
3424                        " Port ", sport,
3425                        "</address>\n", NULL);
3426 }
3427
3428 /*
3429  * Handle a request to include the server's OS platform in the Server
3430  * response header field (the ServerTokens directive).  Unfortunately
3431  * this requires a new global in order to communicate the setting back to
3432  * http_main so it can insert the information in the right place in the
3433  * string.
3434  */
3435
3436 static char *server_banner = NULL;
3437 static int banner_locked = 0;
3438 static const char *server_description = NULL;
3439
3440 enum server_token_type {
3441     SrvTk_MAJOR,         /* eg: Apache/2 */
3442     SrvTk_MINOR,         /* eg. Apache/2.0 */
3443     SrvTk_MINIMAL,       /* eg: Apache/2.0.41 */
3444     SrvTk_OS,            /* eg: Apache/2.0.41 (UNIX) */
3445     SrvTk_FULL,          /* eg: Apache/2.0.41 (UNIX) PHP/4.2.2 FooBar/1.2b */
3446     SrvTk_PRODUCT_ONLY   /* eg: Apache */
3447 };
3448 static enum server_token_type ap_server_tokens = SrvTk_FULL;
3449
3450 static apr_status_t reset_banner(void *dummy)
3451 {
3452     banner_locked = 0;
3453     ap_server_tokens = SrvTk_FULL;
3454     server_banner = NULL;
3455     server_description = NULL;
3456     return APR_SUCCESS;
3457 }
3458
3459 AP_DECLARE(void) ap_get_server_revision(ap_version_t *version)
3460 {
3461     version->major = AP_SERVER_MAJORVERSION_NUMBER;
3462     version->minor = AP_SERVER_MINORVERSION_NUMBER;
3463     version->patch = AP_SERVER_PATCHLEVEL_NUMBER;
3464     version->add_string = AP_SERVER_ADD_STRING;
3465 }
3466
3467 AP_DECLARE(const char *) ap_get_server_description(void)
3468 {
3469     return server_description ? server_description :
3470         AP_SERVER_BASEVERSION " (" PLATFORM ")";
3471 }
3472
3473 AP_DECLARE(const char *) ap_get_server_banner(void)
3474 {
3475     return server_banner ? server_banner : AP_SERVER_BASEVERSION;
3476 }
3477
3478 AP_DECLARE(void) ap_add_version_component(apr_pool_t *pconf, const char *component)
3479 {
3480     if (! banner_locked) {
3481         /*
3482          * If the version string is null, register our cleanup to reset the
3483          * pointer on pool destruction. We also know that, if NULL,
3484          * we are adding the original SERVER_BASEVERSION string.
3485          */
3486         if (server_banner == NULL) {
3487             apr_pool_cleanup_register(pconf, NULL, reset_banner,
3488                                       apr_pool_cleanup_null);
3489             server_banner = apr_pstrdup(pconf, component);
3490         }
3491         else {
3492             /*
3493              * Tack the given component identifier to the end of
3494              * the existing string.
3495              */
3496             server_banner = apr_pstrcat(pconf, server_banner, " ",
3497                                         component, NULL);
3498         }
3499     }
3500     server_description = apr_pstrcat(pconf, server_description, " ",
3501                                      component, NULL);
3502 }
3503
3504 /*
3505  * This routine adds the real server base identity to the banner string,
3506  * and then locks out changes until the next reconfig.
3507  */
3508 static void set_banner(apr_pool_t *pconf)
3509 {
3510     if (ap_server_tokens == SrvTk_PRODUCT_ONLY) {
3511         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT);
3512     }
3513     else if (ap_server_tokens == SrvTk_MINIMAL) {
3514         ap_add_version_component(pconf, AP_SERVER_BASEVERSION);
3515     }
3516     else if (ap_server_tokens == SrvTk_MINOR) {
3517         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MINORREVISION);
3518     }
3519     else if (ap_server_tokens == SrvTk_MAJOR) {
3520         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MAJORVERSION);
3521     }
3522     else {
3523         ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ")");
3524     }
3525
3526     /*
3527      * Lock the server_banner string if we're not displaying
3528      * the full set of tokens
3529      */
3530     if (ap_server_tokens != SrvTk_FULL) {
3531         banner_locked++;
3532     }
3533     server_description = AP_SERVER_BASEVERSION " (" PLATFORM ")";
3534 }
3535
3536 static const char *set_serv_tokens(cmd_parms *cmd, void *dummy,
3537                                    const char *arg)
3538 {
3539     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3540
3541     if (err != NULL) {
3542         return err;
3543     }
3544
3545     if (!ap_casecmpstr(arg, "OS")) {
3546         ap_server_tokens = SrvTk_OS;
3547     }
3548     else if (!ap_casecmpstr(arg, "Min") || !ap_casecmpstr(arg, "Minimal")) {
3549         ap_server_tokens = SrvTk_MINIMAL;
3550     }
3551     else if (!ap_casecmpstr(arg, "Major")) {
3552         ap_server_tokens = SrvTk_MAJOR;
3553     }
3554     else if (!ap_casecmpstr(arg, "Minor") ) {
3555         ap_server_tokens = SrvTk_MINOR;
3556     }
3557     else if (!ap_casecmpstr(arg, "Prod") || !ap_casecmpstr(arg, "ProductOnly")) {
3558         ap_server_tokens = SrvTk_PRODUCT_ONLY;
3559     }
3560     else if (!ap_casecmpstr(arg, "Full")) {
3561         ap_server_tokens = SrvTk_FULL;
3562     }
3563     else {
3564         return "ServerTokens takes 1 argument: 'Prod(uctOnly)', 'Major', 'Minor', 'Min(imal)', 'OS', or 'Full'";
3565     }
3566
3567     return NULL;
3568 }
3569
3570 static const char *set_limit_req_line(cmd_parms *cmd, void *dummy,
3571                                       const char *arg)
3572 {
3573     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
3574     int lim;
3575
3576     if (err != NULL) {
3577         return err;
3578     }
3579
3580     lim = atoi(arg);
3581     if (lim < 0) {
3582         return apr_pstrcat(cmd->temp_pool, "LimitRequestLine \"", arg,
3583                            "\" must be a non-negative integer", NULL);
3584     }
3585
3586     cmd->server->limit_req_line = lim;
3587     return NULL;
3588 }
3589
3590 static const char *set_limit_req_fieldsize(cmd_parms *cmd, void *dummy,
3591                                            const char *arg)
3592 {
3593     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
3594     int lim;
3595
3596     if (err != NULL) {
3597         return err;
3598     }
3599
3600     lim = atoi(arg);
3601     if (lim < 0) {
3602         return apr_pstrcat(cmd->temp_pool, "LimitRequestFieldsize \"", arg,
3603                           "\" must be a non-negative integer",
3604                           NULL);
3605     }
3606
3607     cmd->server->limit_req_fieldsize = lim;
3608     return NULL;
3609 }
3610
3611 static const char *set_limit_req_fields(cmd_parms *cmd, void *dummy,
3612                                         const char *arg)
3613 {
3614     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
3615     int lim;
3616
3617     if (err != NULL) {
3618         return err;
3619     }
3620
3621     lim = atoi(arg);
3622     if (lim < 0) {
3623         return apr_pstrcat(cmd->temp_pool, "LimitRequestFields \"", arg,
3624                            "\" must be a non-negative integer (0 = no limit)",
3625                            NULL);
3626     }
3627
3628     cmd->server->limit_req_fields = lim;
3629     return NULL;
3630 }
3631
3632 static const char *set_limit_req_body(cmd_parms *cmd, void *conf_,
3633                                       const char *arg)
3634 {
3635     core_dir_config *conf = conf_;
3636     char *errp;
3637
3638     if (APR_SUCCESS != apr_strtoff(&conf->limit_req_body, arg, &errp, 10)) {
3639         return "LimitRequestBody argument is not parsable.";
3640     }
3641     if (*errp || conf->limit_req_body < 0) {
3642         return "LimitRequestBody requires a non-negative integer.";
3643     }
3644
3645     return NULL;
3646 }
3647
3648 static const char *set_limit_xml_req_body(cmd_parms *cmd, void *conf_,
3649                                           const char *arg)
3650 {
3651     core_dir_config *conf = conf_;
3652
3653     conf->limit_xml_body = atol(arg);
3654     if (conf->limit_xml_body < 0)
3655         return "LimitXMLRequestBody requires a non-negative integer.";
3656
3657     return NULL;
3658 }
3659
3660 static const char *set_max_ranges(cmd_parms *cmd, void *conf_, const char *arg)
3661 {
3662     core_dir_config *conf = conf_;
3663     int val = 0;
3664
3665     if (!ap_casecmpstr(arg, "none")) {
3666         val = AP_MAXRANGES_NORANGES;
3667     }
3668     else if (!ap_casecmpstr(arg, "default")) {
3669         val = AP_MAXRANGES_DEFAULT;
3670     }
3671     else if (!ap_casecmpstr(arg, "unlimited")) {
3672         val = AP_MAXRANGES_UNLIMITED;
3673     }
3674     else {
3675         val = atoi(arg);
3676         if (val <= 0)
3677             return "MaxRanges requires 'none', 'default', 'unlimited' or "
3678                    "a positive integer";
3679     }
3680
3681     conf->max_ranges = val;
3682
3683     return NULL;
3684 }
3685
3686 static const char *set_max_overlaps(cmd_parms *cmd, void *conf_, const char *arg)
3687 {
3688     core_dir_config *conf = conf_;
3689     int val = 0;
3690
3691     if (!ap_casecmpstr(arg, "none")) {
3692         val = AP_MAXRANGES_NORANGES;
3693     }
3694     else if (!ap_casecmpstr(arg, "default")) {
3695         val = AP_MAXRANGES_DEFAULT;
3696     }
3697     else if (!ap_casecmpstr(arg, "unlimited")) {
3698         val = AP_MAXRANGES_UNLIMITED;
3699     }
3700     else {
3701         val = atoi(arg);
3702         if (val <= 0)
3703             return "MaxRangeOverlaps requires 'none', 'default', 'unlimited' or "
3704             "a positive integer";
3705     }
3706
3707     conf->max_overlaps = val;
3708
3709     return NULL;
3710 }
3711
3712 static const char *set_max_reversals(cmd_parms *cmd, void *conf_, const char *arg)
3713 {
3714     core_dir_config *conf = conf_;
3715     int val = 0;
3716
3717     if (!ap_casecmpstr(arg, "none")) {
3718         val = AP_MAXRANGES_NORANGES;
3719     }
3720     else if (!ap_casecmpstr(arg, "default")) {
3721         val = AP_MAXRANGES_DEFAULT;
3722     }
3723     else if (!ap_casecmpstr(arg, "unlimited")) {
3724         val = AP_MAXRANGES_UNLIMITED;
3725     }
3726     else {
3727         val = atoi(arg);
3728         if (val <= 0)
3729             return "MaxRangeReversals requires 'none', 'default', 'unlimited' or "
3730             "a positive integer";
3731     }
3732
3733     conf->max_reversals = val;
3734
3735     return NULL;
3736 }
3737
3738 AP_DECLARE(apr_size_t) ap_get_limit_xml_body(const request_rec *r)
3739 {
3740     core_dir_config *conf;
3741
3742     conf = ap_get_core_module_config(r->per_dir_config);
3743     if (conf->limit_xml_body == AP_LIMIT_UNSET)
3744         return AP_DEFAULT_LIMIT_XML_BODY;
3745
3746     return (apr_size_t)conf->limit_xml_body;
3747 }
3748
3749 #if !defined (RLIMIT_CPU) || !(defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)) || !defined (RLIMIT_NPROC)
3750 static const char *no_set_limit(cmd_parms *cmd, void *conf_,
3751                                 const char *arg, const char *arg2)
3752 {
3753     ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server, APLOGNO(00118)
3754                 "%s not supported on this platform", cmd->cmd->name);
3755
3756     return NULL;
3757 }
3758 #endif
3759
3760 #ifdef RLIMIT_CPU
3761 static const char *set_limit_cpu(cmd_parms *cmd, void *conf_,
3762                                  const char *arg, const char *arg2)
3763 {
3764     core_dir_config *conf = conf_;
3765
3766     ap_unixd_set_rlimit(cmd, &conf->limit_cpu, arg, arg2, RLIMIT_CPU);
3767     return NULL;
3768 }
3769 #endif
3770
3771 #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)
3772 static const char *set_limit_mem(cmd_parms *cmd, void *conf_,
3773                                  const char *arg, const char * arg2)
3774 {
3775     core_dir_config *conf = conf_;
3776
3777 #if defined(RLIMIT_AS)
3778     ap_unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2 ,RLIMIT_AS);
3779 #elif defined(RLIMIT_DATA)
3780     ap_unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_DATA);
3781 #elif defined(RLIMIT_VMEM)
3782     ap_unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_VMEM);
3783 #endif
3784
3785     return NULL;
3786 }
3787 #endif
3788
3789 #ifdef RLIMIT_NPROC
3790 static const char *set_limit_nproc(cmd_parms *cmd, void *conf_,
3791                                    const char *arg, const char * arg2)
3792 {
3793     core_dir_config *conf = conf_;
3794
3795     ap_unixd_set_rlimit(cmd, &conf->limit_nproc, arg, arg2, RLIMIT_NPROC);
3796     return NULL;
3797 }
3798 #endif
3799
3800 static const char *set_recursion_limit(cmd_parms *cmd, void *dummy,
3801                                        const char *arg1, const char *arg2)
3802 {
3803     core_server_config *conf =
3804         ap_get_core_module_config(cmd->server->module_config);
3805     int limit = atoi(arg1);
3806
3807     if (limit <= 0) {
3808         return "The recursion limit must be greater than zero.";
3809     }
3810     if (limit < 4) {
3811         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(00119)
3812                      "Limiting internal redirects to very low numbers may "
3813                      "cause normal requests to fail.");
3814     }
3815
3816     conf->redirect_limit = limit;
3817
3818     if (arg2) {
3819         limit = atoi(arg2);
3820
3821         if (limit <= 0) {
3822             return "The recursion limit must be greater than zero.";
3823         }
3824         if (limit < 4) {
3825             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(00120)
3826                          "Limiting the subrequest depth to a very low level may"
3827                          " cause normal requests to fail.");
3828         }
3829     }
3830
3831     conf->subreq_limit = limit;
3832
3833     return NULL;
3834 }
3835
3836 static void log_backtrace(const request_rec *r)
3837 {
3838     const request_rec *top = r;
3839
3840     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00121)
3841                   "r->uri = %s", r->uri ? r->uri : "(unexpectedly NULL)");
3842
3843     while (top && (top->prev || top->main)) {
3844         if (top->prev) {
3845             top = top->prev;
3846             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00122)
3847                           "redirected from r->uri = %s",
3848                           top->uri ? top->uri : "(unexpectedly NULL)");
3849         }
3850
3851         if (!top->prev && top->main) {
3852             top = top->main;
3853             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00123)
3854                           "subrequested from r->uri = %s",
3855                           top->uri ? top->uri : "(unexpectedly NULL)");
3856         }
3857     }
3858 }
3859
3860 /*
3861  * check whether redirect limit is reached
3862  */
3863 AP_DECLARE(int) ap_is_recursion_limit_exceeded(const request_rec *r)
3864 {
3865     core_server_config *conf =
3866         ap_get_core_module_config(r->server->module_config);
3867     const request_rec *top = r;
3868     int redirects = 0, subreqs = 0;
3869     int rlimit = conf->redirect_limit
3870                  ? conf->redirect_limit
3871                  : AP_DEFAULT_MAX_INTERNAL_REDIRECTS;
3872     int slimit = conf->subreq_limit
3873                  ? conf->subreq_limit
3874                  : AP_DEFAULT_MAX_SUBREQ_DEPTH;
3875
3876
3877     while (top->prev || top->main) {
3878         if (top->prev) {
3879             if (++redirects >= rlimit) {
3880                 /* uuh, too much. */
3881                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00124)
3882                               "Request exceeded the limit of %d internal "
3883                               "redirects due to probable configuration error. "
3884                               "Use 'LimitInternalRecursion' to increase the "
3885                               "limit if necessary. Use 'LogLevel debug' to get "
3886                               "a backtrace.", rlimit);
3887
3888                 /* post backtrace */
3889                 log_backtrace(r);
3890
3891                 /* return failure */
3892                 return 1;
3893             }
3894
3895             top = top->prev;
3896         }
3897
3898         if (!top->prev && top->main) {
3899             if (++subreqs >= slimit) {
3900                 /* uuh, too much. */
3901                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00125)
3902                               "Request exceeded the limit of %d subrequest "
3903                               "nesting levels due to probable configuration "
3904                               "error. Use 'LimitInternalRecursion' to increase "
3905                               "the limit if necessary. Use 'LogLevel debug' to "
3906                               "get a backtrace.", slimit);
3907
3908                 /* post backtrace */
3909                 log_backtrace(r);
3910
3911                 /* return failure */
3912                 return 1;
3913             }
3914
3915             top = top->main;
3916         }
3917     }
3918
3919     /* recursion state: ok */
3920     return 0;
3921 }
3922
3923 static const char *set_trace_enable(cmd_parms *cmd, void *dummy,
3924                                     const char *arg1)
3925 {
3926     core_server_config *conf =
3927         ap_get_core_module_config(cmd->server->module_config);
3928
3929     if (ap_casecmpstr(arg1, "on") == 0) {
3930         conf->trace_enable = AP_TRACE_ENABLE;
3931     }
3932     else if (ap_casecmpstr(arg1, "off") == 0) {
3933         conf->trace_enable = AP_TRACE_DISABLE;
3934     }
3935     else if (ap_casecmpstr(arg1, "extended") == 0) {
3936         conf->trace_enable = AP_TRACE_EXTENDED;
3937     }
3938     else {
3939         return "TraceEnable must be one of 'on', 'off', or 'extended'";
3940     }
3941
3942     return NULL;
3943 }
3944
3945 static const char *set_protocols(cmd_parms *cmd, void *dummy,
3946                                  const char *arg)
3947 {
3948     core_server_config *conf =
3949     ap_get_core_module_config(cmd->server->module_config);
3950     const char **np;
3951     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
3952
3953     if (err) {
3954         return err;
3955     }
3956     
3957     np = (const char **)apr_array_push(conf->protocols);
3958     *np = arg;
3959
3960     return NULL;
3961 }
3962
3963 static const char *set_protocols_honor_order(cmd_parms *cmd, void *dummy,
3964                                              const char *arg)
3965 {
3966     core_server_config *conf =
3967     ap_get_core_module_config(cmd->server->module_config);
3968     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
3969     
3970     if (err) {
3971         return err;
3972     }
3973     
3974     if (ap_casecmpstr(arg, "on") == 0) {
3975         conf->protocols_honor_order = 1;
3976     }
3977     else if (ap_casecmpstr(arg, "off") == 0) {
3978         conf->protocols_honor_order = 0;
3979     }
3980     else {
3981         return "ProtocolsHonorOrder must be 'on' or 'off'";
3982     }
3983     
3984     return NULL;
3985 }
3986
3987 static const char *set_http_protocol(cmd_parms *cmd, void *dummy,
3988                                      const char *arg)
3989 {
3990     core_server_config *conf =
3991         ap_get_core_module_config(cmd->server->module_config);
3992
3993     if (strncmp(arg, "min=", 4) == 0) {
3994         arg += 4;
3995         if (strcmp(arg, "0.9") == 0)
3996             conf->http09_enable = AP_HTTP09_ENABLE;
3997         else if (strcmp(arg, "1.0") == 0)
3998             conf->http09_enable = AP_HTTP09_DISABLE;
3999         else
4000             return "HttpProtocol 'min' must be one of '0.9' and '1.0'";
4001         return NULL;
4002     }
4003
4004     if (strcmp(arg, "strict") == 0)
4005         conf->http_conformance = AP_HTTP_CONFORMANCE_STRICT;
4006     else if (strcmp(arg, "strict,log-only") == 0)
4007         conf->http_conformance = AP_HTTP_CONFORMANCE_STRICT|
4008                                  AP_HTTP_CONFORMANCE_LOGONLY;
4009     else if (strcmp(arg, "liberal") == 0)
4010         conf->http_conformance = AP_HTTP_CONFORMANCE_LIBERAL;
4011     else
4012         return "HttpProtocol accepts 'min=0.9', 'min=1.0', 'liberal', "
4013                "'strict', 'strict,log-only'";
4014
4015     if ((conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT) &&
4016         (conf->http_conformance & AP_HTTP_CONFORMANCE_LIBERAL)) {
4017         return "HttpProtocol 'strict' and 'liberal' are mutually exclusive";
4018     }
4019
4020     return NULL;
4021 }
4022
4023 static const char *set_async_filter(cmd_parms *cmd, void *dummy,
4024                                              const char *arg)
4025 {
4026     core_server_config *conf =
4027     ap_get_core_module_config(cmd->server->module_config);
4028     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
4029
4030     if (err) {
4031         return err;
4032     }
4033
4034     if (ap_casecmpstr(arg, "network") == 0) {
4035         conf->async_filter = AP_FTYPE_NETWORK;
4036     }
4037     else if (ap_casecmpstr(arg, "connection") == 0) {
4038         conf->async_filter = AP_FTYPE_CONNECTION;
4039     }
4040     else if (ap_casecmpstr(arg, "request") == 0) {
4041         conf->async_filter = 0;
4042     }
4043     else {
4044         return "AsyncFilter must be 'network', 'connection' or 'request'";
4045     }
4046     conf->async_filter_set = 1;
4047
4048     return NULL;
4049 }
4050
4051 static const char *set_http_method(cmd_parms *cmd, void *conf, const char *arg)
4052 {
4053     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
4054     if (err != NULL)
4055         return err;
4056     ap_method_register(cmd->pool, arg);
4057     return NULL;
4058 }
4059
4060 static const char *set_cl_head_zero(cmd_parms *cmd, void *dummy, int arg)
4061 {
4062     core_server_config *conf =
4063         ap_get_core_module_config(cmd->server->module_config);
4064
4065     if (arg) {
4066         conf->http_cl_head_zero = AP_HTTP_CL_HEAD_ZERO_ENABLE;
4067     } else {
4068         conf->http_cl_head_zero = AP_HTTP_CL_HEAD_ZERO_DISABLE;
4069     }
4070     return NULL;
4071 }
4072
4073 static const char *set_expect_strict(cmd_parms *cmd, void *dummy, int arg)
4074 {
4075     core_server_config *conf =
4076         ap_get_core_module_config(cmd->server->module_config);
4077
4078     if (arg) {
4079         conf->http_expect_strict = AP_HTTP_EXPECT_STRICT_ENABLE;
4080     } else {
4081         conf->http_expect_strict = AP_HTTP_EXPECT_STRICT_DISABLE;
4082     }
4083     return NULL;
4084 }
4085
4086 static apr_hash_t *errorlog_hash;
4087
4088 static int log_constant_item(const ap_errorlog_info *info, const char *arg,
4089                              char *buf, int buflen)
4090 {
4091     char *end = apr_cpystrn(buf, arg, buflen);
4092     return end - buf;
4093 }
4094
4095 static char *parse_errorlog_misc_string(apr_pool_t *p,
4096                                         ap_errorlog_format_item *it,
4097                                         const char **sa)
4098 {
4099     const char *s;
4100     char scratch[MAX_STRING_LEN];
4101     char *d = scratch;
4102     /*
4103      * non-leading white space terminates this string to allow the next field
4104      * separator to be inserted
4105      */
4106     int at_start = 1;
4107
4108     it->func = log_constant_item;
4109     s = *sa;
4110
4111     while (*s && *s != '%' && (*s != ' ' || at_start) && d < scratch + MAX_STRING_LEN) {
4112         if (*s != '\\') {
4113             if (*s != ' ') {
4114                 at_start = 0;
4115             }
4116             *d++ = *s++;
4117         }
4118         else {
4119             s++;
4120             switch (*s) {
4121             case 'r':
4122                 *d++ = '\r';
4123                 s++;
4124                 break;
4125             case 'n':
4126                 *d++ = '\n';
4127                 s++;
4128                 break;
4129             case 't':
4130                 *d++ = '\t';
4131                 s++;
4132                 break;
4133             case '\0':
4134                 /* handle end of string */
4135                 *d++ = '\\';
4136                 break;
4137             default:
4138                 /* copy next char verbatim */
4139                 *d++ = *s++;
4140                 break;
4141             }
4142         }
4143     }
4144     *d = '\0';
4145     it->arg = apr_pstrdup(p, scratch);
4146
4147     *sa = s;
4148     return NULL;
4149 }
4150
4151 static char *parse_errorlog_item(apr_pool_t *p, ap_errorlog_format_item *it,
4152                                  const char **sa)
4153 {
4154     const char *s = *sa;
4155     ap_errorlog_handler *handler;
4156     int i;
4157
4158     if (*s != '%') {
4159         if (*s == ' ') {
4160             it->flags |= AP_ERRORLOG_FLAG_FIELD_SEP;
4161         }
4162         return parse_errorlog_misc_string(p, it, sa);
4163     }
4164
4165     ++s;
4166
4167     if (*s == ' ') {
4168         /* percent-space (% ) is a field separator */
4169         it->flags |= AP_ERRORLOG_FLAG_FIELD_SEP;
4170         *sa = ++s;
4171         /* recurse */
4172         return parse_errorlog_item(p, it, sa);
4173     }
4174     else if (*s == '%') {
4175         it->arg = "%";
4176         it->func = log_constant_item;
4177         *sa = ++s;
4178         return NULL;
4179     }
4180
4181     while (*s) {
4182         switch (*s) {
4183         case '{':
4184             ++s;
4185             it->arg = ap_getword(p, &s, '}');
4186             break;
4187         case '+':
4188             ++s;
4189             it->flags |= AP_ERRORLOG_FLAG_REQUIRED;
4190             break;
4191         case '-':
4192             ++s;
4193             it->flags |= AP_ERRORLOG_FLAG_NULL_AS_HYPHEN;
4194             break;
4195         case '0':
4196         case '1':
4197         case '2':
4198         case '3':
4199         case '4':
4200         case '5':
4201         case '6':
4202         case '7':
4203         case '8':
4204         case '9':
4205             i = *s - '0';
4206             while (apr_isdigit(*++s))
4207                 i = i * 10 + (*s) - '0';
4208             it->min_loglevel = i;
4209             break;
4210         case 'M':
4211             it->func = NULL;
4212             it->flags |= AP_ERRORLOG_FLAG_MESSAGE;
4213             *sa = ++s;
4214             return NULL;
4215         default:
4216             handler = (ap_errorlog_handler *)apr_hash_get(errorlog_hash, s, 1);
4217             if (!handler) {
4218                 char dummy[2];
4219
4220                 dummy[0] = *s;
4221                 dummy[1] = '\0';
4222                 return apr_pstrcat(p, "Unrecognized error log format directive %",
4223                                dummy, NULL);
4224             }
4225             it->func = handler->func;
4226             *sa = ++s;
4227             return NULL;
4228         }
4229     }
4230
4231     return "Ran off end of error log format parsing args to some directive";
4232 }
4233
4234 static apr_array_header_t *parse_errorlog_string(apr_pool_t *p,
4235                                                  const char *s,
4236                                                  const char **err,
4237                                                  int is_main_fmt)
4238 {
4239     apr_array_header_t *a = apr_array_make(p, 30,
4240                                            sizeof(ap_errorlog_format_item));
4241     char *res;
4242     int seen_msg_fmt = 0;
4243
4244     while (s && *s) {
4245         ap_errorlog_format_item *item =
4246             (ap_errorlog_format_item *)apr_array_push(a);
4247         memset(item, 0, sizeof(*item));
4248         res = parse_errorlog_item(p, item, &s);
4249         if (res) {
4250             *err = res;
4251             return NULL;
4252         }
4253         if (item->flags & AP_ERRORLOG_FLAG_MESSAGE) {
4254             if (!is_main_fmt) {
4255                 *err = "%M cannot be used in once-per-request or "
4256                        "once-per-connection formats";
4257                 return NULL;
4258             }
4259             seen_msg_fmt = 1;
4260         }
4261         if (is_main_fmt && item->flags & AP_ERRORLOG_FLAG_REQUIRED) {
4262             *err = "The '+' flag cannot be used in the main error log format";
4263             return NULL;
4264         }
4265         if (!is_main_fmt && item->min_loglevel) {
4266             *err = "The loglevel cannot be used as a condition in "
4267                    "once-per-request or once-per-connection formats";
4268             return NULL;
4269         }
4270         if (item->min_loglevel > APLOG_TRACE8) {
4271             *err = "The specified loglevel modifier is out of range";
4272             return NULL;
4273         }
4274     }
4275
4276     if (is_main_fmt && !seen_msg_fmt) {
4277         *err = "main ErrorLogFormat must contain message format string '%M'";
4278         return NULL;
4279     }
4280
4281     return a;
4282 }
4283
4284 static const char *set_errorlog(cmd_parms *cmd, void *dummy, const char *arg1,
4285                                 const char *arg2)
4286 {
4287     ap_errorlog_provider *provider;
4288     const char *err;
4289     cmd->server->errorlog_provider = NULL;
4290
4291     if (!arg2) {
4292         /* Stay backward compatible and check for "syslog" */
4293         if (strncmp("syslog", arg1, 6) == 0) {
4294             arg2 = arg1 + 7; /* skip the ':' if any */
4295             arg1 = "syslog";
4296         }
4297         else {
4298             /* Admin can define only "ErrorLog provider" and we should 
4299              * still handle that using the defined provider, but with empty
4300              * error_fname. */
4301             provider = ap_lookup_provider(AP_ERRORLOG_PROVIDER_GROUP, arg1,
4302                                           AP_ERRORLOG_PROVIDER_VERSION);
4303             if (provider) {
4304                 arg2 = "";
4305             }
4306             else {
4307                 return set_server_string_slot(cmd, dummy, arg1);
4308             }
4309         }
4310     }
4311
4312     if (strcmp("file", arg1) == 0) {
4313         return set_server_string_slot(cmd, dummy, arg2);
4314     }
4315
4316     provider = ap_lookup_provider(AP_ERRORLOG_PROVIDER_GROUP, arg1,
4317                                     AP_ERRORLOG_PROVIDER_VERSION);
4318     if (!provider) {
4319         return apr_psprintf(cmd->pool,
4320                             "Unknown ErrorLog provider: %s",
4321                             arg1);
4322     }
4323
4324     err = provider->parse_errorlog_arg(cmd, arg2);
4325     if (err) {
4326         return err;
4327     }
4328
4329     cmd->server->errorlog_provider = provider;
4330     return set_server_string_slot(cmd, dummy, arg2);
4331 }
4332
4333 static const char *set_errorlog_format(cmd_parms *cmd, void *dummy,
4334                                        const char *arg1, const char *arg2)
4335 {
4336     const char *err_string = NULL;
4337     core_server_config *conf =
4338         ap_get_core_module_config(cmd->server->module_config);
4339
4340     if (!arg2) {
4341         conf->error_log_format = parse_errorlog_string(cmd->pool, arg1,
4342                                                        &err_string, 1);
4343     }
4344     else if (!ap_casecmpstr(arg1, "connection")) {
4345         if (!conf->error_log_conn) {
4346             conf->error_log_conn = apr_array_make(cmd->pool, 5,
4347                                                   sizeof(apr_array_header_t *));
4348         }
4349
4350         if (*arg2) {
4351             apr_array_header_t **e;
4352             e = (apr_array_header_t **) apr_array_push(conf->error_log_conn);
4353             *e = parse_errorlog_string(cmd->pool, arg2, &err_string, 0);
4354         }
4355     }
4356     else if (!ap_casecmpstr(arg1, "request")) {
4357         if (!conf->error_log_req) {
4358             conf->error_log_req = apr_array_make(cmd->pool, 5,
4359                                                  sizeof(apr_array_header_t *));
4360         }
4361
4362         if (*arg2) {
4363             apr_array_header_t **e;
4364             e = (apr_array_header_t **) apr_array_push(conf->error_log_req);
4365             *e = parse_errorlog_string(cmd->pool, arg2, &err_string, 0);
4366         }
4367     }
4368     else {
4369         err_string = "ErrorLogFormat type must be one of request, connection";
4370     }
4371
4372     return err_string;
4373 }
4374
4375 AP_DECLARE(void) ap_register_errorlog_handler(apr_pool_t *p, char *tag,
4376                                               ap_errorlog_handler_fn_t *handler,
4377                                               int flags)
4378 {
4379     ap_errorlog_handler *log_struct = apr_palloc(p, sizeof(*log_struct));
4380     log_struct->func = handler;
4381     log_struct->flags = flags;
4382
4383     apr_hash_set(errorlog_hash, tag, 1, (const void *)log_struct);
4384 }
4385
4386
4387 static const char *set_merge_trailers(cmd_parms *cmd, void *dummy, int arg)
4388 {
4389     core_server_config *conf = ap_get_module_config(cmd->server->module_config,
4390                                                     &core_module);
4391     conf->merge_trailers = (arg ? AP_MERGE_TRAILERS_ENABLE :
4392             AP_MERGE_TRAILERS_DISABLE);
4393
4394     return NULL;
4395 }
4396
4397 /* Note --- ErrorDocument will now work from .htaccess files.
4398  * The AllowOverride of Fileinfo allows webmasters to turn it off
4399  */
4400
4401 static const command_rec core_cmds[] = {
4402
4403 /* Old access config file commands */
4404
4405 AP_INIT_RAW_ARGS("<Directory", dirsection, NULL, RSRC_CONF,
4406   "Container for directives affecting resources located in the specified "
4407   "directories"),
4408 AP_INIT_RAW_ARGS("<Location", urlsection, NULL, RSRC_CONF,
4409   "Container for directives affecting resources accessed through the "
4410   "specified URL paths"),
4411 AP_INIT_RAW_ARGS("<VirtualHost", virtualhost_section, NULL, RSRC_CONF,
4412   "Container to map directives to a particular virtual host, takes one or "
4413   "more host addresses"),
4414 AP_INIT_RAW_ARGS("<Files", filesection, NULL, OR_ALL,
4415   "Container for directives affecting files matching specified patterns"),
4416 AP_INIT_RAW_ARGS("<Limit", ap_limit_section, NULL, OR_LIMIT | OR_AUTHCFG,
4417   "Container for authentication directives when accessed using specified HTTP "
4418   "methods"),
4419 AP_INIT_RAW_ARGS("<LimitExcept", ap_limit_section, (void*)1,
4420                  OR_LIMIT | OR_AUTHCFG,
4421   "Container for authentication directives to be applied when any HTTP "
4422   "method other than those specified is used to access the resource"),
4423 AP_INIT_TAKE1("<IfModule", start_ifmod, NULL, EXEC_ON_READ | OR_ALL,
4424   "Container for directives based on existence of specified modules"),
4425 AP_INIT_TAKE1("<IfDefine", start_ifdefine, NULL, EXEC_ON_READ | OR_ALL,
4426   "Container for directives based on existence of command line defines"),
4427 AP_INIT_RAW_ARGS("<DirectoryMatch", dirsection, (void*)1, RSRC_CONF,
4428   "Container for directives affecting resources located in the "
4429   "specified directories"),
4430 AP_INIT_RAW_ARGS("<LocationMatch", urlsection, (void*)1, RSRC_CONF,
4431   "Container for directives affecting resources accessed through the "
4432   "specified URL paths"),
4433 AP_INIT_RAW_ARGS("<FilesMatch", filesection, (void*)1, OR_ALL,
4434   "Container for directives affecting files matching specified patterns"),
4435 #ifdef GPROF
4436 AP_INIT_TAKE1("GprofDir", set_gprof_dir, NULL, RSRC_CONF,
4437   "Directory to plop gmon.out files"),
4438 #endif
4439 AP_INIT_TAKE1("AddDefaultCharset", set_add_default_charset, NULL, OR_FILEINFO,
4440   "The name of the default charset to add to any Content-Type without one or 'Off' to disable"),
4441 AP_INIT_TAKE1("AcceptPathInfo", set_accept_path_info, NULL, OR_FILEINFO,
4442   "Set to on or off for PATH_INFO to be accepted by handlers, or default for the per-handler preference"),
4443 AP_INIT_TAKE12("Define", set_define, NULL, EXEC_ON_READ|RSRC_CONF,
4444               "Define a variable, optionally to a value.  Same as passing -D to the command line."),
4445 AP_INIT_TAKE1("UnDefine", unset_define, NULL, EXEC_ON_READ|RSRC_CONF,
4446               "Undefine the existence of a variable. Undo a Define."),
4447 AP_INIT_RAW_ARGS("Error", generate_message, (void*) APLOG_ERR, OR_ALL,
4448                  "Generate error message from within configuration."),
4449 AP_INIT_RAW_ARGS("Warning", generate_message, (void*) APLOG_WARNING, OR_ALL,
4450                  "Generate warning message from within configuration."),
4451 AP_INIT_RAW_ARGS("<If", ifsection, COND_IF, OR_ALL,
4452   "Container for directives to be conditionally applied"),
4453 AP_INIT_RAW_ARGS("<ElseIf", ifsection, COND_ELSEIF, OR_ALL,
4454   "Container for directives to be conditionally applied"),
4455 AP_INIT_RAW_ARGS("<Else", ifsection, COND_ELSE, OR_ALL,
4456   "Container for directives to be conditionally applied"),
4457
4458 /* Old resource config file commands */
4459
4460 AP_INIT_RAW_ARGS("AccessFileName", set_access_name, NULL, RSRC_CONF,
4461   "Name(s) of per-directory config files (default: .htaccess)"),
4462 AP_INIT_TAKE1("DocumentRoot", set_document_root, NULL, RSRC_CONF,
4463   "Root directory of the document tree"),
4464 AP_INIT_TAKE2("ErrorDocument", set_error_document, NULL, OR_FILEINFO,
4465   "Change responses for HTTP errors"),
4466 AP_INIT_RAW_ARGS("AllowOverride", set_override, NULL, ACCESS_CONF,
4467   "Controls what groups of directives can be configured by per-directory "
4468   "config files"),
4469 AP_INIT_TAKE_ARGV("AllowOverrideList", set_override_list, NULL, ACCESS_CONF,
4470   "Controls what individual directives can be configured by per-directory "
4471   "config files"),
4472 AP_INIT_RAW_ARGS("Options", set_options, NULL, OR_OPTIONS,
4473   "Set a number of attributes for a given directory"),
4474 AP_INIT_TAKE1("DefaultType", set_default_type, NULL, OR_FILEINFO,
4475   "the default media type for otherwise untyped files (DEPRECATED)"),
4476 AP_INIT_RAW_ARGS("FileETag", set_etag_bits, NULL, OR_FILEINFO,
4477   "Specify components used to construct a file's ETag"),
4478 AP_INIT_TAKE1("EnableMMAP", set_enable_mmap, NULL, OR_FILEINFO,
4479   "Controls whether memory-mapping may be used to read files"),
4480 AP_INIT_TAKE1("EnableSendfile", set_enable_sendfile, NULL, OR_FILEINFO,
4481   "Controls whether sendfile may be used to transmit files"),
4482
4483 /* Old server config file commands */
4484
4485 AP_INIT_TAKE1("Protocol", set_protocol, NULL, RSRC_CONF,
4486   "Set the Protocol for httpd to use."),
4487 AP_INIT_TAKE2("AcceptFilter", set_accf_map, NULL, RSRC_CONF,
4488   "Set the Accept Filter to use for a protocol"),
4489 AP_INIT_TAKE1("Port", ap_set_deprecated, NULL, RSRC_CONF,
4490   "Port was replaced with Listen in Apache 2.0"),
4491 AP_INIT_TAKE1("HostnameLookups", set_hostname_lookups, NULL,
4492   ACCESS_CONF|RSRC_CONF,
4493   "\"on\" to enable, \"off\" to disable reverse DNS lookups, or \"double\" to "
4494   "enable double-reverse DNS lookups"),
4495 AP_INIT_TAKE1("ServerAdmin", set_server_string_slot,
4496   (void *)APR_OFFSETOF(server_rec, server_admin), RSRC_CONF,
4497   "The email address of the server administrator"),
4498 AP_INIT_TAKE1("ServerName", server_hostname_port, NULL, RSRC_CONF,
4499   "The hostname and port of the server"),
4500 AP_INIT_TAKE1("ServerSignature", set_signature_flag, NULL, OR_ALL,
4501   "En-/disable server signature (on|off|email)"),
4502 AP_INIT_TAKE1("ServerRoot", set_server_root, NULL, RSRC_CONF | EXEC_ON_READ,
4503   "Common directory of server-related files (logs, confs, etc.)"),
4504 AP_INIT_TAKE1("DefaultRuntimeDir", set_runtime_dir, NULL, RSRC_CONF | EXEC_ON_READ,
4505   "Common directory for run-time files (shared memory, locks, etc.)"),
4506 AP_INIT_TAKE12("ErrorLog", set_errorlog,
4507   (void *)APR_OFFSETOF(server_rec, error_fname), RSRC_CONF,
4508   "The filename of the error log"),
4509 AP_INIT_TAKE12("ErrorLogFormat", set_errorlog_format, NULL, RSRC_CONF,
4510   "Format string for the ErrorLog"),
4511 AP_INIT_RAW_ARGS("ServerAlias", set_server_alias, NULL, RSRC_CONF,
4512   "A name or names alternately used to access the server"),
4513 AP_INIT_TAKE1("ServerPath", set_serverpath, NULL, RSRC_CONF,
4514   "The pathname the server can be reached at"),
4515 AP_INIT_TAKE1("Timeout", set_timeout, NULL, RSRC_CONF,
4516   "Timeout duration (sec)"),
4517 AP_INIT_FLAG("ContentDigest", set_content_md5, NULL, OR_OPTIONS,
4518   "whether or not to send a Content-MD5 header with each request"),
4519 AP_INIT_TAKE1("UseCanonicalName", set_use_canonical_name, NULL,
4520   RSRC_CONF|ACCESS_CONF,
4521   "How to work out the ServerName : Port when constructing URLs"),
4522 AP_INIT_TAKE1("UseCanonicalPhysicalPort", set_use_canonical_phys_port, NULL,
4523   RSRC_CONF|ACCESS_CONF,
4524   "Whether to use the physical Port when constructing URLs"),
4525 /* TODO: RlimitFoo should all be part of mod_cgi, not in the core */
4526 /* TODO: ListenBacklog in MPM */
4527 AP_INIT_TAKE1("Include", include_config, NULL,
4528   (RSRC_CONF | ACCESS_CONF | EXEC_ON_READ),
4529   "Name(s) of the config file(s) to be included; fails if the wildcard does "
4530   "not match at least one file"),
4531 AP_INIT_TAKE1("IncludeOptional", include_config, (void*)1,
4532   (RSRC_CONF | ACCESS_CONF | EXEC_ON_READ),
4533   "Name or pattern of the config file(s) to be included; ignored if the file "
4534   "does not exist or the pattern does not match any files"),
4535 AP_INIT_ITERATE("LogLevel", set_loglevel, NULL, RSRC_CONF|ACCESS_CONF,
4536   "Level of verbosity in error logging"),
4537 AP_INIT_TAKE_ARGV("LogLevelOverride", set_loglevel_override, NULL, RSRC_CONF,
4538   "Override LogLevel for clients with certain IPs"),
4539 AP_INIT_TAKE1("NameVirtualHost", ap_set_name_virtual_host, NULL, RSRC_CONF,
4540   "A numeric IP address:port, or the name of a host"),
4541 AP_INIT_TAKE1("ServerTokens", set_serv_tokens, NULL, RSRC_CONF,
4542   "Determine tokens displayed in the Server: header - Min(imal), "
4543   "Major, Minor, Prod(uctOnly), OS, or Full"),
4544 AP_INIT_TAKE1("LimitRequestLine", set_limit_req_line, NULL, RSRC_CONF,
4545   "Limit on maximum size of an HTTP request line"),
4546 AP_INIT_TAKE1("LimitRequestFieldsize", set_limit_req_fieldsize, NULL,
4547   RSRC_CONF,
4548   "Limit on maximum size of an HTTP request header field"),
4549 AP_INIT_TAKE1("LimitRequestFields", set_limit_req_fields, NULL, RSRC_CONF,
4550   "Limit (0 = unlimited) on max number of header fields in a request message"),
4551 AP_INIT_TAKE1("LimitRequestBody", set_limit_req_body,
4552   (void*)APR_OFFSETOF(core_dir_config, limit_req_body), OR_ALL,
4553   "Limit (in bytes) on maximum size of request message body"),
4554 AP_INIT_TAKE1("LimitXMLRequestBody", set_limit_xml_req_body, NULL, OR_ALL,
4555               "Limit (in bytes) on maximum size of an XML-based request "
4556               "body"),
4557 AP_INIT_RAW_ARGS("Mutex", ap_set_mutex, NULL, RSRC_CONF,
4558                  "mutex (or \"default\") and mechanism"),
4559
4560 AP_INIT_TAKE1("MaxRanges", set_max_ranges, NULL, RSRC_CONF|ACCESS_CONF,
4561               "Maximum number of Ranges in a request before returning the entire "
4562               "resource, or 0 for unlimited"),
4563 AP_INIT_TAKE1("MaxRangeOverlaps", set_max_overlaps, NULL, RSRC_CONF|ACCESS_CONF,
4564               "Maximum number of overlaps in Ranges in a request before returning the entire "
4565               "resource, or 0 for unlimited"),
4566 AP_INIT_TAKE1("MaxRangeReversals", set_max_reversals, NULL, RSRC_CONF|ACCESS_CONF,
4567               "Maximum number of reversals in Ranges in a request before returning the entire "
4568               "resource, or 0 for unlimited"),
4569 /* System Resource Controls */
4570 #ifdef RLIMIT_CPU
4571 AP_INIT_TAKE12("RLimitCPU", set_limit_cpu,
4572   (void*)APR_OFFSETOF(core_dir_config, limit_cpu),
4573   OR_ALL, "Soft/hard limits for max CPU usage in seconds"),
4574 #else
4575 AP_INIT_TAKE12("RLimitCPU", no_set_limit, NULL,
4576   OR_ALL, "Soft/hard limits for max CPU usage in seconds"),
4577 #endif
4578 #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined (RLIMIT_AS)
4579 AP_INIT_TAKE12("RLimitMEM", set_limit_mem,
4580   (void*)APR_OFFSETOF(core_dir_config, limit_mem),
4581   OR_ALL, "Soft/hard limits for max memory usage per process"),
4582 #else
4583 AP_INIT_TAKE12("RLimitMEM", no_set_limit, NULL,
4584   OR_ALL, "Soft/hard limits for max memory usage per process"),
4585 #endif
4586 #ifdef RLIMIT_NPROC
4587 AP_INIT_TAKE12("RLimitNPROC", set_limit_nproc,
4588   (void*)APR_OFFSETOF(core_dir_config, limit_nproc),
4589   OR_ALL, "soft/hard limits for max number of processes per uid"),
4590 #else
4591 AP_INIT_TAKE12("RLimitNPROC", no_set_limit, NULL,
4592    OR_ALL, "soft/hard limits for max number of processes per uid"),
4593 #endif
4594
4595 /* internal recursion stopper */
4596 AP_INIT_TAKE12("LimitInternalRecursion", set_recursion_limit, NULL, RSRC_CONF,
4597               "maximum recursion depth of internal redirects and subrequests"),
4598
4599 AP_INIT_FLAG("CGIPassAuth", set_cgi_pass_auth, NULL, OR_AUTHCFG,
4600              "Controls whether HTTP authorization headers, normally hidden, will "
4601              "be passed to scripts"),
4602 AP_INIT_TAKE2("CGIVar", set_cgi_var, NULL, OR_FILEINFO,
4603               "Controls how some CGI variables are set"),
4604 AP_INIT_FLAG("QualifyRedirectURL", set_qualify_redirect_url, NULL, OR_FILEINFO,
4605              "Controls whether the REDIRECT_URL environment variable is fully "
4606              "qualified"),
4607
4608 AP_INIT_TAKE1("ForceType", ap_set_string_slot_lower,
4609        (void *)APR_OFFSETOF(core_dir_config, mime_type), OR_FILEINFO,
4610      "a mime type that overrides other configured type"),
4611 AP_INIT_TAKE1("SetHandler", set_sethandler, NULL, OR_FILEINFO,
4612    "a handler name that overrides any other configured handler"),
4613 AP_INIT_TAKE1("SetOutputFilter", ap_set_string_slot,
4614        (void *)APR_OFFSETOF(core_dir_config, output_filters), OR_FILEINFO,
4615    "filter (or ; delimited list of filters) to be run on the request content"),
4616 AP_INIT_TAKE1("SetInputFilter", ap_set_string_slot,
4617        (void *)APR_OFFSETOF(core_dir_config, input_filters), OR_FILEINFO,
4618    "filter (or ; delimited list of filters) to be run on the request body"),
4619 AP_INIT_TAKE1("AllowEncodedSlashes", set_allow2f, NULL, RSRC_CONF,
4620              "Allow URLs containing '/' encoded as '%2F'"),
4621
4622 /* scoreboard.c directives */
4623 AP_INIT_TAKE1("ScoreBoardFile", ap_set_scoreboard, NULL, RSRC_CONF,
4624               "A file for Apache to maintain runtime process management information"),
4625 AP_INIT_FLAG("ExtendedStatus", ap_set_extended_status, NULL, RSRC_CONF,
4626              "\"On\" to track extended status information, \"Off\" to disable"),
4627 AP_INIT_FLAG("SeeRequestTail", ap_set_reqtail, NULL, RSRC_CONF,
4628              "For extended status, \"On\" to see the last 63 chars of "
4629              "the request line, \"Off\" (default) to see the first 63"),
4630
4631 /*
4632  * These are default configuration directives that mpms can/should
4633  * pay attention to.
4634  * XXX These are not for all platforms, and even some Unix MPMs might not want
4635  * some directives.
4636  */
4637 AP_INIT_TAKE1("PidFile",  ap_mpm_set_pidfile, NULL, RSRC_CONF,
4638               "A file for logging the server process ID"),
4639 AP_INIT_TAKE1("MaxRequestsPerChild", ap_mpm_set_max_requests, NULL, RSRC_CONF,
4640               "Maximum number of connections a particular child serves before "
4641               "dying. (DEPRECATED, use MaxConnectionsPerChild)"),
4642 AP_INIT_TAKE1("MaxConnectionsPerChild", ap_mpm_set_max_requests, NULL, RSRC_CONF,
4643               "Maximum number of connections a particular child serves before dying."),
4644 AP_INIT_TAKE1("CoreDumpDirectory", ap_mpm_set_coredumpdir, NULL, RSRC_CONF,
4645               "The location of the directory Apache changes to before dumping core"),
4646 AP_INIT_TAKE1("MaxMemFree", ap_mpm_set_max_mem_free, NULL, RSRC_CONF,
4647               "Maximum number of 1k blocks a particular child's allocator may hold."),
4648 AP_INIT_TAKE1("ThreadStackSize", ap_mpm_set_thread_stacksize, NULL, RSRC_CONF,
4649               "Size in bytes of stack used by threads handling client connections"),
4650 #if AP_ENABLE_EXCEPTION_HOOK
4651 AP_INIT_TAKE1("EnableExceptionHook", ap_mpm_set_exception_hook, NULL, RSRC_CONF,
4652               "Controls whether exception hook may be called after a crash"),
4653 #endif
4654 AP_INIT_TAKE1("TraceEnable", set_trace_enable, NULL, RSRC_CONF,
4655               "'on' (default), 'off' or 'extended' to trace request body content"),
4656 AP_INIT_FLAG("MergeTrailers", set_merge_trailers, NULL, RSRC_CONF,
4657               "merge request trailers into request headers or not"),
4658 AP_INIT_ITERATE("HttpProtocol", set_http_protocol, NULL, RSRC_CONF,
4659               "'min=0.9' (default) or 'min=1.0' to allow/deny HTTP/0.9; "
4660               "'liberal', 'strict', 'strict,log-only'"),
4661 AP_INIT_ITERATE("RegisterHttpMethod", set_http_method, NULL, RSRC_CONF,
4662                 "Registers non-standard HTTP methods"),
4663 AP_INIT_FLAG("HttpContentLengthHeadZero", set_cl_head_zero, NULL, OR_OPTIONS,
4664   "whether to permit Content-Length of 0 responses to HEAD requests"),
4665 AP_INIT_FLAG("HttpExpectStrict", set_expect_strict, NULL, OR_OPTIONS,
4666   "whether to return a 417 if a client doesn't send 100-Continue"),
4667 AP_INIT_ITERATE("Protocols", set_protocols, NULL, RSRC_CONF,
4668                 "Controls which protocols are allowed"),
4669 AP_INIT_TAKE1("ProtocolsHonorOrder", set_protocols_honor_order, NULL, RSRC_CONF,
4670               "'off' (default) or 'on' to respect given order of protocols, "
4671               "by default the client specified order determines selection"),
4672 AP_INIT_TAKE1("AsyncFilter", set_async_filter, NULL, RSRC_CONF,
4673               "'network', 'connection' (default) or 'request' to limit the "
4674               "types of filters that support asynchronous handling"),
4675 { NULL }
4676 };
4677
4678 /*****************************************************************
4679  *
4680  * Core handlers for various phases of server operation...
4681  */
4682
4683 AP_DECLARE_NONSTD(int) ap_core_translate(request_rec *r)
4684 {
4685     apr_status_t rv;
4686     char *path;
4687
4688     /* XXX this seems too specific, this should probably become
4689      * some general-case test
4690      */
4691     if (r->proxyreq) {
4692         return HTTP_FORBIDDEN;
4693     }
4694     if (!r->uri || ((r->uri[0] != '/') && strcmp(r->uri, "*"))) {
4695         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00126)
4696                      "Invalid URI in request %s", r->the_request);
4697         return HTTP_BAD_REQUEST;
4698     }
4699
4700     if (r->server->path
4701         && !strncmp(r->uri, r->server->path, r->server->pathlen)
4702         && (r->server->path[r->server->pathlen - 1] == '/'
4703             || r->uri[r->server->pathlen] == '/'
4704             || r->uri[r->server->pathlen] == '\0'))
4705     {
4706         path = r->uri + r->server->pathlen;
4707     }
4708     else {
4709         path = r->uri;
4710     }
4711     /*
4712      * Make sure that we do not mess up the translation by adding two
4713      * /'s in a row.  This happens under windows when the document
4714      * root ends with a /
4715      */
4716     /* skip all leading /'s (e.g. http://localhost///foo)
4717      * so we are looking at only the relative path.
4718      */
4719     while (*path == '/') {
4720         ++path;
4721     }
4722     if ((rv = apr_filepath_merge(&r->filename, ap_document_root(r), path,
4723                                  APR_FILEPATH_TRUENAME
4724                                | APR_FILEPATH_SECUREROOT, r->pool))
4725                 != APR_SUCCESS) {
4726         ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00127)
4727                      "Cannot map %s to file", r->the_request);
4728         return HTTP_FORBIDDEN;
4729     }
4730     r->canonical_filename = r->filename;
4731
4732     return OK;
4733 }
4734
4735 /*****************************************************************
4736  *
4737  * Test the filesystem name through directory_walk and file_walk
4738  */
4739 static int core_map_to_storage(request_rec *r)
4740 {
4741     int access_status;
4742
4743     if ((access_status = ap_directory_walk(r))) {
4744         return access_status;
4745     }
4746
4747     if ((access_status = ap_file_walk(r))) {
4748         return access_status;
4749     }
4750
4751     return OK;
4752 }
4753
4754
4755 static int do_nothing(request_rec *r) { return OK; }
4756
4757 static int core_override_type(request_rec *r)
4758 {
4759     core_dir_config *conf =
4760         (core_dir_config *)ap_get_core_module_config(r->per_dir_config);
4761
4762     /* Check for overrides with ForceType / SetHandler
4763      */
4764     if (conf->mime_type && strcmp(conf->mime_type, "none"))
4765         ap_set_content_type(r, (char*) conf->mime_type);
4766
4767     if (conf->expr_handler) { 
4768         const char *err;
4769         const char *val;
4770         val = ap_expr_str_exec(r, conf->expr_handler, &err);
4771         if (err) {
4772             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(03154)
4773                           "Can't evaluate handler expression: %s", err);
4774             return HTTP_INTERNAL_SERVER_ERROR;
4775         }
4776
4777         if (val != ap_strstr_c(val, "proxy:unix")) { 
4778             /* Retained for compatibility --  but not for UDS */
4779             char *tmp = apr_pstrdup(r->pool, val);
4780             ap_str_tolower(tmp);
4781             val = tmp;
4782         }
4783
4784         if (strcmp(val, "none")) { 
4785             r->handler = val;
4786         }
4787     }
4788     else if (conf->handler && strcmp(conf->handler, "none")) { 
4789         r->handler = conf->handler;
4790     }
4791
4792     /* Deal with the poor soul who is trying to force path_info to be
4793      * accepted within the core_handler, where they will let the subreq
4794      * address its contents.  This is toggled by the user in the very
4795      * beginning of the fixup phase (here!), so modules should override the user's
4796      * discretion in their own module fixup phase.  It is tristate, if
4797      * the user doesn't specify, the result is AP_REQ_DEFAULT_PATH_INFO.
4798      * (which the module may interpret to its own customary behavior.)
4799      * It won't be touched if the value is no longer AP_ACCEPT_PATHINFO_UNSET,
4800      * so any module changing the value prior to the fixup phase
4801      * OVERRIDES the user's choice.
4802      */
4803     if ((r->used_path_info == AP_REQ_DEFAULT_PATH_INFO)
4804         && (conf->accept_path_info != AP_ACCEPT_PATHINFO_UNSET)) {
4805         /* No module knew better, and the user coded AcceptPathInfo */
4806         r->used_path_info = conf->accept_path_info;
4807     }
4808
4809     return OK;
4810 }
4811
4812 static int default_handler(request_rec *r)
4813 {
4814     conn_rec *c = r->connection;
4815     apr_bucket_brigade *bb;
4816     apr_bucket *e;
4817     core_dir_config *d;
4818     int errstatus;
4819     apr_file_t *fd = NULL;
4820     apr_status_t status;
4821     /* XXX if/when somebody writes a content-md5 filter we either need to
4822      *     remove this support or coordinate when to use the filter vs.
4823      *     when to use this code
4824      *     The current choice of when to compute the md5 here matches the 1.3
4825      *     support fairly closely (unlike 1.3, we don't handle computing md5
4826      *     when the charset is translated).
4827      */
4828     int bld_content_md5;
4829
4830     d = (core_dir_config *)ap_get_core_module_config(r->per_dir_config);
4831     bld_content_md5 = (d->content_md5 == AP_CONTENT_MD5_ON)
4832                       && r->output_filters->frec->ftype != AP_FTYPE_RESOURCE;
4833
4834     ap_allow_standard_methods(r, MERGE_ALLOW, M_GET, M_OPTIONS, M_POST, -1);
4835
4836     /* If filters intend to consume the request body, they must
4837      * register an InputFilter to slurp the contents of the POST
4838      * data from the POST input stream.  It no longer exists when
4839      * the output filters are invoked by the default handler.
4840      */
4841     if ((errstatus = ap_discard_request_body(r)) != OK) {
4842         return errstatus;
4843     }
4844
4845     if (r->method_number == M_GET || r->method_number == M_POST) {
4846         if (r->finfo.filetype == APR_NOFILE) {
4847             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00128)
4848                           "File does not exist: %s",
4849                           apr_pstrcat(r->pool, r->filename, r->path_info, NULL));
4850             return HTTP_NOT_FOUND;
4851         }
4852
4853         /* Don't try to serve a dir.  Some OSs do weird things with
4854          * raw I/O on a dir.
4855          */
4856         if (r->finfo.filetype == APR_DIR) {
4857             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00129)
4858                           "Attempt to serve directory: %s", r->filename);
4859             return HTTP_NOT_FOUND;
4860         }
4861
4862         if ((r->used_path_info != AP_REQ_ACCEPT_PATH_INFO) &&
4863             r->path_info && *r->path_info)
4864         {
4865             /* default to reject */
4866             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00130)
4867                           "File does not exist: %s",
4868                           apr_pstrcat(r->pool, r->filename, r->path_info, NULL));
4869             return HTTP_NOT_FOUND;
4870         }
4871
4872         /* We understood the (non-GET) method, but it might not be legal for
4873            this particular resource. Check to see if the 'deliver_script'
4874            flag is set. If so, then we go ahead and deliver the file since
4875            it isn't really content (only GET normally returns content).
4876
4877            Note: based on logic further above, the only possible non-GET
4878            method at this point is POST. In the future, we should enable
4879            script delivery for all methods.  */
4880         if (r->method_number != M_GET) {
4881             core_request_config *req_cfg;
4882
4883             req_cfg = ap_get_core_module_config(r->request_config);
4884             if (!req_cfg->deliver_script) {
4885                 /* The flag hasn't been set for this request. Punt. */
4886                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00131)
4887                               "This resource does not accept the %s method.",
4888                               r->method);
4889                 return HTTP_METHOD_NOT_ALLOWED;
4890             }
4891         }
4892
4893
4894         if ((status = apr_file_open(&fd, r->filename, APR_READ | APR_BINARY
4895 #if APR_HAS_SENDFILE
4896                             | AP_SENDFILE_ENABLED(d->enable_sendfile)
4897 #endif
4898                                     , 0, r->pool)) != APR_SUCCESS) {
4899             ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00132)
4900                           "file permissions deny server access: %s", r->filename);
4901             return HTTP_FORBIDDEN;
4902         }
4903
4904         ap_update_mtime(r, r->finfo.mtime);
4905         ap_set_last_modified(r);
4906         ap_set_etag(r);
4907         ap_set_accept_ranges(r);
4908         ap_set_content_length(r, r->finfo.size);
4909         if (bld_content_md5) {
4910             apr_table_setn(r->headers_out, "Content-MD5",
4911                            ap_md5digest(r->pool, fd));
4912         }
4913
4914         bb = apr_brigade_create(r->pool, c->bucket_alloc);
4915
4916         if ((errstatus = ap_meets_conditions(r)) != OK) {
4917             apr_file_close(fd);
4918             r->status = errstatus;
4919         }
4920         else {
4921             e = apr_brigade_insert_file(bb, fd, 0, r->finfo.size, r->pool);
4922
4923 #if APR_HAS_MMAP
4924             if (d->enable_mmap == ENABLE_MMAP_OFF) {
4925                 (void)apr_bucket_file_enable_mmap(e, 0);
4926             }
4927 #endif
4928         }
4929
4930         e = apr_bucket_eos_create(c->bucket_alloc);
4931         APR_BRIGADE_INSERT_TAIL(bb, e);
4932
4933         status = ap_pass_brigade(r->output_filters, bb);
4934         if (status == APR_SUCCESS
4935             || r->status != HTTP_OK
4936             || c->aborted) {
4937             return OK;
4938         }
4939         else {
4940             /* no way to know what type of error occurred */
4941             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00133)
4942                           "default_handler: ap_pass_brigade returned %i",
4943                           status);
4944             return AP_FILTER_ERROR;
4945         }
4946     }
4947     else {              /* unusual method (not GET or POST) */
4948         if (r->method_number == M_INVALID) {
4949             /* See if this looks like an undecrypted SSL handshake attempt.
4950              * It's safe to look a couple bytes into the_request if it exists, as it's
4951              * always allocated at least MIN_LINE_ALLOC (80) bytes.
4952              */
4953             if (r->the_request
4954                 && r->the_request[0] == 0x16
4955                 && (r->the_request[1] == 0x2 || r->the_request[1] == 0x3)) {
4956                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00134)
4957                               "Invalid method in request %s - possible attempt to establish SSL connection on non-SSL port", r->the_request);
4958             } else {
4959                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00135)
4960                               "Invalid method in request %s", r->the_request);
4961             }
4962             return HTTP_NOT_IMPLEMENTED;
4963         }
4964
4965         if (r->method_number == M_OPTIONS) {
4966             return ap_send_http_options(r);
4967         }
4968         return HTTP_METHOD_NOT_ALLOWED;
4969     }
4970 }
4971
4972 /* Optional function coming from mod_logio, used for logging of output
4973  * traffic
4974  */
4975 APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *ap__logio_add_bytes_out;
4976 APR_OPTIONAL_FN_TYPE(authz_some_auth_required) *ap__authz_ap_some_auth_required;
4977
4978 /* Insist that at least one module will undertake to provide system
4979  * security by dropping startup privileges.
4980  */
4981 static int sys_privileges = 0;
4982 AP_DECLARE(int) ap_sys_privileges_handlers(int inc)
4983 {
4984     sys_privileges += inc;
4985     return sys_privileges;
4986 }
4987
4988 static int check_errorlog_dir(apr_pool_t *p, server_rec *s)
4989 {
4990     if (!s->error_fname || s->error_fname[0] == '|'
4991         || s->errorlog_provider != NULL) {
4992         return APR_SUCCESS;
4993     }
4994     else {
4995         char *abs = ap_server_root_relative(p, s->error_fname);
4996         char *dir = ap_make_dirstr_parent(p, abs);
4997         apr_finfo_t finfo;
4998         apr_status_t rv = apr_stat(&finfo, dir, APR_FINFO_TYPE, p);
4999         if (rv == APR_SUCCESS && finfo.filetype != APR_DIR)
5000             rv = APR_ENOTDIR;
5001         if (rv != APR_SUCCESS) {
5002             const char *desc = "main error log";
5003             if (s->defn_name)
5004                 desc = apr_psprintf(p, "error log of vhost defined at %s:%d",
5005                                     s->defn_name, s->defn_line_number);
5006             ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_EMERG, rv,
5007                           ap_server_conf, APLOGNO(02291)
5008                          "Cannot access directory '%s' for %s", dir, desc);
5009             return !OK;
5010         }
5011     }
5012     return OK;
5013 }
5014
5015 static int core_check_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
5016 {
5017     int rv = OK;
5018     while (s) {
5019         if (check_errorlog_dir(ptemp, s) != OK)
5020             rv = !OK;
5021         s = s->next;
5022     }
5023     return rv;
5024 }
5025
5026
5027 static int core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
5028 {
5029     ap_mutex_init(pconf);
5030
5031     if (!saved_server_config_defines)
5032         init_config_defines(pconf);
5033     apr_pool_cleanup_register(pconf, NULL, reset_config_defines,
5034                               apr_pool_cleanup_null);
5035
5036     mpm_common_pre_config(pconf);
5037
5038     return OK;
5039 }
5040
5041 static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
5042 {
5043     ap__logio_add_bytes_out = APR_RETRIEVE_OPTIONAL_FN(ap_logio_add_bytes_out);
5044     ident_lookup = APR_RETRIEVE_OPTIONAL_FN(ap_ident_lookup);
5045     ap__authz_ap_some_auth_required = APR_RETRIEVE_OPTIONAL_FN(authz_some_auth_required);
5046     authn_ap_auth_type = APR_RETRIEVE_OPTIONAL_FN(authn_ap_auth_type);
5047     authn_ap_auth_name = APR_RETRIEVE_OPTIONAL_FN(authn_ap_auth_name);
5048     access_compat_ap_satisfies = APR_RETRIEVE_OPTIONAL_FN(access_compat_ap_satisfies);
5049
5050     set_banner(pconf);
5051     ap_setup_make_content_type(pconf);
5052     ap_setup_auth_internal(ptemp);
5053     if (!sys_privileges) {
5054         ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL, APLOGNO(00136)
5055                      "Server MUST relinquish startup privileges before "
5056                      "accepting connections.  Please ensure mod_unixd "
5057                      "or other system security module is loaded.");
5058         return !OK;
5059     }
5060     apr_pool_cleanup_register(pconf, NULL, ap_mpm_end_gen_helper,
5061                               apr_pool_cleanup_null);
5062     return OK;
5063 }
5064
5065 static void core_insert_filter(request_rec *r)
5066 {
5067     core_dir_config *conf = (core_dir_config *)
5068                             ap_get_core_module_config(r->per_dir_config);
5069     const char *filter, *filters = conf->output_filters;
5070
5071     if (filters) {
5072         while (*filters && (filter = ap_getword(r->pool, &filters, ';'))) {
5073             ap_add_output_filter(filter, NULL, r, r->connection);
5074         }
5075     }
5076
5077     filters = conf->input_filters;
5078     if (filters) {
5079         while (*filters && (filter = ap_getword(r->pool, &filters, ';'))) {
5080             ap_add_input_filter(filter, NULL, r, r->connection);
5081         }
5082     }
5083 }
5084
5085 static apr_size_t num_request_notes = AP_NUM_STD_NOTES;
5086
5087 static apr_status_t reset_request_notes(void *dummy)
5088 {
5089     num_request_notes = AP_NUM_STD_NOTES;
5090     return APR_SUCCESS;
5091 }
5092
5093 AP_DECLARE(apr_size_t) ap_register_request_note(void)
5094 {
5095     apr_pool_cleanup_register(apr_hook_global_pool, NULL, reset_request_notes,
5096                               apr_pool_cleanup_null);
5097     return num_request_notes++;
5098 }
5099
5100 AP_DECLARE(void **) ap_get_request_note(request_rec *r, apr_size_t note_num)
5101 {
5102     core_request_config *req_cfg;
5103
5104     if (note_num >= num_request_notes) {
5105         return NULL;
5106     }
5107
5108     req_cfg = (core_request_config *)
5109         ap_get_core_module_config(r->request_config);
5110
5111     if (!req_cfg) {
5112         return NULL;
5113     }
5114
5115     return &(req_cfg->notes[note_num]);
5116 }
5117
5118 AP_DECLARE(apr_socket_t *) ap_get_conn_socket(conn_rec *c)
5119 {
5120     return ap_get_core_module_config(c->conn_config);
5121 }
5122
5123 static int core_create_req(request_rec *r)
5124 {
5125     /* Alloc the config struct and the array of request notes in
5126      * a single block for efficiency
5127      */
5128     core_request_config *req_cfg;
5129
5130     req_cfg = apr_pcalloc(r->pool, sizeof(core_request_config) +
5131                           sizeof(void *) * num_request_notes);
5132     req_cfg->notes = (void **)((char *)req_cfg + sizeof(core_request_config));
5133
5134     /* ### temporarily enable script delivery as the default */
5135     req_cfg->deliver_script = 1;
5136
5137     if (r->main) {
5138         core_request_config *main_req_cfg = (core_request_config *)
5139             ap_get_core_module_config(r->main->request_config);
5140         req_cfg->bb = main_req_cfg->bb;
5141     }
5142     else {
5143         req_cfg->bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
5144     }
5145
5146     ap_set_core_module_config(r->request_config, req_cfg);
5147
5148     return OK;
5149 }
5150
5151 static int core_create_proxy_req(request_rec *r, request_rec *pr)
5152 {
5153     return core_create_req(pr);
5154 }
5155
5156 static conn_rec *core_create_conn(apr_pool_t *ptrans, server_rec *s,
5157                                   apr_socket_t *csd, long id, void *sbh,
5158                                   apr_bucket_alloc_t *alloc)
5159 {
5160     apr_status_t rv;
5161     apr_pool_t *pool;
5162     conn_rec *c = (conn_rec *) apr_pcalloc(ptrans, sizeof(conn_rec));
5163     core_server_config *sconf = ap_get_core_module_config(s->module_config);
5164
5165     c->sbh = sbh;
5166     (void)ap_update_child_status(c->sbh, SERVER_BUSY_READ, (request_rec *)NULL);
5167
5168     /* Got a connection structure, so initialize what fields we can
5169      * (the rest are zeroed out by pcalloc).
5170      */
5171     apr_pool_create(&pool, ptrans);
5172     apr_pool_tag(pool, "master_conn");
5173     c->pool = pool;
5174
5175     c->conn_config = ap_create_conn_config(c->pool);
5176     c->notes = apr_table_make(c->pool, 5);
5177     c->slaves = apr_array_make(c->pool, 20, sizeof(conn_slave_rec *));
5178     c->requests = apr_array_make(c->pool, 20, sizeof(request_rec *));
5179
5180
5181     if ((rv = apr_socket_addr_get(&c->local_addr, APR_LOCAL, csd))
5182         != APR_SUCCESS) {
5183         ap_log_error(APLOG_MARK, APLOG_INFO, rv, s, APLOGNO(00137)
5184                      "apr_socket_addr_get(APR_LOCAL)");
5185         apr_socket_close(csd);
5186         return NULL;
5187     }
5188
5189     apr_sockaddr_ip_get(&c->local_ip, c->local_addr);
5190     if ((rv = apr_socket_addr_get(&c->client_addr, APR_REMOTE, csd))
5191         != APR_SUCCESS) {
5192         ap_log_error(APLOG_MARK, APLOG_INFO, rv, s, APLOGNO(00138)
5193                      "apr_socket_addr_get(APR_REMOTE)");
5194         apr_socket_close(csd);
5195         return NULL;
5196     }
5197
5198     apr_sockaddr_ip_get(&c->client_ip, c->client_addr);
5199     c->base_server = s;
5200
5201     c->id = id;
5202     c->bucket_alloc = alloc;
5203     c->empty = apr_brigade_create(c->pool, c->bucket_alloc);
5204     c->filters = apr_hash_make(c->pool);
5205     c->async_filter = sconf->async_filter;
5206
5207     c->clogging_input_filters = 0;
5208
5209     if (sconf->conn_log_level) {
5210         int i;
5211         conn_log_config *conf;
5212         const struct ap_logconf *log = NULL;
5213         struct ap_logconf *merged;
5214
5215         for (i = 0; i < sconf->conn_log_level->nelts; i++) {
5216             conf = APR_ARRAY_IDX(sconf->conn_log_level, i, conn_log_config *);
5217             if (apr_ipsubnet_test(conf->subnet, c->client_addr))
5218                 log = &conf->log;
5219         }
5220         if (log) {
5221             merged = ap_new_log_config(c->pool, log);
5222             ap_merge_log_config(&s->log, merged);
5223             c->log = merged;
5224         }
5225     }
5226
5227     return c;
5228 }
5229
5230 static int core_pre_connection(conn_rec *c, void *csd)
5231 {
5232     core_net_rec *net = apr_palloc(c->pool, sizeof(*net));
5233     apr_status_t rv;
5234
5235     /* The Nagle algorithm says that we should delay sending partial
5236      * packets in hopes of getting more data.  We don't want to do
5237      * this; we are not telnet.  There are bad interactions between
5238      * persistent connections and Nagle's algorithm that have very severe
5239      * performance penalties.  (Failing to disable Nagle is not much of a
5240      * problem with simple HTTP.)
5241      */
5242     rv = apr_socket_opt_set(csd, APR_TCP_NODELAY, 1);
5243     if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
5244         /* expected cause is that the client disconnected already,
5245          * hence the debug level
5246          */
5247         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(00139)
5248                       "apr_socket_opt_set(APR_TCP_NODELAY)");
5249     }
5250
5251     /* The core filter requires the timeout mode to be set, which
5252      * incidentally sets the socket to be nonblocking.  If this
5253      * is not initialized correctly, Linux - for example - will
5254      * be initially blocking, while Solaris will be non blocking
5255      * and any initial read will fail.
5256      */
5257     rv = apr_socket_timeout_set(csd, c->base_server->timeout);
5258     if (rv != APR_SUCCESS) {
5259         /* expected cause is that the client disconnected already */
5260         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(00140)
5261                       "apr_socket_timeout_set");
5262     }
5263
5264     net->c = c;
5265     net->in_ctx = NULL;
5266     net->out_ctx = NULL;
5267     net->client_socket = csd;
5268
5269     ap_set_core_module_config(net->c->conn_config, csd);
5270     /* only the master connection talks to the network */
5271     if (c->master == NULL) {
5272         ap_add_input_filter_handle(ap_core_input_filter_handle, net, NULL,
5273                                    net->c);
5274         ap_add_output_filter_handle(ap_core_output_filter_handle, net, NULL,
5275                                     net->c);
5276     }
5277     return DONE;
5278 }
5279
5280 AP_CORE_DECLARE(conn_rec *) ap_create_slave_connection(conn_rec *c)
5281 {
5282     apr_pool_t *pool;
5283     conn_slave_rec *new;
5284     conn_rec *sc = (conn_rec *) apr_palloc(c->pool, sizeof(conn_rec));
5285
5286     apr_pool_create(&pool, c->pool);
5287     apr_pool_tag(pool, "slave_conn");
5288     memcpy(sc, c, sizeof(conn_rec));
5289     sc->slaves = NULL;
5290     sc->master = c;
5291     sc->input_filters = NULL;
5292     sc->output_filters = NULL;
5293     sc->pool = pool;
5294     new = apr_array_push(c->slaves);
5295     new->c = sc;
5296     return sc;
5297 }
5298
5299 AP_DECLARE(int) ap_state_query(int query)
5300 {
5301     switch (query) {
5302     case AP_SQ_MAIN_STATE:
5303         return ap_main_state;
5304     case AP_SQ_RUN_MODE:
5305         return ap_run_mode;
5306     case AP_SQ_CONFIG_GEN:
5307         return ap_config_generation;
5308     default:
5309         return AP_SQ_NOT_SUPPORTED;
5310     }
5311 }
5312
5313 static apr_random_t *rng = NULL;
5314 #if APR_HAS_THREADS
5315 static apr_thread_mutex_t *rng_mutex = NULL;
5316 #endif
5317
5318 static void core_child_init(apr_pool_t *pchild, server_rec *s)
5319 {
5320     apr_proc_t proc;
5321 #if APR_HAS_THREADS
5322     int threaded_mpm;
5323     if (ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded_mpm) == APR_SUCCESS
5324         && threaded_mpm)
5325     {
5326         apr_thread_mutex_create(&rng_mutex, APR_THREAD_MUTEX_DEFAULT, pchild);
5327     }
5328 #endif
5329     /* The MPMs use plain fork() and not apr_proc_fork(), so we have to call
5330      * apr_random_after_fork() manually in the child
5331      */
5332     proc.pid = getpid();
5333     apr_random_after_fork(&proc);
5334 }
5335
5336 static void core_optional_fn_retrieve(void)
5337 {
5338     ap_init_scoreboard(NULL);
5339 }
5340
5341 AP_CORE_DECLARE(void) ap_random_parent_after_fork(void)
5342 {
5343     /*
5344      * To ensure that the RNG state in the parent changes after the fork, we
5345      * pull some data from the RNG and discard it. This ensures that the RNG
5346      * states in the children are different even after the pid wraps around.
5347      * As we only use apr_random for insecure random bytes, pulling 2 bytes
5348      * should be enough.
5349      * XXX: APR should probably have some dedicated API to do this, but it
5350      * XXX: currently doesn't.
5351      */
5352     apr_uint16_t data;
5353     apr_random_insecure_bytes(rng, &data, sizeof(data));
5354 }
5355
5356 AP_CORE_DECLARE(void) ap_init_rng(apr_pool_t *p)
5357 {
5358     unsigned char seed[8];
5359     apr_status_t rv;
5360     rng = apr_random_standard_new(p);
5361     do {
5362         rv = apr_generate_random_bytes(seed, sizeof(seed));
5363         if (rv != APR_SUCCESS)
5364             goto error;
5365         apr_random_add_entropy(rng, seed, sizeof(seed));
5366         rv = apr_random_insecure_ready(rng);
5367     } while (rv == APR_ENOTENOUGHENTROPY);
5368     if (rv == APR_SUCCESS)
5369         return;
5370 error:
5371     ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, APLOGNO(00141)
5372                  "Could not initialize random number generator");
5373     exit(1);
5374 }
5375
5376 AP_DECLARE(void) ap_random_insecure_bytes(void *buf, apr_size_t size)
5377 {
5378 #if APR_HAS_THREADS
5379     if (rng_mutex)
5380         apr_thread_mutex_lock(rng_mutex);
5381 #endif
5382     /* apr_random_insecure_bytes can only fail with APR_ENOTENOUGHENTROPY,
5383      * and we have ruled that out during initialization. Therefore we don't
5384      * need to check the return code.
5385      */
5386     apr_random_insecure_bytes(rng, buf, size);
5387 #if APR_HAS_THREADS
5388     if (rng_mutex)
5389         apr_thread_mutex_unlock(rng_mutex);
5390 #endif
5391 }
5392
5393 /*
5394  * Finding a random number in a range.
5395  *      n' = a + n(b-a+1)/(M+1)
5396  * where:
5397  *      n' = random number in range
5398  *      a  = low end of range
5399  *      b  = high end of range
5400  *      n  = random number of 0..M
5401  *      M  = maxint
5402  * Algorithm 'borrowed' from PHP's rand() function.
5403  */
5404 #define RAND_RANGE(__n, __min, __max, __tmax) \
5405 (__n) = (__min) + (long) ((double) ((__max) - (__min) + 1.0) * ((__n) / ((__tmax) + 1.0)))
5406 AP_DECLARE(apr_uint32_t) ap_random_pick(apr_uint32_t min, apr_uint32_t max)
5407 {
5408     apr_uint32_t number;
5409 #if (!__GNUC__ || __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || \
5410      !__sparc__ || APR_SIZEOF_VOIDP != 8)
5411     /* This triggers a gcc bug on sparc/64bit with gcc < 4.8, PR 52900 */
5412     if (max < 16384) {
5413         apr_uint16_t num16;
5414         ap_random_insecure_bytes(&num16, sizeof(num16));
5415         RAND_RANGE(num16, min, max, APR_UINT16_MAX);
5416         number = num16;
5417     }
5418     else
5419 #endif
5420     {
5421         ap_random_insecure_bytes(&number, sizeof(number));
5422         RAND_RANGE(number, min, max, APR_UINT32_MAX);
5423     }
5424     return number;
5425 }
5426
5427 static apr_status_t core_insert_network_bucket(conn_rec *c,
5428                                                apr_bucket_brigade *bb,
5429                                                apr_socket_t *socket)
5430 {
5431     apr_bucket *e = apr_bucket_socket_create(socket, c->bucket_alloc);
5432     APR_BRIGADE_INSERT_TAIL(bb, e);
5433     return APR_SUCCESS;
5434 }
5435
5436 static apr_status_t core_dirwalk_stat(apr_finfo_t *finfo, request_rec *r,
5437                                       apr_int32_t wanted) 
5438 {
5439     return apr_stat(finfo, r->filename, wanted, r->pool);
5440 }
5441
5442 static void core_dump_config(apr_pool_t *p, server_rec *s)
5443 {
5444     core_server_config *sconf = ap_get_core_module_config(s->module_config);
5445     apr_file_t *out = NULL;
5446     const char *tmp;
5447     const char **defines;
5448     int i;
5449     if (!ap_exists_config_define("DUMP_RUN_CFG"))
5450         return;
5451
5452     apr_file_open_stdout(&out, p);
5453     apr_file_printf(out, "ServerRoot: \"%s\"\n", ap_server_root);
5454     tmp = ap_server_root_relative(p, sconf->ap_document_root);
5455     apr_file_printf(out, "Main DocumentRoot: \"%s\"\n", tmp);
5456     if (s->error_fname[0] != '|' && s->errorlog_provider == NULL)
5457         tmp = ap_server_root_relative(p, s->error_fname);
5458     else
5459         tmp = s->error_fname;
5460     apr_file_printf(out, "Main ErrorLog: \"%s\"\n", tmp);
5461     if (ap_scoreboard_fname) {
5462         tmp = ap_runtime_dir_relative(p, ap_scoreboard_fname);
5463         apr_file_printf(out, "ScoreBoardFile: \"%s\"\n", tmp);
5464     }
5465     ap_dump_mutexes(p, s, out);
5466     ap_mpm_dump_pidfile(p, out);
5467
5468     defines = (const char **)ap_server_config_defines->elts;
5469     for (i = 0; i < ap_server_config_defines->nelts; i++) {
5470         const char *name = defines[i];
5471         const char *val = NULL;
5472         if (server_config_defined_vars)
5473            val = apr_table_get(server_config_defined_vars, name);
5474         if (val)
5475             apr_file_printf(out, "Define: %s=%s\n", name, val);
5476         else
5477             apr_file_printf(out, "Define: %s\n", name);
5478     }
5479 }
5480
5481 static int core_upgrade_handler(request_rec *r)
5482 {
5483     conn_rec *c = r->connection;
5484     const char *upgrade;
5485
5486     if (c->master) {
5487         /* Not possible to perform an HTTP/1.1 upgrade from a slave
5488          * connection. */
5489         return DECLINED;
5490     }
5491     
5492     upgrade = apr_table_get(r->headers_in, "Upgrade");
5493     if (upgrade && *upgrade) {
5494         const char *conn = apr_table_get(r->headers_in, "Connection");
5495         if (ap_find_token(r->pool, conn, "upgrade")) {
5496             apr_array_header_t *offers = NULL;
5497             const char *err;
5498             
5499             err = ap_parse_token_list_strict(r->pool, upgrade, &offers, 0);
5500             if (err) {
5501                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02910)
5502                               "parsing Upgrade header: %s", err);
5503                 return DECLINED;
5504             }
5505             
5506             if (offers && offers->nelts > 0) {
5507                 const char *protocol = ap_select_protocol(c, r, NULL, offers);
5508                 if (protocol && strcmp(protocol, ap_get_protocol(c))) {
5509                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02909)
5510                                   "Upgrade selects '%s'", protocol);
5511                     /* Let the client know what we are upgrading to. */
5512                     apr_table_clear(r->headers_out);
5513                     apr_table_setn(r->headers_out, "Upgrade", protocol);
5514                     apr_table_setn(r->headers_out, "Connection", "Upgrade");
5515                     
5516                     r->status = HTTP_SWITCHING_PROTOCOLS;
5517                     r->status_line = ap_get_status_line(r->status);
5518                     ap_send_interim_response(r, 1);
5519
5520                     ap_switch_protocol(c, r, r->server, protocol);
5521
5522                     /* make sure httpd closes the connection after this */
5523                     c->keepalive = AP_CONN_CLOSE;
5524                     return DONE;
5525                 }
5526             }
5527         }
5528     }
5529     else if (!c->keepalives) {
5530         /* first request on a master connection, if we have protocols other
5531          * than the current one enabled here, announce them to the
5532          * client. If the client is already talking a protocol with requests
5533          * on slave connections, leave it be. */
5534         const apr_array_header_t *upgrades;
5535         ap_get_protocol_upgrades(c, r, NULL, 0, &upgrades);
5536         if (upgrades && upgrades->nelts > 0) {
5537             char *protocols = apr_array_pstrcat(r->pool, upgrades, ',');
5538             apr_table_setn(r->headers_out, "Upgrade", protocols);
5539             apr_table_setn(r->headers_out, "Connection", "Upgrade");
5540         }
5541     }
5542     
5543     return DECLINED;
5544 }
5545
5546 static int core_upgrade_storage(request_rec *r)
5547 {
5548     if ((r->method_number == M_OPTIONS) && r->uri && (r->uri[0] == '*') &&
5549         (r->uri[1] == '\0')) {
5550         return core_upgrade_handler(r);
5551     }
5552     return DECLINED;
5553 }
5554
5555 static void register_hooks(apr_pool_t *p)
5556 {
5557     errorlog_hash = apr_hash_make(p);
5558     ap_register_log_hooks(p);
5559     ap_register_config_hooks(p);
5560     ap_expr_init(p);
5561
5562     /* create_connection and pre_connection should always be hooked
5563      * APR_HOOK_REALLY_LAST by core to give other modules the opportunity
5564      * to install alternate network transports and stop other functions
5565      * from being run.
5566      */
5567     ap_hook_create_connection(core_create_conn, NULL, NULL,
5568                               APR_HOOK_REALLY_LAST);
5569     ap_hook_pre_connection(core_pre_connection, NULL, NULL,
5570                            APR_HOOK_REALLY_LAST);
5571
5572     ap_hook_pre_config(core_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
5573     ap_hook_post_config(core_post_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
5574     ap_hook_check_config(core_check_config,NULL,NULL,APR_HOOK_FIRST);
5575     ap_hook_test_config(core_dump_config,NULL,NULL,APR_HOOK_FIRST);
5576     ap_hook_translate_name(ap_core_translate,NULL,NULL,APR_HOOK_REALLY_LAST);
5577     ap_hook_map_to_storage(core_upgrade_storage,NULL,NULL,APR_HOOK_REALLY_FIRST);
5578     ap_hook_map_to_storage(core_map_to_storage,NULL,NULL,APR_HOOK_REALLY_LAST);
5579     ap_hook_open_logs(ap_open_logs,NULL,NULL,APR_HOOK_REALLY_FIRST);
5580     ap_hook_child_init(core_child_init,NULL,NULL,APR_HOOK_REALLY_FIRST);
5581     ap_hook_child_init(ap_logs_child_init,NULL,NULL,APR_HOOK_MIDDLE);
5582     ap_hook_handler(core_upgrade_handler,NULL,NULL,APR_HOOK_REALLY_FIRST);
5583     ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST);
5584     /* FIXME: I suspect we can eliminate the need for these do_nothings - Ben */
5585     ap_hook_type_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);
5586     ap_hook_fixups(core_override_type,NULL,NULL,APR_HOOK_REALLY_FIRST);
5587     ap_hook_create_request(core_create_req, NULL, NULL, APR_HOOK_MIDDLE);
5588     APR_OPTIONAL_HOOK(proxy, create_req, core_create_proxy_req, NULL, NULL,
5589                       APR_HOOK_MIDDLE);
5590     ap_hook_pre_mpm(ap_create_scoreboard, NULL, NULL, APR_HOOK_MIDDLE);
5591     ap_hook_child_status(ap_core_child_status, NULL, NULL, APR_HOOK_MIDDLE);
5592     ap_hook_insert_network_bucket(core_insert_network_bucket, NULL, NULL,
5593                                   APR_HOOK_REALLY_LAST);
5594     ap_hook_dirwalk_stat(core_dirwalk_stat, NULL, NULL, APR_HOOK_REALLY_LAST);
5595     ap_hook_open_htaccess(ap_open_htaccess, NULL, NULL, APR_HOOK_REALLY_LAST);
5596     ap_hook_optional_fn_retrieve(core_optional_fn_retrieve, NULL, NULL,
5597                                  APR_HOOK_MIDDLE);
5598     ap_hook_output_pending(ap_filter_output_pending, NULL, NULL,
5599             APR_HOOK_MIDDLE);
5600
5601     /* register the core's insert_filter hook and register core-provided
5602      * filters
5603      */
5604     ap_hook_insert_filter(core_insert_filter, NULL, NULL, APR_HOOK_MIDDLE);
5605
5606     ap_core_input_filter_handle =
5607         ap_register_input_filter("CORE_IN", ap_core_input_filter,
5608                                  NULL, AP_FTYPE_NETWORK);
5609     ap_content_length_filter_handle =
5610         ap_register_output_filter("CONTENT_LENGTH", ap_content_length_filter,
5611                                   NULL, AP_FTYPE_PROTOCOL);
5612     ap_core_output_filter_handle =
5613         ap_register_output_filter("CORE", ap_core_output_filter,
5614                                   NULL, AP_FTYPE_NETWORK);
5615     ap_request_core_filter_handle =
5616         ap_register_output_filter("REQ_CORE", ap_request_core_filter,
5617                                   NULL, AP_FTYPE_TRANSCODE);
5618     ap_subreq_core_filter_handle =
5619         ap_register_output_filter("SUBREQ_CORE", ap_sub_req_output_filter,
5620                                   NULL, AP_FTYPE_CONTENT_SET);
5621     ap_old_write_func =
5622         ap_register_output_filter("OLD_WRITE", ap_old_write_filter,
5623                                   NULL, AP_FTYPE_RESOURCE - 10);
5624 }
5625
5626 AP_DECLARE_MODULE(core) = {
5627     MPM20_MODULE_STUFF,
5628     AP_PLATFORM_REWRITE_ARGS_HOOK, /* hook to run before apache parses args */
5629     create_core_dir_config,       /* create per-directory config structure */
5630     merge_core_dir_configs,       /* merge per-directory config structures */
5631     create_core_server_config,    /* create per-server config structure */
5632     merge_core_server_configs,    /* merge per-server config structures */
5633     core_cmds,                    /* command apr_table_t */
5634     register_hooks                /* register hooks */
5635 };
5636