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