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