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