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