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