]> granicus.if.org Git - apache/blob - modules/http/http_core.c
Fix the core_output_filter to work with FLUSH buckets. With this change,
[apache] / modules / http / http_core.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000 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 #define CORE_PRIVATE
60 #include "ap_config.h"
61 #include "apr_strings.h"
62 #include "apr_lib.h"
63 #include "httpd.h"
64 #include "http_config.h"
65 #include "http_core.h"
66 #include "http_protocol.h"      /* For index_of_response().  Grump. */
67 #include "http_request.h"
68 #include "http_vhost.h"
69 #include "http_main.h"          /* For the default_handler below... */
70 #include "http_log.h"
71 #include "rfc1413.h"
72 #include "util_md5.h"
73 #include "apr_fnmatch.h"
74 #include "http_connection.h"
75 #include "ap_buckets.h"
76 #include "util_filter.h"
77 #include "util_ebcdic.h"
78 #include "mpm.h"
79 #ifdef HAVE_NETDB_H
80 #include <netdb.h>
81 #endif
82 #ifdef HAVE_SYS_SOCKET_H
83 #include <sys/socket.h>
84 #endif
85 #ifdef HAVE_ARPA_INET_H
86 #include <arpa/inet.h>
87 #endif
88 #ifdef HAVE_STRINGS_H
89 #include <strings.h>
90 #endif
91
92 /* Make sure we don't write less than 4096 bytes at any one time.
93  */
94 #define MIN_SIZE_TO_WRITE  9000
95
96 /* Allow Apache to use ap_mmap */
97 #ifdef AP_USE_MMAP_FILES
98 #include "apr_mmap.h"
99
100 /* mmap support for static files based on ideas from John Heidemann's
101  * patch against 1.0.5.  See
102  * <http://www.isi.edu/~johnh/SOFTWARE/APACHE/index.html>.
103  */
104
105 /* Files have to be at least this big before they're mmap()d.  This is to deal
106  * with systems where the expense of doing an mmap() and an munmap() outweighs
107  * the benefit for small files.  It shouldn't be set lower than 1.
108  */
109 #ifndef MMAP_THRESHOLD
110 #  ifdef SUNOS4
111 #  define MMAP_THRESHOLD                (8*1024)
112 #  else
113 #  define MMAP_THRESHOLD                1
114 #  endif /* SUNOS4 */
115 #endif /* MMAP_THRESHOLD */
116 #ifndef MMAP_LIMIT
117 #define MMAP_LIMIT              (4*1024*1024)
118 #endif
119 #endif /* AP_USE_MMAP_FILES */
120
121 /* LimitXMLRequestBody handling */
122 #define AP_LIMIT_UNSET                  ((long) -1)
123 #define AP_DEFAULT_LIMIT_XML_BODY       ((size_t)1000000)
124
125 /* Server core module... This module provides support for really basic
126  * server operations, including options and commands which control the
127  * operation of other modules.  Consider this the bureaucracy module.
128  *
129  * The core module also defines handlers, etc., do handle just enough
130  * to allow a server with the core module ONLY to actually serve documents
131  * (though it slaps DefaultType on all of 'em); this was useful in testing,
132  * but may not be worth preserving.
133  *
134  * This file could almost be mod_core.c, except for the stuff which affects
135  * the http_conf_globals.
136  */
137
138 static void *create_core_dir_config(apr_pool_t *a, char *dir)
139 {
140     core_dir_config *conf;
141
142     conf = (core_dir_config *)apr_pcalloc(a, sizeof(core_dir_config));
143     if (!dir || dir[strlen(dir) - 1] == '/') {
144         conf->d = dir;
145     }
146     else if (strncmp(dir, "proxy:", 6) == 0) {
147         conf->d = apr_pstrdup(a, dir);
148     }
149     else {
150         conf->d = apr_pstrcat(a, dir, "/", NULL);
151     }
152     conf->d_is_fnmatch = conf->d ? (apr_is_fnmatch(conf->d) != 0) : 0;
153     conf->d_components = conf->d ? ap_count_dirs(conf->d) : 0;
154
155     conf->opts = dir ? OPT_UNSET : OPT_UNSET|OPT_ALL;
156     conf->opts_add = conf->opts_remove = OPT_NONE;
157     conf->override = dir ? OR_UNSET : OR_UNSET|OR_ALL;
158
159     conf->content_md5 = 2;
160
161     conf->use_canonical_name = USE_CANONICAL_NAME_UNSET;
162
163     conf->hostname_lookups = HOSTNAME_LOOKUP_UNSET;
164     conf->do_rfc1413 = DEFAULT_RFC1413 | 2; /* set bit 1 to indicate default */
165     conf->satisfy = SATISFY_NOSPEC;
166
167 #ifdef RLIMIT_CPU
168     conf->limit_cpu = NULL;
169 #endif
170 #if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
171     conf->limit_mem = NULL;
172 #endif
173 #ifdef RLIMIT_NPROC
174     conf->limit_nproc = NULL;
175 #endif
176
177     conf->limit_req_body = 0;
178     conf->limit_xml_body = AP_LIMIT_UNSET;
179     conf->sec = apr_make_array(a, 2, sizeof(void *));
180 #ifdef WIN32
181     conf->script_interpreter_source = INTERPRETER_SOURCE_UNSET;
182 #endif
183
184     conf->server_signature = srv_sig_unset;
185
186     conf->add_default_charset = ADD_DEFAULT_CHARSET_UNSET;
187     conf->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
188
189     conf->output_filters = apr_make_array(a, 2, sizeof(void *));
190     conf->input_filters = apr_make_array(a, 2, sizeof(void *));
191     return (void *)conf;
192 }
193
194 static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv)
195 {
196     core_dir_config *base = (core_dir_config *)basev;
197     core_dir_config *new = (core_dir_config *)newv;
198     core_dir_config *conf;
199     int i;
200   
201     conf = (core_dir_config *)apr_palloc(a, sizeof(core_dir_config));
202     memcpy((char *)conf, (const char *)base, sizeof(core_dir_config));
203     if (base->response_code_strings) {
204         conf->response_code_strings =
205             apr_palloc(a, sizeof(*conf->response_code_strings)
206                       * RESPONSE_CODES);
207         memcpy(conf->response_code_strings, base->response_code_strings,
208                sizeof(*conf->response_code_strings) * RESPONSE_CODES);
209     }
210     
211     conf->d = new->d;
212     conf->d_is_fnmatch = new->d_is_fnmatch;
213     conf->d_components = new->d_components;
214     conf->r = new->r;
215     
216     if (new->opts & OPT_UNSET) {
217         /* there was no explicit setting of new->opts, so we merge
218          * preserve the invariant (opts_add & opts_remove) == 0
219          */
220         conf->opts_add = (conf->opts_add & ~new->opts_remove) | new->opts_add;
221         conf->opts_remove = (conf->opts_remove & ~new->opts_add)
222                             | new->opts_remove;
223         conf->opts = (conf->opts & ~conf->opts_remove) | conf->opts_add;
224         if ((base->opts & OPT_INCNOEXEC) && (new->opts & OPT_INCLUDES)) {
225             conf->opts = (conf->opts & ~OPT_INCNOEXEC) | OPT_INCLUDES;
226         }
227     }
228     else {
229         /* otherwise we just copy, because an explicit opts setting
230          * overrides all earlier +/- modifiers
231          */
232         conf->opts = new->opts;
233         conf->opts_add = new->opts_add;
234         conf->opts_remove = new->opts_remove;
235     }
236
237     if (!(new->override & OR_UNSET)) {
238         conf->override = new->override;
239     }
240     if (new->ap_default_type) {
241         conf->ap_default_type = new->ap_default_type;
242     }
243     
244     if (new->ap_auth_type) {
245         conf->ap_auth_type = new->ap_auth_type;
246     }
247     if (new->ap_auth_name) {
248         conf->ap_auth_name = new->ap_auth_name;
249     }
250     if (new->ap_requires) {
251         conf->ap_requires = new->ap_requires;
252     }
253
254     if (new->response_code_strings) {
255         if (conf->response_code_strings == NULL) {
256             conf->response_code_strings = apr_palloc(a,
257                 sizeof(*conf->response_code_strings) * RESPONSE_CODES);
258             memcpy(conf->response_code_strings, new->response_code_strings,
259                    sizeof(*conf->response_code_strings) * RESPONSE_CODES);
260         }
261         else {
262             for (i = 0; i < RESPONSE_CODES; ++i) {
263                 if (new->response_code_strings[i] != NULL) {
264                     conf->response_code_strings[i]
265                         = new->response_code_strings[i];
266                 }
267             }
268         }
269     }
270     if (new->hostname_lookups != HOSTNAME_LOOKUP_UNSET) {
271         conf->hostname_lookups = new->hostname_lookups;
272     }
273     if ((new->do_rfc1413 & 2) == 0) {
274         conf->do_rfc1413 = new->do_rfc1413;
275     }
276     if ((new->content_md5 & 2) == 0) {
277         conf->content_md5 = new->content_md5;
278     }
279     if (new->use_canonical_name != USE_CANONICAL_NAME_UNSET) {
280         conf->use_canonical_name = new->use_canonical_name;
281     }
282
283 #ifdef RLIMIT_CPU
284     if (new->limit_cpu) {
285         conf->limit_cpu = new->limit_cpu;
286     }
287 #endif
288 #if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
289     if (new->limit_mem) {
290         conf->limit_mem = new->limit_mem;
291     }
292 #endif
293 #ifdef RLIMIT_NPROC
294     if (new->limit_nproc) {
295         conf->limit_nproc = new->limit_nproc;
296     }
297 #endif
298
299     if (new->limit_req_body) {
300         conf->limit_req_body = new->limit_req_body;
301     }
302
303     if (new->limit_xml_body != AP_LIMIT_UNSET)
304         conf->limit_xml_body = new->limit_xml_body;
305     else
306         conf->limit_xml_body = base->limit_xml_body;
307
308     conf->sec = apr_append_arrays(a, base->sec, new->sec);
309
310     if (new->satisfy != SATISFY_NOSPEC) {
311         conf->satisfy = new->satisfy;
312     }
313
314 #ifdef WIN32
315     if (new->script_interpreter_source != INTERPRETER_SOURCE_UNSET) {
316         conf->script_interpreter_source = new->script_interpreter_source;
317     }
318 #endif
319
320     if (new->server_signature != srv_sig_unset) {
321         conf->server_signature = new->server_signature;
322     }
323
324     if (new->add_default_charset != ADD_DEFAULT_CHARSET_UNSET) {
325         conf->add_default_charset = new->add_default_charset;
326         if (new->add_default_charset_name) {
327             conf->add_default_charset_name = new->add_default_charset_name;
328         }
329     }
330     conf->output_filters = apr_append_arrays(a, base->output_filters, 
331                                              new->output_filters);
332     conf->input_filters = apr_append_arrays(a, base->input_filters,
333                                             new->input_filters);
334
335     return (void*)conf;
336 }
337
338 static void *create_core_server_config(apr_pool_t *a, server_rec *s)
339 {
340     core_server_config *conf;
341     int is_virtual = s->is_virtual;
342   
343     conf = (core_server_config *)apr_pcalloc(a, sizeof(core_server_config));
344 #ifdef GPROF
345     conf->gprof_dir = NULL;
346 #endif
347     conf->access_name = is_virtual ? NULL : DEFAULT_ACCESS_FNAME;
348     conf->ap_document_root = is_virtual ? NULL : DOCUMENT_LOCATION;
349     conf->sec = apr_make_array(a, 40, sizeof(void *));
350     conf->sec_url = apr_make_array(a, 40, sizeof(void *));
351     
352     return (void *)conf;
353 }
354
355 static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
356 {
357     core_server_config *base = (core_server_config *)basev;
358     core_server_config *virt = (core_server_config *)virtv;
359     core_server_config *conf;
360
361     conf = (core_server_config *)apr_pcalloc(p, sizeof(core_server_config));
362     *conf = *virt;
363     if (!conf->access_name) {
364         conf->access_name = base->access_name;
365     }
366     if (!conf->ap_document_root) {
367         conf->ap_document_root = base->ap_document_root;
368     }
369     conf->sec = apr_append_arrays(p, base->sec, virt->sec);
370     conf->sec_url = apr_append_arrays(p, base->sec_url, virt->sec_url);
371
372     return conf;
373 }
374
375 /* Add per-directory configuration entry (for <directory> section);
376  * these are part of the core server config.
377  */
378
379 AP_CORE_DECLARE(void) ap_add_per_dir_conf(server_rec *s, void *dir_config)
380 {
381     core_server_config *sconf = ap_get_module_config(s->module_config,
382                                                      &core_module);
383     void **new_space = (void **)apr_push_array(sconf->sec);
384     
385     *new_space = dir_config;
386 }
387
388 AP_CORE_DECLARE(void) ap_add_per_url_conf(server_rec *s, void *url_config)
389 {
390     core_server_config *sconf = ap_get_module_config(s->module_config,
391                                                      &core_module);
392     void **new_space = (void **)apr_push_array(sconf->sec_url);
393     
394     *new_space = url_config;
395 }
396
397 AP_CORE_DECLARE(void) ap_add_file_conf(core_dir_config *conf, void *url_config)
398 {
399     void **new_space = (void **)apr_push_array(conf->sec);
400     
401     *new_space = url_config;
402 }
403
404 /* core_reorder_directories reorders the directory sections such that the
405  * 1-component sections come first, then the 2-component, and so on, finally
406  * followed by the "special" sections.  A section is "special" if it's a regex,
407  * or if it doesn't start with / -- consider proxy: matching.  All movements
408  * are in-order to preserve the ordering of the sections from the config files.
409  * See directory_walk().
410  */
411
412 #if defined(HAVE_DRIVE_LETTERS)
413 #define IS_SPECIAL(entry_core)  \
414     ((entry_core)->r != NULL \
415         || ((entry_core)->d[0] != '/' && (entry_core)->d[1] != ':'))
416 #elif defined(NETWARE)
417 /* XXX: Fairly certain this is correct... '/' must prefix the path
418  *      or else in the case xyz:/ or abc/xyz:/, '/' must follow the ':'.
419  *      If there is no leading '/' or embedded ':/', then we are special.
420  */
421 #define IS_SPECIAL(entry_core)  \
422     ((entry_core)->r != NULL \
423         || ((entry_core)->d[0] != '/' \
424             && strchr((entry_core)->d, ':') \
425             && *(strchr((entry_core)->d, ':') + 1) != '/'))
426 #else
427 #define IS_SPECIAL(entry_core)  \
428     ((entry_core)->r != NULL || (entry_core)->d[0] != '/')
429 #endif
430
431 /* We need to do a stable sort, qsort isn't stable.  So to make it stable
432  * we'll be maintaining the original index into the list, and using it
433  * as the minor key during sorting.  The major key is the number of
434  * components (where a "special" section has infinite components).
435  */
436 struct reorder_sort_rec {
437     void *elt;
438     int orig_index;
439 };
440
441 static int reorder_sorter(const void *va, const void *vb)
442 {
443     const struct reorder_sort_rec *a = va;
444     const struct reorder_sort_rec *b = vb;
445     core_dir_config *core_a;
446     core_dir_config *core_b;
447
448     core_a = (core_dir_config *)ap_get_module_config(a->elt, &core_module);
449     core_b = (core_dir_config *)ap_get_module_config(b->elt, &core_module);
450     if (IS_SPECIAL(core_a)) {
451         if (!IS_SPECIAL(core_b)) {
452             return 1;
453         }
454     }
455     else if (IS_SPECIAL(core_b)) {
456         return -1;
457     }
458     else {
459         /* we know they're both not special */
460         if (core_a->d_components < core_b->d_components) {
461             return -1;
462         }
463         else if (core_a->d_components > core_b->d_components) {
464             return 1;
465         }
466     }
467     /* Either they're both special, or they're both not special and have the
468      * same number of components.  In any event, we now have to compare
469      * the minor key. */
470     return a->orig_index - b->orig_index;
471 }
472
473 void ap_core_reorder_directories(apr_pool_t *p, server_rec *s)
474 {
475     core_server_config *sconf;
476     apr_array_header_t *sec;
477     struct reorder_sort_rec *sortbin;
478     int nelts;
479     void **elts;
480     int i;
481     apr_pool_t *tmp;
482
483     sconf = ap_get_module_config(s->module_config, &core_module);
484     sec = sconf->sec;
485     nelts = sec->nelts;
486     elts = (void **)sec->elts;
487
488     /* we have to allocate tmp space to do a stable sort */
489     apr_create_pool(&tmp, p);
490     sortbin = apr_palloc(tmp, sec->nelts * sizeof(*sortbin));
491     for (i = 0; i < nelts; ++i) {
492         sortbin[i].orig_index = i;
493         sortbin[i].elt = elts[i];
494     }
495
496     qsort(sortbin, nelts, sizeof(*sortbin), reorder_sorter);
497
498     /* and now copy back to the original array */
499     for (i = 0; i < nelts; ++i) {
500       elts[i] = sortbin[i].elt;
501     }
502
503     apr_destroy_pool(tmp);
504 }
505
506 /*****************************************************************
507  *
508  * There are some elements of the core config structures in which
509  * other modules have a legitimate interest (this is ugly, but necessary
510  * to preserve NCSA back-compatibility).  So, we have a bunch of accessors
511  * here...
512  */
513
514 AP_DECLARE(int) ap_allow_options(request_rec *r)
515 {
516     core_dir_config *conf = 
517       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module); 
518
519     return conf->opts; 
520
521
522 AP_DECLARE(int) ap_allow_overrides(request_rec *r) 
523
524     core_dir_config *conf;
525     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
526                                                    &core_module); 
527
528     return conf->override; 
529
530
531 AP_DECLARE(const char *) ap_auth_type(request_rec *r)
532 {
533     core_dir_config *conf;
534
535     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
536                                                    &core_module); 
537     return conf->ap_auth_type;
538 }
539
540 AP_DECLARE(const char *) ap_auth_name(request_rec *r)
541 {
542     core_dir_config *conf;
543
544     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
545                                                    &core_module); 
546     return conf->ap_auth_name;
547 }
548
549 AP_DECLARE(const char *) ap_default_type(request_rec *r)
550 {
551     core_dir_config *conf;
552
553     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
554                                                    &core_module); 
555     return conf->ap_default_type 
556                ? conf->ap_default_type 
557                : DEFAULT_CONTENT_TYPE;
558 }
559
560 AP_DECLARE(const char *) ap_document_root(request_rec *r) /* Don't use this! */
561 {
562     core_server_config *conf;
563
564     conf = (core_server_config *)ap_get_module_config(r->server->module_config,
565                                                       &core_module); 
566     return conf->ap_document_root;
567 }
568
569 AP_DECLARE(const apr_array_header_t *) ap_requires(request_rec *r)
570 {
571     core_dir_config *conf;
572
573     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
574                                                    &core_module); 
575     return conf->ap_requires;
576 }
577
578 AP_DECLARE(int) ap_satisfies(request_rec *r)
579 {
580     core_dir_config *conf;
581
582     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
583                                                    &core_module);
584
585     return conf->satisfy;
586 }
587
588 /* Should probably just get rid of this... the only code that cares is
589  * part of the core anyway (and in fact, it isn't publicised to other
590  * modules).
591  */
592
593 char *ap_response_code_string(request_rec *r, int error_index)
594 {
595     core_dir_config *conf;
596
597     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
598                                                    &core_module); 
599
600     if (conf->response_code_strings == NULL) {
601         return NULL;
602     }
603     return conf->response_code_strings[error_index];
604 }
605
606
607 /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
608 static apr_inline void do_double_reverse (conn_rec *conn)
609 {
610     struct hostent *hptr;
611
612     if (conn->double_reverse) {
613         /* already done */
614         return;
615     }
616     if (conn->remote_host == NULL || conn->remote_host[0] == '\0') {
617         /* single reverse failed, so don't bother */
618         conn->double_reverse = -1;
619         return;
620     }
621     hptr = gethostbyname(conn->remote_host);   
622     if (hptr) {          
623         char **haddr;
624
625         for (haddr = hptr->h_addr_list; *haddr; haddr++) {
626             if (((struct in_addr *)(*haddr))->s_addr
627                 == conn->remote_addr.sin_addr.s_addr) {
628                 conn->double_reverse = 1;
629                 return;
630             }
631         }
632     }
633     conn->double_reverse = -1;
634 }
635
636 AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config,
637                                             int type)
638 {
639     struct in_addr *iaddr;
640     struct hostent *hptr;
641     int hostname_lookups;
642
643     /* If we haven't checked the host name, and we want to */
644     if (dir_config) {
645         hostname_lookups =
646             ((core_dir_config *)ap_get_module_config(dir_config, &core_module))
647                 ->hostname_lookups;
648         if (hostname_lookups == HOSTNAME_LOOKUP_UNSET) {
649             hostname_lookups = HOSTNAME_LOOKUP_OFF;
650         }
651     }
652     else {
653         /* the default */
654         hostname_lookups = HOSTNAME_LOOKUP_OFF;
655     }
656
657     if (type != REMOTE_NOLOOKUP
658         && conn->remote_host == NULL
659         && (type == REMOTE_DOUBLE_REV
660             || hostname_lookups != HOSTNAME_LOOKUP_OFF)) {
661         iaddr = &(conn->remote_addr.sin_addr);
662         hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET);
663         if (hptr != NULL) {
664             conn->remote_host = apr_pstrdup(conn->pool, (void *)hptr->h_name);
665             ap_str_tolower(conn->remote_host);
666            
667             if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) {
668                 do_double_reverse(conn);
669                 if (conn->double_reverse != 1) {
670                     conn->remote_host = NULL;
671                 }
672             }
673         }
674         /* if failed, set it to the NULL string to indicate error */
675         if (conn->remote_host == NULL) {
676             conn->remote_host = "";
677         }
678     }
679     if (type == REMOTE_DOUBLE_REV) {
680         do_double_reverse(conn);
681         if (conn->double_reverse == -1) {
682             return NULL;
683         }
684     }
685
686 /*
687  * Return the desired information; either the remote DNS name, if found,
688  * or either NULL (if the hostname was requested) or the IP address
689  * (if any identifier was requested).
690  */
691     if (conn->remote_host != NULL && conn->remote_host[0] != '\0') {
692         return conn->remote_host;
693     }
694     else {
695         if (type == REMOTE_HOST || type == REMOTE_DOUBLE_REV) {
696             return NULL;
697         }
698         else {
699             return conn->remote_ip;
700         }
701     }
702 }
703
704 AP_DECLARE(const char *) ap_get_remote_logname(request_rec *r)
705 {
706     core_dir_config *dir_conf;
707
708     if (r->connection->remote_logname != NULL) {
709         return r->connection->remote_logname;
710     }
711
712 /* If we haven't checked the identity, and we want to */
713     dir_conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
714                                                        &core_module);
715
716     if (dir_conf->do_rfc1413 & 1) {
717         return ap_rfc1413(r->connection, r->server);
718     }
719     else {
720         return NULL;
721     }
722 }
723
724 /* There are two options regarding what the "name" of a server is.  The
725  * "canonical" name as defined by ServerName and Port, or the "client's
726  * name" as supplied by a possible Host: header or full URI.  We never
727  * trust the port passed in the client's headers, we always use the
728  * port of the actual socket.
729  *
730  * The DNS option to UseCanonicalName causes this routine to do a
731  * reverse lookup on the local IP address of the connectiona and use
732  * that for the ServerName. This makes its value more reliable while
733  * at the same time allowing Demon's magic virtual hosting to work.
734  * The assumption is that DNS lookups are sufficiently quick...
735  * -- fanf 1998-10-03
736  */
737 AP_DECLARE(const char *) ap_get_server_name(request_rec *r)
738 {
739     conn_rec *conn = r->connection;
740     core_dir_config *d;
741
742     d = (core_dir_config *)ap_get_module_config(r->per_dir_config,
743                                                 &core_module);
744
745     if (d->use_canonical_name == USE_CANONICAL_NAME_OFF) {
746         return r->hostname ? r->hostname : r->server->server_hostname;
747     }
748     if (d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
749         if (conn->local_host == NULL) {
750             struct in_addr *iaddr;
751             struct hostent *hptr;
752             iaddr = &(conn->local_addr.sin_addr);
753             hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr),
754                                  AF_INET);
755             if (hptr != NULL) {
756                 conn->local_host = apr_pstrdup(conn->pool,
757                                               (void *)hptr->h_name);
758                 ap_str_tolower(conn->local_host);
759             }
760             else {
761                 conn->local_host = apr_pstrdup(conn->pool,
762                                               r->server->server_hostname);
763             }
764         }
765         return conn->local_host;
766     }
767     /* default */
768     return r->server->server_hostname;
769 }
770
771 AP_DECLARE(unsigned) ap_get_server_port(const request_rec *r)
772 {
773     unsigned port;
774     core_dir_config *d =
775       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
776     
777     port = r->server->port ? r->server->port : ap_default_port(r);
778
779     if (d->use_canonical_name == USE_CANONICAL_NAME_OFF
780         || d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
781         return r->hostname ? ntohs(r->connection->local_addr.sin_port)
782                            : port;
783     }
784     /* default */
785     return port;
786 }
787
788 AP_DECLARE(char *) ap_construct_url(apr_pool_t *p, const char *uri,
789                                     request_rec *r)
790 {
791     unsigned port = ap_get_server_port(r);
792     const char *host = ap_get_server_name(r);
793
794     if (ap_is_default_port(port, r)) {
795         return apr_pstrcat(p, ap_http_method(r), "://", host, uri, NULL);
796     }
797     return apr_psprintf(p, "%s://%s:%u%s", ap_http_method(r), host, port, uri);
798 }
799
800 AP_DECLARE(unsigned long) ap_get_limit_req_body(const request_rec *r)
801 {
802     core_dir_config *d =
803       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
804     
805     return d->limit_req_body;
806 }
807
808 #ifdef WIN32
809 static apr_status_t get_win32_registry_default_value(apr_pool_t *p, HKEY hkey,
810                                                      char* relativepath, 
811                                                      char **value)
812 {
813     HKEY hkeyOpen;
814     DWORD type;
815     DWORD size = 0;
816     DWORD result = RegOpenKeyEx(hkey, relativepath, 0, 
817                                 KEY_QUERY_VALUE, &hkeyOpen);
818     
819     if (result != ERROR_SUCCESS) 
820         return APR_FROM_OS_ERROR(result);
821
822     /* Read to NULL buffer to determine value size */
823     result = RegQueryValueEx(hkeyOpen, "", 0, &type, NULL, &size);
824     
825    if (result == ERROR_SUCCESS) {
826         if ((size < 2) || (type != REG_SZ && type != REG_EXPAND_SZ)) {
827             result = ERROR_INVALID_PARAMETER;
828         }
829         else {
830             *value = apr_palloc(p, size);
831             /* Read value based on size query above */
832             result = RegQueryValueEx(hkeyOpen, "", 0, &type, *value, &size);
833         }
834     }
835
836     /* TODO: This might look fine, but we need to provide some warning
837      * somewhere that some environment variables may -not- be translated,
838      * seeing as we may have chopped the environment table down somewhat.
839      */
840     if ((result == ERROR_SUCCESS) && (type == REG_EXPAND_SZ)) 
841     {
842         char *tmp = *value;
843         size = ExpandEnvironmentStrings(tmp, *value, 0);
844         if (size) {
845             *value = apr_palloc(p, size);
846             size = ExpandEnvironmentStrings(tmp, *value, size);
847         }
848     }
849
850     RegCloseKey(hkeyOpen);
851     return APR_FROM_OS_ERROR(result);
852 }
853
854 static char* get_interpreter_from_win32_registry(apr_pool_t *p, const char* ext,
855                                                  char** arguments, int strict)
856 {
857     char execcgi_path[] = "SHELL\\EXECCGI\\COMMAND";
858     char execopen_path[] = "SHELL\\OPEN\\COMMAND";
859     char typeName[MAX_PATH];
860     int cmdOfName = FALSE;
861     HKEY hkeyName;
862     HKEY hkeyType;
863     DWORD type;
864     int size;
865     int result;
866     char *buffer;
867     char *s;
868     
869     if (!ext)
870         return NULL;
871     /* 
872      * Future optimization:
873      * When the registry is successfully searched, store the strings for
874      * interpreter and arguments in an ext hash to speed up subsequent look-ups
875      */
876
877     /* Open the key associated with the script filetype extension */
878     result = RegOpenKeyEx(HKEY_CLASSES_ROOT, ext, 0, KEY_QUERY_VALUE, 
879                           &hkeyType);
880
881     if (result != ERROR_SUCCESS) 
882         return NULL;
883
884     /* Retrieve the name of the script filetype extension */
885     size = sizeof(typeName);
886     result = RegQueryValueEx(hkeyType, "", NULL, &type, typeName, &size);
887     
888     if (result == ERROR_SUCCESS && type == REG_SZ && typeName[0]) {
889         /* Open the key associated with the script filetype extension */
890         result = RegOpenKeyEx(HKEY_CLASSES_ROOT, typeName, 0, 
891                               KEY_QUERY_VALUE, &hkeyName);
892
893         if (result == ERROR_SUCCESS)
894             cmdOfName = TRUE;
895     }
896
897     /* Open the key for the script command path by:
898      * 
899      *   1) the 'named' filetype key for ExecCGI/Command
900      *   2) the extension's type key for ExecCGI/Command
901      *
902      * and if the strict arg is false, then continue trying:
903      *
904      *   3) the 'named' filetype key for Open/Command
905      *   4) the extension's type key for Open/Command
906      */
907
908     if (cmdOfName) {
909         result = get_win32_registry_default_value(p, hkeyName, 
910                                                   execcgi_path, &buffer);
911     }
912
913     if (!cmdOfName || (result != ERROR_SUCCESS)) {
914         result = get_win32_registry_default_value(p, hkeyType, 
915                                                   execcgi_path, &buffer);
916     }
917
918     if (!strict && cmdOfName && (result != ERROR_SUCCESS)) {
919         result = get_win32_registry_default_value(p, hkeyName, 
920                                                   execopen_path, &buffer);
921     }
922
923     if (!strict && (result != ERROR_SUCCESS)) {
924         result = get_win32_registry_default_value(p, hkeyType, 
925                                                   execopen_path, &buffer);
926     }
927
928     if (cmdOfName)
929         RegCloseKey(hkeyName);
930
931     RegCloseKey(hkeyType);
932
933     if (result != ERROR_SUCCESS)
934         return NULL;
935
936     /*
937      * The canonical way shell command entries are entered in the Win32 
938      * registry is as follows:
939      *   shell [options] "%1" [args]
940      * where
941      *   shell - full path name to interpreter or shell to run.
942      *           E.g., c:\usr\local\ntreskit\perl\bin\perl.exe
943      *   options - optional switches
944      *              E.g., \C
945      *   "%1" - Place holder for file to run the shell against. 
946      *          Typically quoted.
947      *   options - additional arguments
948      *              E.g., /silent
949      *
950      * If we find a %1 or a quoted %1, lop off the remainder to arguments. 
951      */
952     if (buffer && *buffer) {
953         if ((s = strstr(buffer, "\"%1")))
954         {
955             *s = '\0';
956             *arguments = s + 4;
957         }
958         else if ((s = strstr(buffer, "%1"))) 
959         {
960             *s = '\0';
961             *arguments = buffer + 2;
962         }
963         else
964             *arguments = strchr(buffer, '\0');
965         while (**arguments && isspace(**arguments))
966             ++*arguments;
967     }
968
969     return buffer;
970 }
971
972 AP_DECLARE (file_type_e) ap_get_win32_interpreter(const  request_rec *r, 
973                                                   char** interpreter,
974                                                   char** arguments)
975 {
976     HANDLE hFile;
977     DWORD nBytesRead;
978     BOOLEAN bResult;
979     char buffer[1024];
980     core_dir_config *d;
981     int i;
982     file_type_e fileType = eFileTypeUNKNOWN;
983     char *ext = NULL;
984     char *exename = NULL;
985
986     d = (core_dir_config *)ap_get_module_config(r->per_dir_config, 
987                                                 &core_module);
988
989     /* Find the file extension */
990     exename = strrchr(r->filename, '/');
991     if (!exename) {
992         exename = strrchr(r->filename, '\\');
993     }
994     if (!exename) {
995         exename = r->filename;
996     }
997     else {
998         exename++;
999     }
1000     ext = strrchr(exename, '.');
1001
1002     if (ext && (!strcasecmp(ext,".bat") || !strcasecmp(ext,".cmd"))) 
1003     {
1004         char *comspec = getenv("COMSPEC");
1005         if (comspec) {
1006             *interpreter = apr_pstrcat(r->pool, "\"", comspec, "\" /c ", NULL);
1007             return eFileTypeSCRIPT;
1008         }
1009         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r->server,
1010          "Failed to start a '%s' file as a script." APR_EOL_STR
1011          "\tCOMSPEC variable is missing from the environment.", ext);
1012         return eFileTypeUNKNOWN;
1013     }
1014
1015     /* If the file has an extension and it is not .com and not .exe and
1016      * we've been instructed to search the registry, then do it!
1017      */
1018     if (ext && strcasecmp(ext,".exe") && strcasecmp(ext,".com") &&
1019         (d->script_interpreter_source == INTERPRETER_SOURCE_REGISTRY ||
1020          d->script_interpreter_source == INTERPRETER_SOURCE_REGISTRY_STRICT)) {
1021          /* Check the registry */
1022         int strict = (d->script_interpreter_source 
1023                             == INTERPRETER_SOURCE_REGISTRY_STRICT);
1024         *interpreter = get_interpreter_from_win32_registry(r->pool, ext, 
1025                                                            arguments, strict);
1026         if (*interpreter)
1027             return eFileTypeSCRIPT;
1028         else if (d->script_interpreter_source == INTERPRETER_SOURCE_REGISTRY_STRICT) {
1029             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r->server,
1030              "ScriptInterpreterSource config directive set to \"registry-strict\"." APR_EOL_STR
1031              "\tInterpreter not found for files of type '%s'.", ext);
1032              return eFileTypeUNKNOWN;
1033         }
1034         else
1035         {
1036             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r->server,
1037              "ScriptInterpreterSource config directive set to \"registry\"." APR_EOL_STR
1038              "\tInterpreter not found for files of type '%s', "
1039              "trying \"script\" method...", ext);
1040         }
1041     }        
1042
1043     /* Need to peek into the file figure out what it really is... */
1044     hFile = CreateFile(r->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
1045                        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1046     if (hFile == INVALID_HANDLE_VALUE) {
1047         return eFileTypeUNKNOWN;
1048     }
1049     bResult = ReadFile(hFile, (void*) &buffer, sizeof(buffer) - 1, 
1050                        &nBytesRead, NULL);
1051     if (!bResult || (nBytesRead == 0)) {
1052         ap_log_rerror(APLOG_MARK, APLOG_ERR, GetLastError(), r,
1053                       "ReadFile(%s) failed", r->filename);
1054         CloseHandle(hFile);
1055         return eFileTypeUNKNOWN;
1056     }
1057     CloseHandle(hFile);
1058     buffer[nBytesRead] = '\0';
1059
1060     /* Script or executable, that is the question... */
1061     if ((buffer[0] == '#') && (buffer[1] == '!')) {
1062         /* Assuming file is a script since it starts with a shebang */
1063         fileType = eFileTypeSCRIPT;
1064         for (i = 2; i < sizeof(buffer); i++) {
1065             if ((buffer[i] == '\r')
1066                 || (buffer[i] == '\n')) {
1067                 break;
1068             }
1069         }
1070         buffer[i] = '\0';
1071         for (i = 2; buffer[i] == ' ' ; ++i)
1072             ;
1073         *interpreter = apr_pstrdup(r->pool, buffer + i ); 
1074     }
1075     else {
1076         /* Not a script, is it an executable? */
1077         IMAGE_DOS_HEADER *hdr = (IMAGE_DOS_HEADER*)buffer;    
1078         if ((nBytesRead >= sizeof(IMAGE_DOS_HEADER)) && (hdr->e_magic == IMAGE_DOS_SIGNATURE)) {
1079             if (hdr->e_lfarlc < 0x40)
1080                 fileType = eFileTypeEXE16;
1081             else
1082                 fileType = eFileTypeEXE32;
1083         }
1084         else
1085             fileType = eFileTypeUNKNOWN;
1086     }
1087
1088     return fileType;
1089 }
1090 #endif
1091
1092 /*****************************************************************
1093  *
1094  * Commands... this module handles almost all of the NCSA httpd.conf
1095  * commands, but most of the old srm.conf is in the the modules.
1096  */
1097
1098
1099 /* returns a parent if it matches the given directive */
1100 static const ap_directive_t * find_parent(const ap_directive_t *dirp,
1101                                           const char *what)
1102 {
1103     while (dirp->parent != NULL) {
1104         dirp = dirp->parent;
1105         /* ### it would be nice to have atom-ized directives */
1106         if (strcasecmp(dirp->directive, what) == 0)
1107             return dirp;
1108     }
1109     return NULL;
1110 }
1111
1112 AP_DECLARE(const char *) ap_check_cmd_context(cmd_parms *cmd,
1113                                               unsigned forbidden)
1114 {
1115     const char *gt = (cmd->cmd->name[0] == '<'
1116                       && cmd->cmd->name[strlen(cmd->cmd->name)-1] != '>')
1117                          ? ">" : "";
1118     const ap_directive_t *found;
1119
1120     if ((forbidden & NOT_IN_VIRTUALHOST) && cmd->server->is_virtual) {
1121         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1122                           " cannot occur within <VirtualHost> section", NULL);
1123     }
1124
1125     if ((forbidden & NOT_IN_LIMIT) && cmd->limited != -1) {
1126         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1127                           " cannot occur within <Limit> section", NULL);
1128     }
1129
1130     if ((forbidden & NOT_IN_DIR_LOC_FILE) == NOT_IN_DIR_LOC_FILE
1131         && cmd->path != NULL) {
1132         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1133                           " cannot occur within <Directory/Location/Files> "
1134                           "section", NULL);
1135     }
1136     
1137     if (((forbidden & NOT_IN_DIRECTORY)
1138          && ((found = find_parent(cmd->directive, "<Directory"))
1139              || (found = find_parent(cmd->directive, "<DirectoryMatch"))))
1140         || ((forbidden & NOT_IN_LOCATION)
1141             && ((found = find_parent(cmd->directive, "<Location"))
1142                 || (found = find_parent(cmd->directive, "<LocationMatch"))))
1143         || ((forbidden & NOT_IN_FILES)
1144             && ((found = find_parent(cmd->directive, "<Files"))
1145                 || (found = find_parent(cmd->directive, "<FilesMatch"))))) {
1146         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1147                           " cannot occur within ", found->directive,
1148                           "> section", NULL);
1149     }
1150
1151     return NULL;
1152 }
1153
1154 static const char *set_access_name(cmd_parms *cmd, void *dummy,
1155                                    const char *arg)
1156 {
1157     void *sconf = cmd->server->module_config;
1158     core_server_config *conf = ap_get_module_config(sconf, &core_module);
1159
1160     const char *err = ap_check_cmd_context(cmd,
1161                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1162     if (err != NULL) {
1163         return err;
1164     }
1165
1166     conf->access_name = apr_pstrdup(cmd->pool, arg);
1167     return NULL;
1168 }
1169
1170 #ifdef GPROF
1171 static const char *set_gprof_dir(cmd_parms *cmd, void *dummy, char *arg)
1172 {
1173     void *sconf = cmd->server->module_config;
1174     core_server_config *conf = ap_get_module_config(sconf, &core_module);
1175
1176     const char *err = ap_check_cmd_context(cmd,
1177                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1178     if (err != NULL) {
1179         return err;
1180     }
1181
1182     conf->gprof_dir = apr_pstrdup(cmd->pool, arg);
1183     return NULL;
1184 }
1185 #endif /*GPROF*/
1186
1187 static const char *set_add_default_charset(cmd_parms *cmd, 
1188                                            void *d_, const char *arg)
1189 {
1190     core_dir_config *d=d_;
1191
1192     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1193     if (err != NULL) {
1194         return err;
1195     }
1196     if (!strcasecmp(arg, "Off")) {
1197        d->add_default_charset = ADD_DEFAULT_CHARSET_OFF;
1198     }
1199     else if (!strcasecmp(arg, "On")) {
1200        d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
1201        d->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
1202     }
1203     else {
1204        d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
1205        d->add_default_charset_name = arg;
1206     }
1207     return NULL;
1208 }
1209
1210 static const char *set_document_root(cmd_parms *cmd, void *dummy,
1211                                      const char *arg)
1212 {
1213     void *sconf = cmd->server->module_config;
1214     core_server_config *conf = ap_get_module_config(sconf, &core_module);
1215   
1216     const char *err = ap_check_cmd_context(cmd,
1217                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1218     if (err != NULL) {
1219         return err;
1220     }
1221
1222     arg = ap_os_canonical_filename(cmd->pool, arg);
1223     if (/* TODO: ap_configtestonly && ap_docrootcheck && */ !ap_is_directory(arg)) {
1224         if (cmd->server->is_virtual) {
1225             ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
1226                          "Warning: DocumentRoot [%s] does not exist",
1227                          arg);
1228         }
1229         else {
1230             return "DocumentRoot must be a directory";
1231         }
1232     }
1233     
1234     conf->ap_document_root = arg;
1235     return NULL;
1236 }
1237
1238 AP_DECLARE(void) ap_custom_response(request_rec *r, int status, char *string)
1239 {
1240     core_dir_config *conf = 
1241         ap_get_module_config(r->per_dir_config, &core_module);
1242     int idx;
1243
1244     if(conf->response_code_strings == NULL) {
1245         conf->response_code_strings = 
1246             apr_pcalloc(r->pool,
1247                     sizeof(*conf->response_code_strings) * 
1248                     RESPONSE_CODES);
1249     }
1250
1251     idx = ap_index_of_response(status);
1252
1253     conf->response_code_strings[idx] = 
1254        ((ap_is_url(string) || (*string == '/')) && (*string != '"')) ? 
1255        apr_pstrdup(r->pool, string) : apr_pstrcat(r->pool, "\"", string, NULL);
1256 }
1257
1258 static const char *set_error_document(cmd_parms *cmd, void *conf_,
1259                                       const char *errno_str, const char *msg)
1260 {
1261     core_dir_config *conf=conf_;
1262     int error_number, index_number, idx500;
1263     enum { MSG, LOCAL_PATH, REMOTE_PATH } what = MSG;
1264                 
1265     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1266     if (err != NULL) {
1267         return err;
1268     }
1269
1270     /* 1st parameter should be a 3 digit number, which we recognize;
1271      * convert it into an array index
1272      */
1273     error_number = atoi(errno_str);
1274     idx500 = ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR);
1275
1276     if (error_number == HTTP_INTERNAL_SERVER_ERROR) {
1277         index_number = idx500;
1278     }
1279     else if ((index_number = ap_index_of_response(error_number)) == idx500) {
1280         return apr_pstrcat(cmd->pool, "Unsupported HTTP response code ",
1281                           errno_str, NULL);
1282     }
1283
1284     /* Heuristic to determine second argument. */
1285     if (ap_strchr_c(msg,' ')) 
1286         what = MSG;
1287     else if (msg[0] == '/')
1288         what = LOCAL_PATH;
1289     else if (ap_is_url(msg))
1290         what = REMOTE_PATH;
1291     else
1292         what = MSG;
1293    
1294     /* The entry should be ignored if it is a full URL for a 401 error */
1295
1296     if (error_number == 401 && what == REMOTE_PATH) {
1297         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, cmd->server,
1298                      "cannot use a full URL in a 401 ErrorDocument "
1299                      "directive --- ignoring!");
1300     }
1301     else { /* Store it... */
1302         if (conf->response_code_strings == NULL) {
1303             conf->response_code_strings =
1304                 apr_pcalloc(cmd->pool,
1305                            sizeof(*conf->response_code_strings) * RESPONSE_CODES);
1306         }
1307         /* hack. Prefix a " if it is a msg; as that is what
1308          * http_protocol.c relies on to distinguish between
1309          * a msg and a (local) path.
1310          */
1311         conf->response_code_strings[index_number] = (what == MSG) ?
1312                 apr_pstrcat(cmd->pool, "\"",msg,NULL) :
1313                 apr_pstrdup(cmd->pool, msg);
1314     }   
1315
1316     return NULL;
1317 }
1318
1319 static const char *set_override(cmd_parms *cmd, void *d_, const char *l)
1320 {
1321     core_dir_config *d=d_;
1322     char *w;
1323   
1324     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1325     if (err != NULL) {
1326         return err;
1327     }
1328
1329     d->override = OR_NONE;
1330     while (l[0]) {
1331         w = ap_getword_conf(cmd->pool, &l);
1332         if (!strcasecmp(w, "Limit")) {
1333             d->override |= OR_LIMIT;
1334         }
1335         else if (!strcasecmp(w, "Options")) {
1336             d->override |= OR_OPTIONS;
1337         }
1338         else if (!strcasecmp(w, "FileInfo")) {
1339             d->override |= OR_FILEINFO;
1340         }
1341         else if (!strcasecmp(w, "AuthConfig")) {
1342             d->override |= OR_AUTHCFG;
1343         }
1344         else if (!strcasecmp(w, "Indexes")) {
1345             d->override |= OR_INDEXES;
1346         }
1347         else if (!strcasecmp(w, "None")) {
1348             d->override = OR_NONE;
1349         }
1350         else if (!strcasecmp(w, "All")) {
1351             d->override = OR_ALL;
1352         }
1353         else {
1354             return apr_pstrcat(cmd->pool, "Illegal override option ", w, NULL);
1355         }
1356         d->override &= ~OR_UNSET;
1357     }
1358
1359     return NULL;
1360 }
1361
1362 static const char *set_options(cmd_parms *cmd, void *d_, const char *l)
1363 {
1364     core_dir_config *d=d_;
1365     allow_options_t opt;
1366     int first = 1;
1367     char action;
1368
1369     while (l[0]) {
1370         char *w = ap_getword_conf(cmd->pool, &l);
1371         action = '\0';
1372
1373         if (*w == '+' || *w == '-') {
1374             action = *(w++);
1375         }
1376         else if (first) {
1377             d->opts = OPT_NONE;
1378             first = 0;
1379         }
1380             
1381         if (!strcasecmp(w, "Indexes")) {
1382             opt = OPT_INDEXES;
1383         }
1384         else if (!strcasecmp(w, "Includes")) {
1385             opt = OPT_INCLUDES;
1386         }
1387         else if (!strcasecmp(w, "IncludesNOEXEC")) {
1388             opt = (OPT_INCLUDES | OPT_INCNOEXEC);
1389         }
1390         else if (!strcasecmp(w, "FollowSymLinks")) {
1391             opt = OPT_SYM_LINKS;
1392         }
1393         else if (!strcasecmp(w, "SymLinksIfOwnerMatch")) {
1394             opt = OPT_SYM_OWNER;
1395         }
1396         else if (!strcasecmp(w, "execCGI")) {
1397             opt = OPT_EXECCGI;
1398         }
1399         else if (!strcasecmp(w, "MultiViews")) {
1400             opt = OPT_MULTI;
1401         }
1402         else if (!strcasecmp(w, "RunScripts")) { /* AI backcompat. Yuck */
1403             opt = OPT_MULTI|OPT_EXECCGI;
1404         }
1405         else if (!strcasecmp(w, "None")) {
1406             opt = OPT_NONE;
1407         }
1408         else if (!strcasecmp(w, "All")) {
1409             opt = OPT_ALL;
1410         }
1411         else {
1412             return apr_pstrcat(cmd->pool, "Illegal option ", w, NULL);
1413         }
1414
1415         /* we ensure the invariant (d->opts_add & d->opts_remove) == 0 */
1416         if (action == '-') {
1417             d->opts_remove |= opt;
1418             d->opts_add &= ~opt;
1419             d->opts &= ~opt;
1420         }
1421         else if (action == '+') {
1422             d->opts_add |= opt;
1423             d->opts_remove &= ~opt;
1424             d->opts |= opt;
1425         }
1426         else {
1427             d->opts |= opt;
1428         }
1429     }
1430
1431     return NULL;
1432 }
1433
1434 static const char *satisfy(cmd_parms *cmd, void *c_, const char *arg)
1435 {
1436     core_dir_config *c=c_;
1437
1438     if (!strcasecmp(arg, "all")) {
1439         c->satisfy = SATISFY_ALL;
1440     }
1441     else if (!strcasecmp(arg, "any")) {
1442         c->satisfy = SATISFY_ANY;
1443     }
1444     else {
1445         return "Satisfy either 'any' or 'all'.";
1446     }
1447     return NULL;
1448 }
1449
1450 static const char *require(cmd_parms *cmd, void *c_, const char *arg)
1451 {
1452     require_line *r;
1453     core_dir_config *c=c_;
1454
1455     if (!c->ap_requires) {
1456         c->ap_requires = apr_make_array(cmd->pool, 2, sizeof(require_line));
1457     }
1458     r = (require_line *)apr_push_array(c->ap_requires);
1459     r->requirement = apr_pstrdup(cmd->pool, arg);
1460     r->method_mask = cmd->limited;
1461     return NULL;
1462 }
1463
1464 AP_CORE_DECLARE_NONSTD(const char *) ap_limit_section(cmd_parms *cmd, void *dummy,
1465                                                   const char *arg) {
1466     const char *limited_methods = ap_getword(cmd->pool, &arg, '>');
1467     void *tog = cmd->cmd->cmd_data;
1468     int limited = 0;
1469     const char *errmsg;
1470   
1471     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1472     if (err != NULL) {
1473         return err;
1474     }
1475
1476     while (limited_methods[0]) {
1477         char *method = ap_getword_conf(cmd->pool, &limited_methods);
1478         int  methnum = ap_method_number_of(method);
1479
1480         if (methnum == M_TRACE && !tog) {
1481             return "TRACE cannot be controlled by <Limit>";
1482         }
1483         else if (methnum == M_INVALID) {
1484             char **xmethod;
1485             register int i, j, k;
1486
1487             /*
1488              * Deal with <Limit> by adding the method to the list.
1489              */
1490             if (!tog) {
1491                 if (cmd->limited_xmethods == NULL) {
1492                     cmd->limited_xmethods = apr_make_array(cmd->pool, 2,
1493                                                            sizeof(char *));
1494                 }
1495                 xmethod = (char **) apr_push_array(cmd->limited_xmethods);
1496                 *xmethod = apr_pstrdup(cmd->pool, method);
1497             }
1498             /*
1499              * <LimitExcept>, so remove any/all occurrences of the method
1500              * in the extension array.
1501              */
1502             else if ((cmd->limited_xmethods != NULL)
1503                      && (cmd->limited_xmethods->nelts != 0)) {
1504                 xmethod = (char **) cmd->limited_xmethods->elts;
1505                 for (i = 0; i < cmd->limited_xmethods->nelts; ) {
1506                     if (strcmp(xmethod[i], method) == 0) {
1507                         for (j = i, k = i + 1;
1508                              k < cmd->limited_xmethods->nelts;
1509                              ++j, ++k) {
1510                             xmethod[j] = xmethod[k];
1511                         }
1512                         cmd->limited_xmethods->nelts--;
1513                     }
1514                 }
1515             }
1516         }
1517         limited |= (1 << methnum);
1518     }
1519
1520     /* Killing two features with one function,
1521      * if (tog == NULL) <Limit>, else <LimitExcept>
1522      */
1523     cmd->limited = tog ? ~limited : limited;
1524
1525     errmsg = ap_walk_config(cmd->directive->first_child, cmd, cmd->context);
1526
1527     cmd->limited = -1;
1528
1529     return errmsg;
1530 }
1531
1532 /* We use this in <DirectoryMatch> and <FilesMatch>, to ensure that 
1533  * people don't get bitten by wrong-cased regex matches
1534  */
1535
1536 #ifdef WIN32
1537 #define USE_ICASE REG_ICASE
1538 #else
1539 #define USE_ICASE 0
1540 #endif
1541
1542 /*
1543  * Report a missing-'>' syntax error.
1544  */
1545 static char *unclosed_directive(cmd_parms *cmd)
1546 {
1547     return apr_pstrcat(cmd->pool, cmd->cmd->name,
1548                       "> directive missing closing '>'", NULL);
1549 }
1550
1551 static const char *dirsection(cmd_parms *cmd, void *mconfig, const char *arg)
1552 {
1553     const char *errmsg;
1554     const char *endp = ap_strrchr_c(arg, '>');
1555     int old_overrides = cmd->override;
1556     char *old_path = cmd->path;
1557     core_dir_config *conf;
1558     void *new_dir_conf = ap_create_per_dir_config(cmd->pool);
1559     regex_t *r = NULL;
1560     const command_rec *thiscmd = cmd->cmd;
1561
1562     const char *err = ap_check_cmd_context(cmd,
1563                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1564     if (err != NULL) {
1565         return err;
1566     }
1567
1568     if (endp == NULL) {
1569         return unclosed_directive(cmd);
1570     }
1571
1572     arg=apr_pstrndup(cmd->pool, arg, endp-arg);
1573
1574     cmd->path = ap_getword_conf(cmd->pool, &arg);
1575     cmd->override = OR_ALL|ACCESS_CONF;
1576
1577     if (thiscmd->cmd_data) { /* <DirectoryMatch> */
1578         r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1579     }
1580     else if (!strcmp(cmd->path, "~")) {
1581         cmd->path = ap_getword_conf(cmd->pool, &arg);
1582         r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1583     }
1584 #if defined(HAVE_DRIVE_LETTERS) || defined(NETWARE)
1585     else if (strcmp(cmd->path, "/") == 0) {
1586         /* Treat 'default' path / as an inalienable root */
1587         cmd->path = apr_pstrdup(cmd->pool, cmd->path);
1588     }
1589 #endif
1590 #if defined(HAVE_UNC_PATHS)
1591     else if (strcmp(cmd->path, "//") == 0) {
1592         /* Treat UNC path // as an inalienable root */
1593         cmd->path = apr_pstrdup(cmd->pool, cmd->path);
1594     }
1595 #endif
1596     else {
1597         /* Ensure that the pathname is canonical */
1598         cmd->path = ap_os_canonical_filename(cmd->pool, cmd->path);
1599     }
1600
1601     /* initialize our config and fetch it */
1602     conf = (core_dir_config *)ap_set_config_vectors(cmd, new_dir_conf,
1603                                                     &core_module);
1604
1605     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_dir_conf);
1606     if (errmsg != NULL)
1607         return errmsg;
1608
1609     conf->r = r;
1610
1611     ap_add_per_dir_conf(cmd->server, new_dir_conf);
1612
1613     if (*arg != '\0') {
1614         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1615                           "> arguments not (yet) supported.", NULL);
1616     }
1617
1618     cmd->path = old_path;
1619     cmd->override = old_overrides;
1620
1621     return NULL;
1622 }
1623
1624 static const char *urlsection(cmd_parms *cmd, void *mconfig, const char *arg)
1625 {
1626     const char *errmsg;
1627     const char *endp = ap_strrchr_c(arg, '>');
1628     int old_overrides = cmd->override;
1629     char *old_path = cmd->path;
1630     core_dir_config *conf;
1631     regex_t *r = NULL;
1632     const command_rec *thiscmd = cmd->cmd;
1633
1634     void *new_url_conf = ap_create_per_dir_config(cmd->pool);
1635
1636     const char *err = ap_check_cmd_context(cmd,
1637                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1638     if (err != NULL) {
1639         return err;
1640     }
1641
1642     if (endp == NULL) {
1643         return unclosed_directive(cmd);
1644     }
1645
1646     arg=apr_pstrndup(cmd->pool, arg, endp-arg);
1647
1648     cmd->path = ap_getword_conf(cmd->pool, &arg);
1649     cmd->override = OR_ALL|ACCESS_CONF;
1650
1651     if (thiscmd->cmd_data) { /* <LocationMatch> */
1652         r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
1653     }
1654     else if (!strcmp(cmd->path, "~")) {
1655         cmd->path = ap_getword_conf(cmd->pool, &arg);
1656         r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
1657     }
1658
1659     /* initialize our config and fetch it */
1660     conf = (core_dir_config *)ap_set_config_vectors(cmd, new_url_conf,
1661                                                     &core_module);
1662
1663     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_url_conf);
1664     if (errmsg != NULL)
1665         return errmsg;
1666
1667     conf->d = apr_pstrdup(cmd->pool, cmd->path);        /* No mangling, please */
1668     conf->d_is_fnmatch = apr_is_fnmatch(conf->d) != 0;
1669     conf->r = r;
1670
1671     ap_add_per_url_conf(cmd->server, new_url_conf);
1672     
1673     if (*arg != '\0') {
1674         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1675                           "> arguments not (yet) supported.", NULL);
1676     }
1677
1678     cmd->path = old_path;
1679     cmd->override = old_overrides;
1680
1681     return NULL;
1682 }
1683
1684 static const char *filesection(cmd_parms *cmd, void *mconfig, const char *arg)
1685 {
1686     const char *errmsg;
1687     const char *endp = ap_strrchr_c(arg, '>');
1688     int old_overrides = cmd->override;
1689     char *old_path = cmd->path;
1690     core_dir_config *conf;
1691     regex_t *r = NULL;
1692     const command_rec *thiscmd = cmd->cmd;
1693     core_dir_config *c=mconfig;
1694
1695     void *new_file_conf = ap_create_per_dir_config(cmd->pool);
1696
1697     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_LOCATION);
1698     if (err != NULL) {
1699         return err;
1700     }
1701
1702     if (endp == NULL) {
1703         return unclosed_directive(cmd);
1704     }
1705
1706     arg=apr_pstrndup(cmd->pool, arg, endp-arg);
1707
1708     cmd->path = ap_getword_conf(cmd->pool, &arg);
1709     /* Only if not an .htaccess file */
1710     if (!old_path) {
1711         cmd->override = OR_ALL|ACCESS_CONF;
1712     }
1713
1714     if (thiscmd->cmd_data) { /* <FilesMatch> */
1715         r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1716     }
1717     else if (!strcmp(cmd->path, "~")) {
1718         cmd->path = ap_getword_conf(cmd->pool, &arg);
1719         r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1720     }
1721     else {
1722         /* Ensure that the pathname is canonical */
1723         cmd->path = ap_os_canonical_filename(cmd->pool, cmd->path);
1724     }
1725
1726     /* initialize our config and fetch it */
1727     conf = (core_dir_config *)ap_set_config_vectors(cmd, new_file_conf,
1728                                                     &core_module);
1729
1730     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_file_conf);
1731     if (errmsg != NULL)
1732         return errmsg;
1733
1734     conf->d = cmd->path;
1735     conf->d_is_fnmatch = apr_is_fnmatch(conf->d) != 0;
1736     conf->r = r;
1737
1738     ap_add_file_conf(c, new_file_conf);
1739
1740     if (*arg != '\0') {
1741         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1742                           "> arguments not (yet) supported.", NULL);
1743     }
1744
1745     cmd->path = old_path;
1746     cmd->override = old_overrides;
1747
1748     return NULL;
1749 }
1750
1751 static const char *start_ifmod(cmd_parms *cmd, void *mconfig, const char *arg)
1752 {
1753     const char *endp = ap_strrchr_c(arg, '>');
1754     int not = (arg[0] == '!');
1755     module *found;
1756
1757     if (endp == NULL) {
1758         return unclosed_directive(cmd);
1759     }
1760
1761     arg=apr_pstrndup(cmd->pool, arg, endp-arg);
1762
1763     if (not) {
1764         arg++;
1765     }
1766
1767     found = ap_find_linked_module(arg);
1768
1769     if ((!not && found) || (not && !found)) {
1770         ap_directive_t *parent = NULL;
1771         ap_directive_t *current = NULL;
1772         const char *retval;
1773
1774         retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd, 
1775                                       &current, &parent, "<IfModule");
1776         *(ap_directive_t **)mconfig = current;
1777         return retval;
1778     }
1779     else { 
1780         *(ap_directive_t **)mconfig = NULL;
1781         return ap_soak_end_container(cmd, "<IfModule");
1782     }
1783 }
1784
1785 AP_DECLARE(int) ap_exists_config_define(const char *name)
1786 {
1787     char **defines;
1788     int i;
1789
1790     defines = (char **)ap_server_config_defines->elts;
1791     for (i = 0; i < ap_server_config_defines->nelts; i++) {
1792         if (strcmp(defines[i], name) == 0) {
1793             return 1;
1794         }
1795     }
1796     return 0;
1797 }
1798
1799 static const char *start_ifdefine(cmd_parms *cmd, void *dummy, const char *arg)
1800 {
1801     const char *endp;
1802     int defined;
1803     int not = 0;
1804
1805     endp = ap_strrchr_c(arg, '>');
1806     if (endp == NULL) {
1807         return unclosed_directive(cmd);
1808     }
1809
1810     arg=apr_pstrndup(cmd->pool, arg, endp-arg);
1811
1812     if (arg[0] == '!') {
1813         not = 1;
1814         arg++;
1815     }
1816
1817     defined = ap_exists_config_define(arg);
1818     if ((!not && defined) || (not && !defined)) {
1819         ap_directive_t *parent = NULL;
1820         ap_directive_t *current = NULL;
1821         const char *retval;
1822
1823         retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd, 
1824                                       &current, &parent, "<IfDefine");
1825         *(ap_directive_t **)dummy = current;
1826         return retval;
1827     }
1828     else { 
1829         *(ap_directive_t **)dummy = NULL;
1830         return ap_soak_end_container(cmd, "<IfDefine");
1831     }
1832 }
1833
1834 /* httpd.conf commands... beginning with the <VirtualHost> business */
1835
1836 static const char *virtualhost_section(cmd_parms *cmd, void *dummy,
1837                                        const char *arg)
1838 {
1839     server_rec *main_server = cmd->server, *s;
1840     const char *errmsg;
1841     const char *endp = ap_strrchr_c(arg, '>');
1842     apr_pool_t *p = cmd->pool;
1843
1844     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1845     if (err != NULL) {
1846         return err;
1847     }
1848
1849     if (endp == NULL) {
1850         return unclosed_directive(cmd);
1851     }
1852
1853     arg=apr_pstrndup(cmd->pool, arg, endp-arg);
1854     
1855     /* FIXME: There's another feature waiting to happen here -- since you
1856         can now put multiple addresses/names on a single <VirtualHost>
1857         you might want to use it to group common definitions and then
1858         define other "subhosts" with their individual differences.  But
1859         personally I'd rather just do it with a macro preprocessor. -djg */
1860     if (main_server->is_virtual) {
1861         return "<VirtualHost> doesn't nest!";
1862     }
1863     
1864     errmsg = ap_init_virtual_host(p, arg, main_server, &s);
1865     if (errmsg) {
1866         return errmsg;
1867     }
1868
1869     s->next = main_server->next;
1870     main_server->next = s;
1871
1872     s->defn_name = cmd->directive->filename;
1873     s->defn_line_number = cmd->directive->line_num;
1874
1875     cmd->server = s;
1876
1877     errmsg = ap_walk_config(cmd->directive->first_child, cmd,
1878                             s->lookup_defaults);
1879
1880     cmd->server = main_server;
1881
1882     return errmsg;
1883 }
1884
1885 static const char *set_server_alias(cmd_parms *cmd, void *dummy,
1886                                     const char *arg)
1887 {
1888     if (!cmd->server->names) {
1889         return "ServerAlias only used in <VirtualHost>";
1890     }
1891     while (*arg) {
1892         char **item, *name = ap_getword_conf(cmd->pool, &arg);
1893         if (ap_is_matchexp(name)) {
1894             item = (char **)apr_push_array(cmd->server->wild_names);
1895         }
1896         else {
1897             item = (char **)apr_push_array(cmd->server->names);
1898         }
1899         *item = name;
1900     }
1901     return NULL;
1902 }
1903
1904 static const char *add_filter(cmd_parms *cmd, void *dummy, const char *arg)
1905 {
1906     core_dir_config *conf = dummy;
1907     char **newfilter;
1908     
1909     newfilter = (char **)apr_push_array(conf->output_filters);
1910     *newfilter = apr_pstrdup(cmd->pool, arg);
1911     return NULL;
1912 }
1913
1914 static const char *add_input_filter(cmd_parms *cmd, void *dummy, const char *arg)
1915 {
1916     core_dir_config *conf = dummy;
1917     char **newfilter;
1918     
1919     newfilter = (char **)apr_push_array(conf->input_filters);
1920     *newfilter = apr_pstrdup(cmd->pool, arg);
1921     return NULL;
1922 }
1923
1924 static const char *add_module_command(cmd_parms *cmd, void *dummy,
1925                                       const char *arg)
1926 {
1927     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1928     if (err != NULL) {
1929         return err;
1930     }
1931
1932     if (!ap_add_named_module(arg)) {
1933         return apr_pstrcat(cmd->pool, "Cannot add module via name '", arg, 
1934                           "': not in list of loaded modules", NULL);
1935     }
1936     *(ap_directive_t **)dummy = NULL;
1937     return NULL;
1938 }
1939
1940 static const char *clear_module_list_command(cmd_parms *cmd, void *dummy)
1941 {
1942     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1943     if (err != NULL) {
1944         return err;
1945     }
1946
1947     ap_clear_module_list();
1948     *(ap_directive_t **)dummy = NULL;
1949     return NULL;
1950 }
1951
1952 static const char *set_server_string_slot(cmd_parms *cmd, void *dummy,
1953                                           const char *arg)
1954 {
1955     /* This one's pretty generic... */
1956   
1957     int offset = (int)(long)cmd->info;
1958     char *struct_ptr = (char *)cmd->server;
1959     
1960     const char *err = ap_check_cmd_context(cmd, 
1961                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1962     if (err != NULL) {
1963         return err;
1964     }
1965
1966     *(const char **)(struct_ptr + offset) = arg;
1967     return NULL;
1968 }
1969
1970 static const char *server_port(cmd_parms *cmd, void *dummy, const char *arg)
1971 {
1972     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1973     int port;
1974
1975     if (err != NULL) {
1976         return err;
1977     }
1978     port = atoi(arg);
1979     if (port <= 0 || port >= 65536) { /* 65536 == 1<<16 */
1980         return apr_pstrcat(cmd->temp_pool, "The port number \"", arg, 
1981                           "\" is outside the appropriate range "
1982                           "(i.e., 1..65535).", NULL);
1983     }
1984     cmd->server->port = port;
1985     return NULL;
1986 }
1987
1988 static const char *set_signature_flag(cmd_parms *cmd, void *d_,
1989                                       const char *arg)
1990 {
1991     core_dir_config *d=d_;
1992
1993     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1994     if (err != NULL) {
1995         return err;
1996     }
1997
1998     if (strcasecmp(arg, "On") == 0) {
1999         d->server_signature = srv_sig_on;
2000     }
2001     else if (strcasecmp(arg, "Off") == 0) {
2002         d->server_signature = srv_sig_off;
2003     }
2004     else if (strcasecmp(arg, "EMail") == 0) {
2005         d->server_signature = srv_sig_withmail;
2006     }
2007     else {
2008         return "ServerSignature: use one of: off | on | email";
2009     }
2010     return NULL;
2011 }
2012
2013 static const char *set_server_root(cmd_parms *cmd, void *dummy,
2014                                    const char *arg) 
2015 {
2016     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2017
2018     if (err != NULL) {
2019         return err;
2020     }
2021
2022     arg = ap_os_canonical_filename(cmd->pool, arg);
2023
2024     if (!ap_is_directory(arg)) {
2025         return "ServerRoot must be a valid directory";
2026     }
2027     ap_server_root = arg;
2028     return NULL;
2029 }
2030
2031 static const char *set_timeout(cmd_parms *cmd, void *dummy, const char *arg)
2032 {
2033     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2034     if (err != NULL) {
2035         return err;
2036     }
2037
2038     cmd->server->timeout = atoi(arg);
2039     return NULL;
2040 }
2041
2042 static const char *set_keep_alive_timeout(cmd_parms *cmd, void *dummy,
2043                                           const char *arg)
2044 {
2045     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2046     if (err != NULL) {
2047         return err;
2048     }
2049
2050     cmd->server->keep_alive_timeout = atoi(arg);
2051     return NULL;
2052 }
2053
2054 static const char *set_keep_alive(cmd_parms *cmd, void *dummy,
2055                                   const char *arg) 
2056 {
2057     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2058     if (err != NULL) {
2059         return err;
2060     }
2061
2062     /* We've changed it to On/Off, but used to use numbers
2063      * so we accept anything but "Off" or "0" as "On"
2064      */
2065     if (!strcasecmp(arg, "off") || !strcmp(arg, "0")) {
2066         cmd->server->keep_alive = 0;
2067     }
2068     else {
2069         cmd->server->keep_alive = 1;
2070     }
2071     return NULL;
2072 }
2073
2074 static const char *set_keep_alive_max(cmd_parms *cmd, void *dummy,
2075                                       const char *arg)
2076 {
2077     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2078     if (err != NULL) {
2079         return err;
2080     }
2081
2082     cmd->server->keep_alive_max = atoi(arg);
2083     return NULL;
2084 }
2085
2086 static const char *set_idcheck(cmd_parms *cmd, void *d_, int arg) 
2087 {
2088     core_dir_config *d=d_;
2089     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2090     if (err != NULL) {
2091         return err;
2092     }
2093
2094     d->do_rfc1413 = arg != 0;
2095     return NULL;
2096 }
2097
2098 static const char *set_hostname_lookups(cmd_parms *cmd, void *d_,
2099                                         const char *arg)
2100 {
2101     core_dir_config *d=d_;
2102
2103     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2104     if (err != NULL) {
2105         return err;
2106     }
2107
2108     if (!strcasecmp(arg, "on")) {
2109         d->hostname_lookups = HOSTNAME_LOOKUP_ON;
2110     }
2111     else if (!strcasecmp(arg, "off")) {
2112         d->hostname_lookups = HOSTNAME_LOOKUP_OFF;
2113     }
2114     else if (!strcasecmp(arg, "double")) {
2115         d->hostname_lookups = HOSTNAME_LOOKUP_DOUBLE;
2116     }
2117     else {
2118         return "parameter must be 'on', 'off', or 'double'";
2119     }
2120     return NULL;
2121 }
2122
2123 static const char *set_serverpath(cmd_parms *cmd, void *dummy,
2124                                   const char *arg) 
2125 {
2126     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2127     if (err != NULL) {
2128         return err;
2129     }
2130
2131     cmd->server->path = arg;
2132     cmd->server->pathlen = strlen(arg);
2133     return NULL;
2134 }
2135
2136 static const char *set_content_md5(cmd_parms *cmd, void *d_, int arg)
2137 {
2138     core_dir_config *d=d_;
2139     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2140     if (err != NULL) {
2141         return err;
2142     }
2143
2144     d->content_md5 = arg != 0;
2145     return NULL;
2146 }
2147
2148 static const char *set_use_canonical_name(cmd_parms *cmd, void *d_,
2149                                           const char *arg)
2150 {
2151     core_dir_config *d=d_;
2152     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2153     if (err != NULL) {
2154         return err;
2155     }
2156
2157     if (strcasecmp(arg, "on") == 0) {
2158         d->use_canonical_name = USE_CANONICAL_NAME_ON;
2159     }
2160     else if (strcasecmp(arg, "off") == 0) {
2161         d->use_canonical_name = USE_CANONICAL_NAME_OFF;
2162     }
2163     else if (strcasecmp(arg, "dns") == 0) {
2164         d->use_canonical_name = USE_CANONICAL_NAME_DNS;
2165     }
2166     else {
2167         return "parameter must be 'on', 'off', or 'dns'";
2168     }
2169     return NULL;
2170 }
2171
2172
2173 static const char *include_config (cmd_parms *cmd, void *dummy,
2174                                    const char *name)
2175 {
2176     ap_directive_t *conftree = NULL;
2177
2178     ap_process_resource_config(cmd->server,
2179         ap_server_root_relative(cmd->pool, name),
2180                                  &conftree, cmd->pool, cmd->temp_pool);
2181     *(ap_directive_t **)dummy = conftree;
2182     return NULL;
2183 }
2184
2185 static const char *set_loglevel(cmd_parms *cmd, void *dummy, const char *arg) 
2186 {
2187     char *str;
2188     
2189     const char *err = ap_check_cmd_context(cmd,
2190                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2191     if (err != NULL) {
2192         return err;
2193     }
2194
2195     if ((str = ap_getword_conf(cmd->pool, &arg))) {
2196         if (!strcasecmp(str, "emerg")) {
2197             cmd->server->loglevel = APLOG_EMERG;
2198         }
2199         else if (!strcasecmp(str, "alert")) {
2200             cmd->server->loglevel = APLOG_ALERT;
2201         }
2202         else if (!strcasecmp(str, "crit")) {
2203             cmd->server->loglevel = APLOG_CRIT;
2204         }
2205         else if (!strcasecmp(str, "error")) {
2206             cmd->server->loglevel = APLOG_ERR;
2207         }
2208         else if (!strcasecmp(str, "warn")) {
2209             cmd->server->loglevel = APLOG_WARNING;
2210         }
2211         else if (!strcasecmp(str, "notice")) {
2212             cmd->server->loglevel = APLOG_NOTICE;
2213         }
2214         else if (!strcasecmp(str, "info")) {
2215             cmd->server->loglevel = APLOG_INFO;
2216         }
2217         else if (!strcasecmp(str, "debug")) {
2218             cmd->server->loglevel = APLOG_DEBUG;
2219         }
2220         else {
2221             return "LogLevel requires level keyword: one of "
2222                    "emerg/alert/crit/error/warn/notice/info/debug";
2223         }
2224     }
2225     else {
2226         return "LogLevel requires level keyword";
2227     }
2228
2229     return NULL;
2230 }
2231
2232 AP_DECLARE(const char *) ap_psignature(const char *prefix, request_rec *r)
2233 {
2234     char sport[20];
2235     core_dir_config *conf;
2236
2237     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
2238                                                    &core_module);
2239     if ((conf->server_signature == srv_sig_off)
2240             || (conf->server_signature == srv_sig_unset)) {
2241         return "";
2242     }
2243
2244     apr_snprintf(sport, sizeof sport, "%u", (unsigned) ap_get_server_port(r));
2245
2246     if (conf->server_signature == srv_sig_withmail) {
2247         return apr_pstrcat(r->pool, prefix, "<ADDRESS>" AP_SERVER_BASEVERSION
2248                           " Server at <A HREF=\"mailto:",
2249                           r->server->server_admin, "\">",
2250                           ap_get_server_name(r), "</A> Port ", sport,
2251                           "</ADDRESS>\n", NULL);
2252     }
2253     return apr_pstrcat(r->pool, prefix, "<ADDRESS>" AP_SERVER_BASEVERSION
2254                       " Server at ", ap_get_server_name(r), " Port ", sport,
2255                       "</ADDRESS>\n", NULL);
2256 }
2257
2258 /*
2259  * Load an authorisation realm into our location configuration, applying the
2260  * usual rules that apply to realms.
2261  */
2262 static const char *set_authname(cmd_parms *cmd, void *mconfig,
2263                                 const char *word1)
2264 {
2265     core_dir_config *aconfig = (core_dir_config *)mconfig;
2266
2267     aconfig->ap_auth_name = ap_escape_quotes(cmd->pool, word1);
2268     return NULL;
2269 }
2270
2271 #ifdef _OSD_POSIX /* BS2000 Logon Passwd file */
2272 static const char *set_bs2000_account(cmd_parms *cmd, void *dummy, char *name)
2273 {
2274     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2275     if (err != NULL) {
2276         return err;
2277     }
2278
2279     return os_set_account(cmd->pool, name);
2280 }
2281 #endif /*_OSD_POSIX*/
2282
2283 /*
2284  * Handle a request to include the server's OS platform in the Server
2285  * response header field (the ServerTokens directive).  Unfortunately
2286  * this requires a new global in order to communicate the setting back to
2287  * http_main so it can insert the information in the right place in the
2288  * string.
2289  */
2290
2291 static char *server_version = NULL;
2292 static int version_locked = 0; 
2293
2294 enum server_token_type {
2295     SrvTk_MIN,          /* eg: Apache/1.3.0 */
2296     SrvTk_OS,           /* eg: Apache/1.3.0 (UNIX) */
2297     SrvTk_FULL,         /* eg: Apache/1.3.0 (UNIX) PHP/3.0 FooBar/1.2b */
2298     SrvTk_PRODUCT_ONLY  /* eg: Apache */
2299 };
2300 static enum server_token_type ap_server_tokens = SrvTk_FULL;
2301
2302 static apr_status_t reset_version(void *dummy)
2303 {
2304     version_locked = 0;
2305     ap_server_tokens = SrvTk_FULL;
2306     server_version = NULL;
2307     return APR_SUCCESS;
2308 }
2309
2310 AP_DECLARE(const char *) ap_get_server_version(void)
2311 {
2312     return (server_version ? server_version : AP_SERVER_BASEVERSION);
2313 }
2314
2315 AP_DECLARE(void) ap_add_version_component(apr_pool_t *pconf, const char *component)
2316 {
2317     if (! version_locked) {
2318         /*
2319          * If the version string is null, register our cleanup to reset the
2320          * pointer on pool destruction. We also know that, if NULL,
2321          * we are adding the original SERVER_BASEVERSION string.
2322          */
2323         if (server_version == NULL) {
2324             apr_register_cleanup(pconf, NULL, reset_version,
2325                                 apr_null_cleanup);
2326             server_version = apr_pstrdup(pconf, component);
2327         }
2328         else {
2329             /*
2330              * Tack the given component identifier to the end of
2331              * the existing string.
2332              */
2333             server_version = apr_pstrcat(pconf, server_version, " ",
2334                                         component, NULL);
2335         }
2336     }
2337 }
2338
2339 /*
2340  * This routine adds the real server base identity to the version string,
2341  * and then locks out changes until the next reconfig.
2342  */
2343 static void ap_set_version(apr_pool_t *pconf)
2344 {
2345     if (ap_server_tokens == SrvTk_PRODUCT_ONLY) {
2346         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT);
2347     }
2348     else if (ap_server_tokens == SrvTk_MIN) {
2349         ap_add_version_component(pconf, AP_SERVER_BASEVERSION);
2350     }
2351     else {
2352         ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ")");
2353     }
2354     /*
2355      * Lock the server_version string if we're not displaying
2356      * the full set of tokens
2357      */
2358     if (ap_server_tokens != SrvTk_FULL) {
2359         version_locked++;
2360     }
2361 }
2362
2363 static const char *set_serv_tokens(cmd_parms *cmd, void *dummy,
2364                                    const char *arg)
2365 {
2366     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2367     if (err != NULL) {
2368         return err;
2369     }
2370
2371     if (!strcasecmp(arg, "OS")) {
2372         ap_server_tokens = SrvTk_OS;
2373     }
2374     else if (!strcasecmp(arg, "Min") || !strcasecmp(arg, "Minimal")) {
2375         ap_server_tokens = SrvTk_MIN;
2376     }
2377     else if (!strcasecmp(arg, "Prod") || !strcasecmp(arg, "ProductOnly")) {
2378         ap_server_tokens = SrvTk_PRODUCT_ONLY;
2379     }
2380     else {
2381         ap_server_tokens = SrvTk_FULL;
2382     }
2383     return NULL;
2384 }
2385
2386 static const char *set_limit_req_line(cmd_parms *cmd, void *dummy,
2387                                       const char *arg)
2388 {
2389     const char *err = ap_check_cmd_context(cmd,
2390                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2391     int lim;
2392
2393     if (err != NULL) {
2394         return err;
2395     }
2396     lim = atoi(arg);
2397     if (lim < 0) {
2398         return apr_pstrcat(cmd->temp_pool, "LimitRequestLine \"", arg, 
2399                           "\" must be a non-negative integer", NULL);
2400     }
2401     if (lim > DEFAULT_LIMIT_REQUEST_LINE) {
2402         return apr_psprintf(cmd->temp_pool, "LimitRequestLine \"%s\" "
2403                            "must not exceed the precompiled maximum of %d",
2404                            arg, DEFAULT_LIMIT_REQUEST_LINE);
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     lim = atoi(arg);
2421     if (lim < 0) {
2422         return apr_pstrcat(cmd->temp_pool, "LimitRequestFieldsize \"", arg, 
2423                           "\" must be a non-negative integer (0 = no limit)",
2424                           NULL);
2425     }
2426     if (lim > DEFAULT_LIMIT_REQUEST_FIELDSIZE) {
2427         return apr_psprintf(cmd->temp_pool, "LimitRequestFieldsize \"%s\" "
2428                           "must not exceed the precompiled maximum of %d",
2429                            arg, DEFAULT_LIMIT_REQUEST_FIELDSIZE);
2430     }
2431     cmd->server->limit_req_fieldsize = lim;
2432     return NULL;
2433 }
2434
2435 static const char *set_limit_req_fields(cmd_parms *cmd, void *dummy,
2436                                         const char *arg)
2437 {
2438     const char *err = ap_check_cmd_context(cmd,
2439                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2440     int lim;
2441
2442     if (err != NULL) {
2443         return err;
2444     }
2445     lim = atoi(arg);
2446     if (lim < 0) {
2447         return apr_pstrcat(cmd->temp_pool, "LimitRequestFields \"", arg, 
2448                           "\" must be a non-negative integer (0 = no limit)",
2449                           NULL);
2450     }
2451     cmd->server->limit_req_fields = lim;
2452     return NULL;
2453 }
2454
2455 static const char *set_limit_req_body(cmd_parms *cmd, void *conf_,
2456                                       const char *arg) 
2457 {
2458     core_dir_config *conf=conf_;
2459     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2460     if (err != NULL) {
2461         return err;
2462     }
2463
2464     /* WTF: If strtoul is not portable, then write a replacement.
2465      *      Instead we have an idiotic define in httpd.h that prevents
2466      *      it from being used even when it is available. Sheesh.
2467      */
2468     conf->limit_req_body = (unsigned long)strtol(arg, (char **)NULL, 10);
2469     return NULL;
2470 }
2471
2472 static const char *set_limit_xml_req_body(cmd_parms *cmd, void *conf_,
2473                                           const char *arg) 
2474 {
2475     core_dir_config *conf = conf_;
2476     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2477     if (err != NULL) {
2478         return err;
2479     }
2480
2481     conf->limit_xml_body = atol(arg);
2482     if (conf->limit_xml_body < 0)
2483         return "LimitXMLRequestBody requires a non-negative integer.";
2484
2485     return NULL;
2486 }
2487
2488 AP_DECLARE(size_t) ap_get_limit_xml_body(const request_rec *r)
2489 {
2490     core_dir_config *conf;
2491
2492     conf = ap_get_module_config(r->per_dir_config, &core_module);
2493     if (conf->limit_xml_body == AP_LIMIT_UNSET)
2494         return AP_DEFAULT_LIMIT_XML_BODY;
2495     return (size_t)conf->limit_xml_body;
2496 }
2497
2498 #ifdef WIN32
2499 static const char *set_interpreter_source(cmd_parms *cmd, core_dir_config *d,
2500                                                 char *arg)
2501 {
2502     if (!strcasecmp(arg, "registry")) {
2503         d->script_interpreter_source = INTERPRETER_SOURCE_REGISTRY;
2504     } else if (!strcasecmp(arg, "registry-strict")) {
2505         d->script_interpreter_source = INTERPRETER_SOURCE_REGISTRY_STRICT;
2506     } else if (!strcasecmp(arg, "script")) {
2507         d->script_interpreter_source = INTERPRETER_SOURCE_SHEBANG;
2508     } else {
2509         return apr_pstrcat(cmd->temp_pool, "ScriptInterpreterSource \"", arg, 
2510                           "\" must be \"registry\", \"registry-strict\" or "
2511                           "\"script\"", NULL);
2512     }
2513     return NULL;
2514 }
2515 #endif
2516
2517 #if !defined (RLIMIT_CPU) || !(defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)) || !defined (RLIMIT_NPROC)
2518 static const char *no_set_limit(cmd_parms *cmd, void *conf_,
2519                                 const char *arg, const char *arg2)
2520 {
2521     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, cmd->server,
2522                 "%s not supported on this platform", cmd->cmd->name);
2523     return NULL;
2524 }
2525 #endif
2526
2527 #ifdef RLIMIT_CPU
2528 static const char *set_limit_cpu(cmd_parms *cmd, void *conf_,
2529                                  const char *arg, const char *arg2)
2530 {
2531     core_dir_config *conf=conf_;
2532
2533     unixd_set_rlimit(cmd, &conf->limit_cpu, arg, arg2, RLIMIT_CPU);
2534     return NULL;
2535 }
2536 #endif
2537
2538 #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)
2539 static const char *set_limit_mem(cmd_parms *cmd, void *conf_,
2540                                  const char *arg, const char * arg2)
2541 {
2542     core_dir_config *conf=conf_;
2543
2544 #if defined(RLIMIT_AS)
2545     unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2 ,RLIMIT_AS);
2546 #elif defined(RLIMIT_DATA)
2547     unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_DATA);
2548 #elif defined(RLIMIT_VMEM)
2549     unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_VMEM);
2550 #endif
2551     return NULL;
2552 }
2553 #endif
2554
2555 #ifdef RLIMIT_NPROC
2556 static const char *set_limit_nproc(cmd_parms *cmd, void *conf_,
2557                                    const char *arg, const char * arg2)
2558 {
2559     core_dir_config *conf=conf_;
2560
2561     unixd_set_rlimit(cmd, &conf->limit_nproc, arg, arg2, RLIMIT_NPROC);
2562     return NULL;
2563 }
2564 #endif
2565
2566 static apr_status_t writev_it_all(apr_socket_t *s, struct iovec *vec, int nvec, 
2567                                   apr_ssize_t len, apr_ssize_t *nbytes)
2568 {
2569     apr_size_t bytes_written = 0;
2570     apr_status_t rv;
2571     apr_ssize_t n = len;
2572     apr_ssize_t i = 0;
2573
2574     *nbytes = 0;
2575
2576     /* XXX handle checking for non-blocking socket */
2577     while (bytes_written != len) {
2578         rv = apr_sendv(s, vec + i, nvec - i, &n);
2579         bytes_written += n;
2580         if (rv != APR_SUCCESS)
2581             return rv;
2582         *nbytes += n;
2583
2584         /* If the write did not complete, adjust the iovecs and issue
2585          * apr_sendv again
2586          */
2587         if (bytes_written < len) {
2588             /* Skip over the vectors that have already been written */
2589             apr_size_t cnt = vec[i].iov_len;
2590             while (n >= cnt && i + 1 < nvec) {
2591                 i++;
2592                 cnt += vec[i].iov_len;
2593             }
2594             if (n < cnt) {
2595                 /* Handle partial write of vec i */
2596                 vec[i].iov_base = (char *) vec[i].iov_base + 
2597                     (vec[i].iov_len - (cnt - n));
2598                 vec[i].iov_len = cnt -n;
2599             }
2600         }
2601         n = len - bytes_written;
2602     }
2603
2604     return APR_SUCCESS;
2605 }
2606 /*
2607  * send_the_file()
2608  * Sends the contents of file fd along with header/trailer bytes, if any,
2609  * to the network. send_the_file will return only when all the bytes have been
2610  * sent (i.e., it handles partial writes) or on a network error condition.
2611  */
2612 static apr_status_t send_the_file(conn_rec *c, apr_file_t *fd, 
2613                                   apr_hdtr_t *hdtr, apr_off_t offset, 
2614                                   apr_ssize_t length, apr_ssize_t *nbytes) 
2615 {
2616     apr_status_t rv = APR_SUCCESS;
2617     apr_int32_t togo;         /* Remaining number of bytes in the file to send */
2618     apr_ssize_t sendlen = 0;
2619     apr_ssize_t bytes_sent;
2620     apr_int32_t i;
2621     apr_off_t o;              /* Track the file offset for partial writes */
2622     char buffer[8192];
2623
2624     *nbytes = 0;
2625
2626     /* Send the headers 
2627      * writev_it_all handles partial writes.
2628      * XXX: optimization... if headers are less than MIN_WRITE_SIZE, copy 
2629      * them into buffer
2630      */
2631     if ( hdtr && hdtr->numheaders > 0 ) {
2632         for (i = 0; i < hdtr->numheaders; i++) {
2633             sendlen += hdtr->headers[i].iov_len;
2634         }
2635         rv = writev_it_all(c->client_socket, hdtr->headers, hdtr->numheaders,
2636                            sendlen, &bytes_sent);
2637         if (rv == APR_SUCCESS)
2638             *nbytes += bytes_sent;     /* track total bytes sent */
2639     }
2640
2641     /* Seek the file to 'offset' */
2642     if (offset != 0 && rv == APR_SUCCESS) {
2643         rv = apr_seek(fd, APR_SET, &offset);
2644     }
2645
2646     /* Send the file, making sure to handle partial writes */
2647     togo = length;
2648     while (rv == APR_SUCCESS && togo) {
2649         sendlen = togo > sizeof(buffer) ? sizeof(buffer) : togo;
2650         o = 0;
2651         rv = apr_read(fd, buffer, &sendlen);
2652         while (rv == APR_SUCCESS && sendlen) {
2653             bytes_sent = sendlen;
2654             rv = apr_send(c->client_socket, &buffer[o], &bytes_sent);
2655             if (rv == APR_SUCCESS) {
2656                 sendlen -= bytes_sent; /* sendlen != bytes_sent ==> partial write */
2657                 o += bytes_sent;       /* o is where we are in the buffer */
2658                 *nbytes += bytes_sent;
2659                 togo -= bytes_sent;    /* track how much of the file we've sent */
2660             }
2661         }
2662     }
2663
2664     /* Send the trailers 
2665      * XXX: optimization... if it will fit, send this on the last send in the 
2666      * loop above
2667      */
2668     sendlen = 0;
2669     if ( rv == APR_SUCCESS && hdtr && hdtr->numtrailers > 0 ) {
2670         for (i = 0; i < hdtr->numtrailers; i++) {
2671             sendlen += hdtr->trailers[i].iov_len;
2672         }
2673         rv = writev_it_all(c->client_socket, hdtr->trailers, hdtr->numtrailers,
2674                            sendlen, &bytes_sent);
2675         if (rv == APR_SUCCESS)
2676             *nbytes += bytes_sent;
2677     }
2678
2679     return rv;
2680 }
2681
2682 /* Note --- ErrorDocument will now work from .htaccess files.  
2683  * The AllowOverride of Fileinfo allows webmasters to turn it off
2684  */
2685
2686 static const command_rec core_cmds[] = {
2687
2688 /* Old access config file commands */
2689
2690 AP_INIT_RAW_ARGS("<Directory", dirsection, NULL, RSRC_CONF, 
2691   "Container for directives affecting resources located in the specified "
2692   "directories"),
2693 AP_INIT_RAW_ARGS("<Location", urlsection, NULL, RSRC_CONF,
2694   "Container for directives affecting resources accessed through the "
2695   "specified URL paths"),
2696 AP_INIT_RAW_ARGS("<VirtualHost", virtualhost_section, NULL, RSRC_CONF,
2697   "Container to map directives to a particular virtual host, takes one or "
2698   "more host addresses"),
2699 AP_INIT_RAW_ARGS("<Files", filesection, NULL, OR_ALL,
2700   "Container for directives affecting files matching specified patterns"),
2701 AP_INIT_RAW_ARGS("<Limit", ap_limit_section, NULL, OR_ALL,
2702   "Container for authentication directives when accessed using specified HTTP "
2703   "methods"),
2704 AP_INIT_RAW_ARGS("<LimitExcept", ap_limit_section, (void*)1, OR_ALL,
2705   "Container for authentication directives to be applied when any HTTP "
2706   "method other than those specified is used to access the resource"),
2707 AP_INIT_TAKE1("<IfModule", start_ifmod, NULL, EXEC_ON_READ | OR_ALL,
2708   "Container for directives based on existance of specified modules"),
2709 AP_INIT_TAKE1("<IfDefine", start_ifdefine, NULL, EXEC_ON_READ | OR_ALL,
2710   "Container for directives based on existance of command line defines"),
2711 AP_INIT_RAW_ARGS("<DirectoryMatch", dirsection, (void*)1, RSRC_CONF,
2712   "Container for directives affecting resources located in the "
2713   "specified directories"),
2714 AP_INIT_RAW_ARGS("<LocationMatch", urlsection, (void*)1, RSRC_CONF,
2715   "Container for directives affecting resources accessed through the "
2716   "specified URL paths"),
2717 AP_INIT_RAW_ARGS("<FilesMatch", filesection, (void*)1, OR_ALL,
2718   "Container for directives affecting files matching specified patterns"),
2719 AP_INIT_TAKE1("AuthType", ap_set_string_slot,
2720   (void*)XtOffsetOf(core_dir_config, ap_auth_type), OR_AUTHCFG, 
2721   "An HTTP authorization type (e.g., \"Basic\")"),
2722 AP_INIT_TAKE1("AuthName", set_authname, NULL, OR_AUTHCFG,
2723   "The authentication realm (e.g. \"Members Only\")"),
2724 AP_INIT_RAW_ARGS("Require", require, NULL, OR_AUTHCFG,
2725   "Selects which authenticated users or groups may access a protected space"),
2726 AP_INIT_TAKE1("Satisfy", satisfy, NULL, OR_AUTHCFG,
2727   "access policy if both allow and require used ('all' or 'any')"),
2728 #ifdef GPROF
2729 AP_INIT_TAKE1("GprofDir", set_gprof_dir, NULL, RSRC_CONF,
2730   "Directory to plop gmon.out files"),
2731 #endif
2732 AP_INIT_TAKE1("AddDefaultCharset", set_add_default_charset, NULL, OR_FILEINFO, 
2733   "The name of the default charset to add to any Content-Type without one or 'Off' to disable"),
2734
2735 /* Old resource config file commands */
2736   
2737 AP_INIT_RAW_ARGS("AccessFileName", set_access_name, NULL, RSRC_CONF,
2738   "Name(s) of per-directory config files (default: .htaccess)"),
2739 AP_INIT_TAKE1("DocumentRoot", set_document_root, NULL, RSRC_CONF,
2740   "Root directory of the document tree"),
2741 AP_INIT_TAKE2("ErrorDocument", set_error_document, NULL, OR_FILEINFO,
2742   "Change responses for HTTP errors"),
2743 AP_INIT_RAW_ARGS("AllowOverride", set_override, NULL, ACCESS_CONF,
2744   "Controls what groups of directives can be configured by per-directory "
2745   "config files"),
2746 AP_INIT_RAW_ARGS("Options", set_options, NULL, OR_OPTIONS,
2747   "Set a number of attributes for a given directory"),
2748 AP_INIT_TAKE1("DefaultType", ap_set_string_slot,
2749   (void*)XtOffsetOf (core_dir_config, ap_default_type),
2750   OR_FILEINFO, "the default MIME type for untypable files"),
2751
2752 /* Old server config file commands */
2753
2754 AP_INIT_TAKE1("Port", server_port, NULL, RSRC_CONF, "A TCP port number"),
2755 AP_INIT_TAKE1("HostnameLookups", set_hostname_lookups, NULL,
2756   ACCESS_CONF|RSRC_CONF,
2757   "\"on\" to enable, \"off\" to disable reverse DNS lookups, or \"double\" to "
2758   "enable double-reverse DNS lookups"),
2759 AP_INIT_TAKE1("ServerAdmin", set_server_string_slot,
2760   (void *)XtOffsetOf (server_rec, server_admin), RSRC_CONF,
2761   "The email address of the server administrator"),
2762 AP_INIT_TAKE1("ServerName", set_server_string_slot,
2763   (void *)XtOffsetOf (server_rec, server_hostname), RSRC_CONF,
2764   "The hostname of the server"),
2765 AP_INIT_TAKE1("ServerSignature", set_signature_flag, NULL, OR_ALL,
2766   "En-/disable server signature (on|off|email)"),
2767 AP_INIT_TAKE1("ServerRoot", set_server_root, NULL, RSRC_CONF,
2768   "Common directory of server-related files (logs, confs, etc.)"),
2769 AP_INIT_TAKE1("ErrorLog", set_server_string_slot,
2770   (void *)XtOffsetOf (server_rec, error_fname), RSRC_CONF,
2771   "The filename of the error log"),
2772 AP_INIT_RAW_ARGS("ServerAlias", set_server_alias, NULL, RSRC_CONF,
2773   "A name or names alternately used to access the server"),
2774 AP_INIT_TAKE1("ServerPath", set_serverpath, NULL, RSRC_CONF,
2775   "The pathname the server can be reached at"),
2776 AP_INIT_TAKE1("Timeout", set_timeout, NULL, RSRC_CONF,
2777   "Timeout duration (sec)"),
2778 AP_INIT_TAKE1("KeepAliveTimeout", set_keep_alive_timeout, NULL, RSRC_CONF,
2779   "Keep-Alive timeout duration (sec)"),
2780 AP_INIT_TAKE1("MaxKeepAliveRequests", set_keep_alive_max, NULL, RSRC_CONF,
2781   "Maximum number of Keep-Alive requests per connection, or 0 for infinite"),
2782 AP_INIT_TAKE1("KeepAlive", set_keep_alive, NULL, RSRC_CONF,
2783   "Whether persistent connections should be On or Off"),
2784 AP_INIT_FLAG("IdentityCheck", set_idcheck, NULL, RSRC_CONF|ACCESS_CONF,
2785   "Enable identd (RFC 1413) user lookups - SLOW"),
2786 AP_INIT_FLAG("ContentDigest", set_content_md5, NULL, OR_OPTIONS,
2787   "whether or not to send a Content-MD5 header with each request"),
2788 AP_INIT_TAKE1("UseCanonicalName", set_use_canonical_name, NULL,
2789   RSRC_CONF|ACCESS_CONF,
2790   "How to work out the ServerName : Port when constructing URLs"),
2791 /* TODO: RlimitFoo should all be part of mod_cgi, not in the core */
2792 AP_INIT_ITERATE("AddModule", add_module_command, NULL,
2793   RSRC_CONF, "The name of a module"),
2794 AP_INIT_NO_ARGS("ClearModuleList", clear_module_list_command, NULL,
2795   RSRC_CONF, NULL),
2796 /* TODO: ListenBacklog in MPM */
2797 AP_INIT_TAKE1("Include", include_config, NULL,
2798   (RSRC_CONF | ACCESS_CONF | EXEC_ON_READ),
2799   "Name of the config file to be included"),
2800 AP_INIT_TAKE1("LogLevel", set_loglevel, NULL, RSRC_CONF,
2801   "Level of verbosity in error logging"),
2802 AP_INIT_TAKE1("NameVirtualHost", ap_set_name_virtual_host, NULL, RSRC_CONF,
2803   "A numeric IP address:port, or the name of a host"),
2804 #ifdef _OSD_POSIX
2805 AP_INIT_TAKE1("BS2000Account", set_bs2000_account, NULL, RSRC_CONF,
2806   "Name of server User's bs2000 logon account name"),
2807 #endif
2808 #ifdef WIN32
2809 AP_INIT_TAKE1("ScriptInterpreterSource", set_interpreter_source, NULL,
2810   OR_FILEINFO,
2811   "Where to find interpreter to run Win32 scripts (Registry or script shebang line)"),
2812 #endif
2813 AP_INIT_TAKE1("ServerTokens", set_serv_tokens, NULL, RSRC_CONF,
2814   "Determine tokens displayed in the Server: header - Min(imal), OS or Full"),
2815 AP_INIT_TAKE1("LimitRequestLine", set_limit_req_line, NULL, RSRC_CONF,
2816   "Limit on maximum size of an HTTP request line"),
2817 AP_INIT_TAKE1("LimitRequestFieldsize", set_limit_req_fieldsize, NULL,
2818   RSRC_CONF,
2819   "Limit on maximum size of an HTTP request header field"),
2820 AP_INIT_TAKE1("LimitRequestFields", set_limit_req_fields, NULL, RSRC_CONF,
2821   "Limit (0 = unlimited) on max number of header fields in a request message"),
2822 AP_INIT_TAKE1("LimitRequestBody", set_limit_req_body,
2823   (void*)XtOffsetOf(core_dir_config, limit_req_body), OR_ALL,
2824   "Limit (in bytes) on maximum size of request message body"),
2825 AP_INIT_TAKE1("LimitXMLRequestBody", set_limit_xml_req_body, NULL, OR_ALL,
2826               "Limit (in bytes) on maximum size of an XML-based request "
2827               "body"),
2828
2829 /* System Resource Controls */
2830 #ifdef RLIMIT_CPU
2831 AP_INIT_TAKE12("RLimitCPU", set_limit_cpu,
2832   (void*)XtOffsetOf(core_dir_config, limit_cpu),
2833   OR_ALL, "Soft/hard limits for max CPU usage in seconds"),
2834 #else
2835 AP_INIT_TAKE12("RLimitCPU", no_set_limit, NULL,
2836   OR_ALL, "Soft/hard limits for max CPU usage in seconds"),
2837 #endif
2838 #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined (RLIMIT_AS)
2839 AP_INIT_TAKE12("RLimitMEM", set_limit_mem,
2840   (void*)XtOffsetOf(core_dir_config, limit_mem),
2841   OR_ALL, "Soft/hard limits for max memory usage per process"),
2842 #else
2843 AP_INIT_TAKE12("RLimitMEM", no_set_limit, NULL,
2844   OR_ALL, "Soft/hard limits for max memory usage per process"),
2845 #endif
2846 #ifdef RLIMIT_NPROC
2847 AP_INIT_TAKE12("RLimitNPROC", set_limit_nproc,
2848   (void*)XtOffsetOf(core_dir_config, limit_nproc),
2849   OR_ALL, "soft/hard limits for max number of processes per uid"),
2850 #else
2851 AP_INIT_TAKE12("RLimitNPROC", no_set_limit, NULL,
2852    OR_ALL, "soft/hard limits for max number of processes per uid"),
2853 #endif
2854 /* XXX These should be allowable in .htaccess files, but currently it won't
2855  * play well with the Options stuff.  Until that is fixed, I would prefer
2856  * to leave it just in the conf file.  Other should feel free to disagree
2857  * with me.  Rbb.
2858  */
2859 AP_INIT_ITERATE("AddOutputFilter", add_filter, NULL, ACCESS_CONF,
2860    "filters to be run"),
2861 AP_INIT_ITERATE("AddInputFilter", add_input_filter, NULL, ACCESS_CONF,
2862    "filters to be run on the request body"),
2863 { NULL }
2864 };
2865
2866 /*****************************************************************
2867  *
2868  * Core handlers for various phases of server operation...
2869  */
2870
2871 AP_DECLARE_NONSTD(int) ap_core_translate(request_rec *r)
2872 {
2873     void *sconf = r->server->module_config;
2874     core_server_config *conf = ap_get_module_config(sconf, &core_module);
2875   
2876     if (r->proxyreq) {
2877         return HTTP_FORBIDDEN;
2878     }
2879     if ((r->uri[0] != '/') && strcmp(r->uri, "*")) {
2880         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
2881                      "Invalid URI in request %s", r->the_request);
2882         return HTTP_BAD_REQUEST;
2883     }
2884     
2885     if (r->server->path 
2886         && !strncmp(r->uri, r->server->path, r->server->pathlen)
2887         && (r->server->path[r->server->pathlen - 1] == '/'
2888             || r->uri[r->server->pathlen] == '/'
2889             || r->uri[r->server->pathlen] == '\0')) {
2890         r->filename = apr_pstrcat(r->pool, conf->ap_document_root,
2891                                  (r->uri + r->server->pathlen), NULL);
2892     }
2893     else {
2894         /*
2895          * Make sure that we do not mess up the translation by adding two
2896          * /'s in a row.  This happens under windows when the document
2897          * root ends with a /
2898          */
2899         if ((conf->ap_document_root[strlen(conf->ap_document_root)-1] == '/')
2900             && (*(r->uri) == '/')) {
2901             r->filename = apr_pstrcat(r->pool, conf->ap_document_root, r->uri+1,
2902                                      NULL);
2903         }
2904         else {
2905             r->filename = apr_pstrcat(r->pool, conf->ap_document_root, r->uri,
2906                                      NULL);
2907         }
2908     }
2909
2910     return OK;
2911 }
2912
2913 static int do_nothing(request_rec *r) { return OK; }
2914
2915 /*
2916  * Default handler for MIME types without other handlers.  Only GET
2917  * and OPTIONS at this point... anyone who wants to write a generic
2918  * handler for PUT or POST is free to do so, but it seems unwise to provide
2919  * any defaults yet... So, for now, we assume that this will always be
2920  * the last handler called and return 405 or 501.
2921  */
2922
2923 static int default_handler(request_rec *r)
2924 {
2925     core_dir_config *d =
2926             (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
2927     int rangestatus, errstatus;
2928     apr_file_t *fd = NULL;
2929     apr_status_t status;
2930 #ifdef AP_USE_MMAP_FILES
2931     apr_mmap_t *mm = NULL;
2932 #endif
2933     /* XXX if/when somebody writes a content-md5 filter we either need to
2934      *     remove this support or coordinate when to use the filter vs.
2935      *     when to use this code
2936      *     The current choice of when to compute the md5 here matches the 1.3
2937      *     support fairly closely (unlike 1.3, we don't handle computing md5
2938      *     when the charset is translated).
2939      */
2940     int bld_content_md5 = 
2941         (d->content_md5 & 1) && r->output_filters->frec->ftype != AP_FTYPE_CONTENT;
2942
2943     /* This handler has no use for a request body (yet), but we still
2944      * need to read and discard it if the client sent one.
2945      */
2946     if ((errstatus = ap_discard_request_body(r)) != OK) {
2947         return errstatus;
2948     }
2949
2950     ap_allow_methods(r, MERGE_ALLOW, "GET", "OPTIONS", NULL);
2951
2952     if (r->method_number == M_INVALID) {
2953         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
2954                     "Invalid method in request %s", r->the_request);
2955         return HTTP_NOT_IMPLEMENTED;
2956     }
2957     if (r->method_number == M_OPTIONS) {
2958         return ap_send_http_options(r);
2959     }
2960     if (r->method_number == M_PUT) {
2961         return HTTP_METHOD_NOT_ALLOWED;
2962     }
2963     if (r->finfo.protection == 0 || (r->path_info && *r->path_info)) {
2964         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r,
2965                       "File does not exist: %s",r->path_info ?
2966                       apr_pstrcat(r->pool, r->filename, r->path_info, NULL)
2967                       : r->filename);
2968         return HTTP_NOT_FOUND;
2969     }
2970     if (r->method_number != M_GET) {
2971         return HTTP_METHOD_NOT_ALLOWED;
2972     }
2973         
2974     if ((status = apr_open(&fd, r->filename, APR_READ | APR_BINARY, 0, r->pool)) != APR_SUCCESS) {
2975         ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
2976                      "file permissions deny server access: %s", r->filename);
2977         return HTTP_FORBIDDEN;
2978     }
2979     ap_update_mtime(r, r->finfo.mtime);
2980     ap_set_last_modified(r);
2981     ap_set_etag(r);
2982     apr_table_setn(r->headers_out, "Accept-Ranges", "bytes");
2983     if (((errstatus = ap_meets_conditions(r)) != OK)
2984         || (errstatus = ap_set_content_length(r, r->finfo.size))) {
2985         apr_close(fd);
2986         return errstatus;
2987     }
2988
2989 #ifdef AP_USE_MMAP_FILES
2990     if ((r->finfo.size >= MMAP_THRESHOLD)
2991         && (r->finfo.size < MMAP_LIMIT)
2992         && (!r->header_only || bld_content_md5)) {
2993         /* we need to protect ourselves in case we die while we've got the
2994          * file mmapped */
2995         apr_status_t status;
2996         if ((status = apr_mmap_create(&mm, fd, 0, r->finfo.size, r->pool)) != APR_SUCCESS) {
2997             ap_log_rerror(APLOG_MARK, APLOG_CRIT, status, r,
2998                          "default_handler: mmap failed: %s", r->filename);
2999             mm = NULL;
3000         }
3001     }
3002     else {
3003         mm = NULL;
3004     }
3005
3006     if (mm == NULL) {
3007 #endif
3008
3009         if (bld_content_md5) {
3010             apr_table_setn(r->headers_out, "Content-MD5",
3011                            ap_md5digest(r->pool, fd));
3012         }
3013
3014         rangestatus = ap_set_byterange(r);
3015
3016         ap_send_http_header(r);
3017         
3018         if (!r->header_only) {
3019             apr_size_t length = r->finfo.size;
3020             apr_off_t  offset = 0;
3021             apr_size_t nbytes = 0;
3022
3023             if (!rangestatus) {
3024                 ap_send_fd(fd, r, offset, length, &nbytes);
3025             }
3026             else {
3027                 while (ap_each_byterange(r, &offset, &length)) {
3028                     if ((status = ap_send_fd(fd, r, offset, length, &nbytes)) != APR_SUCCESS) {
3029                         ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
3030                                   "error byteserving file: %s", r->filename);
3031                         return HTTP_INTERNAL_SERVER_ERROR;
3032                     }
3033                 }
3034             }
3035         }
3036
3037 #ifdef AP_USE_MMAP_FILES
3038     }
3039     else {
3040         unsigned char *addr;
3041         apr_mmap_offset((void**)&addr, mm ,0);
3042
3043         if (bld_content_md5) {
3044             apr_md5_ctx_t context;
3045             
3046             apr_MD5Init(&context);
3047             apr_MD5Update(&context, addr, (unsigned int)r->finfo.size);
3048             apr_table_setn(r->headers_out, "Content-MD5",
3049                           ap_md5contextTo64(r->pool, &context));
3050         }
3051
3052         rangestatus = ap_set_byterange(r);
3053         ap_send_http_header(r);
3054         
3055         if (!r->header_only) {
3056             if (!rangestatus) {
3057                 ap_send_mmap(mm, r, 0, r->finfo.size);
3058             }
3059             else {
3060                 apr_off_t offset;
3061                 apr_size_t length;
3062                 while (ap_each_byterange(r, &offset, &length)) {
3063                     ap_send_mmap(mm, r, offset, length);
3064                 }
3065             }
3066         }
3067     }
3068 #endif
3069
3070     apr_close(fd);
3071     return OK;
3072 }
3073 /*
3074  * coalesce_filter()
3075  * This is a simple filter to coalesce many small buckets into one large
3076  * bucket. 
3077  *
3078  * Note:
3079  * This implementation of coalesce_filter will only coalesce a single
3080  * contiguous string of coalesable buckets. It will not coalesce multiple
3081  * non-contiguous buckets. For example, if a brigade contains 10 small 
3082  * buckets followed by a large bucket (or a pipe or file bucket) followed 
3083  * by more small buckets, only the first 10 buckets will be coalesced.
3084  */
3085 typedef struct COALESCE_FILTER_CTX {
3086     char *buf;           /* Start of buffer */
3087     char *cur;           /* Pointer to next location to write */
3088     apr_ssize_t cnt;     /* Number of bytes put in buf */
3089     apr_ssize_t avail;   /* Number of bytes available in the buf */
3090 } coalesce_filter_ctx_t;
3091 #define FILTER_BUFF_SIZE 8192
3092 #define MIN_BUCKET_SIZE 200
3093 static apr_status_t coalesce_filter(ap_filter_t *f, ap_bucket_brigade *b)
3094 {
3095     apr_status_t rv;
3096     apr_pool_t *p = f->r->pool;
3097     ap_bucket *e, *insert_before = NULL, *destroy_me = NULL;
3098     coalesce_filter_ctx_t *ctx = f->ctx;
3099     int pass_the_brigade = 0, insert_first = 0;
3100
3101     if (ctx == NULL) {
3102         f->ctx = ctx = apr_pcalloc(p, sizeof(coalesce_filter_ctx_t));
3103         ctx->avail = FILTER_BUFF_SIZE;
3104     }
3105
3106     if (ctx->cnt) {
3107         insert_first = 1;
3108     }
3109
3110     /* Iterate across the buckets, coalescing the small buckets into a 
3111      * single buffer 
3112      */
3113     AP_BRIGADE_FOREACH(e, b) {
3114         if (destroy_me) {
3115             ap_bucket_destroy(destroy_me);
3116             destroy_me = NULL;
3117         }
3118         if (AP_BUCKET_IS_EOS(e)  || AP_BUCKET_IS_FILE(e) ||
3119             AP_BUCKET_IS_PIPE(e) || AP_BUCKET_IS_FLUSH(e)) {
3120             pass_the_brigade = 1;
3121         }
3122         else {
3123             const char *str;
3124             apr_ssize_t n;
3125             rv = ap_bucket_read(e, &str, &n, 0);
3126             if (rv != APR_SUCCESS) {
3127                 /* XXX: log error */
3128                 return rv;
3129             }
3130             if ((n < MIN_BUCKET_SIZE) && (n < ctx->avail)) {
3131                 /* Coalesce this bucket into the buffer */
3132                 if (ctx->buf == NULL) {
3133                     ctx->buf = apr_palloc(p, FILTER_BUFF_SIZE);
3134                     ctx->cur = ctx->buf;
3135                     ctx->cnt = 0;
3136                 }
3137                 memcpy(ctx->cur, str, n);
3138                 ctx->cnt += n;
3139                 ctx->cur += n;
3140                 ctx->avail -= n;
3141                 /* If this is the first bucket to be coalesced, don't remove it 
3142                  * from the brigade. Save it as a marker for where to insert 
3143                  * ctx->buf into the brigade when we're done.
3144                  */
3145                 if (insert_before || insert_first){
3146                     AP_BUCKET_REMOVE(e);
3147                     destroy_me = e;
3148                 }
3149                 else {
3150                     insert_before = e;
3151                 }
3152             } 
3153             else if (insert_before || insert_first) {
3154                 /* This bucket was not able to be coalesced because it either
3155                  * exceeds MIN_BUCKET_SIZE or its contents will not fit into
3156                  * buf. We're done...
3157                  */
3158                 pass_the_brigade = 1;
3159                 break;
3160             }
3161             else {
3162                 /* If there is even a single bucket that cannot be coalesced, 
3163                  * then we must pass the brigade down to the next filter.
3164                  */
3165                 pass_the_brigade = 1;
3166             }
3167         }
3168     }
3169
3170     if (destroy_me) {
3171         ap_bucket_destroy(destroy_me);
3172         destroy_me = NULL;
3173     }
3174
3175     if (pass_the_brigade) {
3176         /* Insert ctx->buf into the correct spotin the brigade */
3177         if (insert_first) {
3178             e = ap_bucket_create_pool(ctx->buf, ctx->cnt, p);
3179             AP_BRIGADE_INSERT_HEAD(b, e);
3180         } 
3181         else if (insert_before) {
3182             e = ap_bucket_create_pool(ctx->buf, ctx->cnt, p);
3183             AP_BUCKET_INSERT_BEFORE(e, insert_before);
3184             AP_BUCKET_REMOVE(insert_before);
3185             ap_bucket_destroy(insert_before);
3186             insert_before = NULL;
3187         }
3188         rv = ap_pass_brigade(f->next, b);
3189         if (rv != APR_SUCCESS) {
3190             /* XXX: Log the error */
3191             return rv;
3192         }
3193         /* Get ctx->buf ready for the next brigade */
3194         if (ctx) {
3195             ctx->cur = ctx->buf;
3196             ctx->cnt = 0;
3197             ctx->avail = FILTER_BUFF_SIZE;
3198         }
3199     }
3200     else {
3201         if (insert_before) {
3202             AP_BUCKET_REMOVE(insert_before);
3203             ap_bucket_destroy(insert_before);
3204         }
3205         /* The brigade should be empty now because all the buckets
3206          * were coalesced into the coalesce_filter buf
3207          */
3208     }
3209
3210     return APR_SUCCESS;
3211 }
3212 /*
3213  * HTTP/1.1 chunked transfer encoding filter.
3214  */
3215 static apr_status_t chunk_filter(ap_filter_t *f, ap_bucket_brigade *b)
3216 {
3217 #define ASCII_CRLF  "\015\012"
3218 #define ASCII_ZERO  "\060"
3219     ap_bucket_brigade *more = NULL;
3220     ap_bucket *e;
3221     apr_status_t rv;
3222
3223     for (more = NULL; b; b = more, more = NULL) {
3224         apr_off_t bytes = 0;
3225         ap_bucket *eos = NULL;
3226         char chunk_hdr[20]; /* enough space for the snprintf below */
3227
3228         AP_BRIGADE_FOREACH(e, b) {
3229             if (AP_BUCKET_IS_EOS(e)) {
3230                 /* there shouldn't be anything after the eos */
3231                 eos = e;
3232                 break;
3233             }
3234             else if (e->length == -1) {
3235                 /* unknown amount of data (e.g. a pipe) */
3236                 const char *data;
3237                 apr_ssize_t len;
3238
3239                 rv = ap_bucket_read(e, &data, &len, 1);
3240                 if (rv != APR_SUCCESS) {
3241                     return rv;
3242                 }
3243                 if (len > 0) {
3244                     /*
3245                      * There may be a new next bucket representing the
3246                      * rest of the data stream on which a read() may
3247                      * block so we pass down what we have so far.
3248                      */
3249                     bytes += len;
3250                     more = ap_brigade_split(b, AP_BUCKET_NEXT(e));
3251                     break;
3252                 }
3253                 else {
3254                     /* If there was nothing in this bucket then we can
3255                      * safely move on to the next one without pausing
3256                      * to pass down what we have counted up so far.
3257                      */
3258                     continue;
3259                 }
3260             }
3261             else {
3262                 bytes += e->length;
3263             }
3264         }
3265
3266         /*
3267          * XXX: if there aren't very many bytes at this point it may
3268          * be a good idea to set them aside and return for more,
3269          * unless we haven't finished counting this brigade yet.
3270          */
3271
3272         /* if there are content bytes, then wrap them in a chunk */
3273         if (bytes > 0) {
3274             apr_size_t hdr_len;
3275
3276             /*
3277              * Insert the chunk header, specifying the number of bytes in
3278              * the chunk.
3279              */
3280             /* XXX might be nice to have APR_OFF_T_FMT_HEX */
3281             hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr),
3282                                    "%qx" CRLF, (apr_uint64_t)bytes);
3283             ap_xlate_proto_to_ascii(chunk_hdr, hdr_len);
3284             e = ap_bucket_create_transient(chunk_hdr, hdr_len);
3285             AP_BRIGADE_INSERT_HEAD(b, e);
3286
3287             /*
3288              * Insert the end-of-chunk CRLF before the EOS bucket, or
3289              * appended to the brigade
3290              */
3291             e = ap_bucket_create_immortal(ASCII_CRLF, 2);
3292             if (eos != NULL) {
3293                 AP_BUCKET_INSERT_BEFORE(eos, e);
3294             }
3295             else {
3296                 AP_BRIGADE_INSERT_TAIL(b, e);
3297             }
3298         }
3299
3300         /* RFC 2616, Section 3.6.1
3301          *
3302          * If there is an EOS bucket, then prefix it with:
3303          *   1) the last-chunk marker ("0" CRLF)
3304          *   2) the trailer
3305          *   3) the end-of-chunked body CRLF
3306          *
3307          * If there is no EOS bucket, then do nothing.
3308          *
3309          * XXX: it would be nice to combine this with the end-of-chunk
3310          * marker above, but this is a bit more straight-forward for
3311          * now.
3312          */
3313         if (eos != NULL) {
3314             /* XXX: (2) trailers ... does not yet exist */
3315             e = ap_bucket_create_immortal(ASCII_ZERO ASCII_CRLF /* <trailers> */ ASCII_CRLF, 5);
3316             AP_BUCKET_INSERT_BEFORE(eos, e);
3317         }
3318
3319         /* pass the brigade to the next filter. */
3320         rv = ap_pass_brigade(f->next, b);
3321         if (rv != APR_SUCCESS || eos != NULL) {
3322             return rv;
3323         }
3324     }
3325
3326     return APR_SUCCESS;
3327 }
3328
3329 static int core_input_filter(ap_filter_t *f, ap_bucket_brigade *b, ap_input_mode_t mode)
3330 {
3331     ap_bucket *e;
3332     
3333     if (!f->ctx) {    /* If we haven't passed up the socket yet... */
3334         f->ctx = (void *)1;
3335         e = ap_bucket_create_socket(f->c->client_socket);
3336         AP_BRIGADE_INSERT_TAIL(b, e);
3337         return APR_SUCCESS;
3338     }
3339     else {            
3340         /* Either some code lost track of the socket
3341          * bucket or we already found out that the
3342          * client closed.
3343          */
3344         return APR_EOF;
3345     }
3346 }
3347
3348 /* Default filter.  This filter should almost always be used.  Its only job
3349  * is to send the headers if they haven't already been sent, and then send
3350  * the actual data.
3351  */
3352 typedef struct CORE_OUTPUT_FILTER_CTX {
3353     ap_bucket_brigade *b;
3354 } core_output_filter_ctx_t;
3355 #define MAX_IOVEC_TO_WRITE 16
3356 static apr_status_t core_output_filter(ap_filter_t *f, ap_bucket_brigade *b)
3357 {
3358     apr_status_t rv;
3359     ap_bucket_brigade *more = NULL;
3360     apr_ssize_t bytes_sent = 0, nbytes;
3361     ap_bucket *e;
3362     conn_rec *c = f->c;
3363     core_output_filter_ctx_t *ctx = f->ctx;
3364
3365     apr_ssize_t nvec = 0;
3366     apr_ssize_t nvec_trailers= 0;
3367     struct iovec vec[MAX_IOVEC_TO_WRITE];
3368     struct iovec vec_trailers[MAX_IOVEC_TO_WRITE];
3369
3370     apr_file_t *fd = NULL;
3371     apr_ssize_t flen = 0;
3372     apr_off_t foffset = 0;
3373
3374     if (ctx == NULL) {
3375         f->ctx = ctx = apr_pcalloc(c->pool, sizeof(core_output_filter_ctx_t));
3376     }
3377     /* If we have a saved brigade, concatenate the new brigade to it */
3378     if (ctx->b) {
3379         AP_BRIGADE_CONCAT(ctx->b, b);
3380         b = ctx->b;
3381         ctx->b = NULL;
3382     }
3383
3384     /* Hijack any bytes in BUFF and prepend it to the brigade. */
3385     if (c->client->outcnt) {
3386         e = ap_bucket_create_pool(c->client->outbase,
3387                                   c->client->outcnt, c->client->pool);
3388         c->client->outcnt = 0;
3389         AP_BRIGADE_INSERT_HEAD(b, e);
3390     }
3391
3392     /* Iterate over the brigade collecting iovecs */
3393     while (b) {
3394         nbytes = 0; /* in case more points to another brigade */
3395         more = NULL;
3396         AP_BRIGADE_FOREACH(e, b) {
3397             if (AP_BUCKET_IS_EOS(e) || AP_BUCKET_IS_FLUSH(e)) {
3398                 break;
3399             }
3400             else if (AP_BUCKET_IS_FILE(e)) {
3401                 ap_bucket_file *a = e->data;
3402                 /* Assume there is at most one AP_BUCKET_FILE in the brigade */
3403                 fd = a->fd;
3404                 flen = e->length;
3405                 foffset = a->offset;
3406             }
3407             else {
3408                 const char *str;
3409                 apr_ssize_t n;
3410                 rv = ap_bucket_read(e, &str, &n, 0);
3411                 if (n) {
3412                     nbytes += n;
3413                     if (!fd) {
3414                         vec[nvec].iov_base = (char*) str;
3415                         vec[nvec].iov_len = n;
3416                         nvec++;
3417                     }
3418                     else {
3419                         /* The bucket is a trailer to a file bucket */
3420                         vec_trailers[nvec_trailers].iov_base = (char*) str;
3421                         vec_trailers[nvec_trailers].iov_len = n;
3422                         nvec_trailers++;
3423                     }
3424                 }
3425             }
3426
3427             if ((nvec == MAX_IOVEC_TO_WRITE) || (nvec_trailers == MAX_IOVEC_TO_WRITE)) {
3428                 /* Split the brigade and break */
3429                 if (AP_BUCKET_NEXT(e) != AP_BRIGADE_SENTINEL(b)) {
3430                     more = ap_brigade_split(b, AP_BUCKET_NEXT(e));
3431                 }
3432                 break;
3433             }
3434         }
3435
3436         /* Completed iterating over the brigades, now determine if we want to
3437          * buffer the brigade or send the brigade out on the network
3438          */
3439         if (!fd && (!more) && (nbytes < MIN_SIZE_TO_WRITE) && !AP_BUCKET_IS_EOS(e) && !AP_BUCKET_IS_FLUSH(e)) {
3440             ap_save_brigade(f, &ctx->b, &b);
3441             return APR_SUCCESS;
3442         }
3443         if (fd) {
3444             apr_hdtr_t hdtr;
3445 #if APR_HAS_SENDFILE
3446             apr_int32_t flags = 0;
3447 #endif
3448
3449             memset(&hdtr, '\0', sizeof(hdtr));
3450             if (nvec) {
3451                 hdtr.numheaders = nvec;
3452                 hdtr.headers = vec;
3453             }
3454             if (nvec_trailers) {
3455                 hdtr.numtrailers = nvec_trailers;
3456                 hdtr.trailers = vec_trailers;
3457             }
3458 #if APR_HAS_SENDFILE
3459             if (!c->keepalive) {
3460                 /* Prepare the socket to be reused */
3461                 flags |= APR_SENDFILE_DISCONNECT_SOCKET;
3462             }
3463             nbytes = flen;
3464             rv = apr_sendfile(c->client_socket, 
3465                               fd,       /* The file to send */
3466                               &hdtr,    /* Header and trailer iovecs */
3467                               &foffset, /* Offset in file to begin sending from */
3468                               &nbytes,
3469                               flags);
3470             bytes_sent = nbytes;
3471
3472             /* If apr_sendfile() returns APR_ENOTIMPL, call send_the_file() to
3473              * loop on apr_read/apr_send to send the file. Our Windows binary 
3474              * distributions (which work on Windows 9x/NT) are compiled on 
3475              * Windows NT. TransmitFile is not available on Windows 95/98 and
3476              * we discover this at runtime when apr_sendfile() returns 
3477              * APR_ENOTIMPL. Having apr_sendfile() return APR_ENOTIMPL seems
3478              * the cleanest way to handle this case.
3479              */
3480             if (rv == APR_ENOTIMPL) {
3481 #endif
3482
3483                 rv = send_the_file(c, fd, &hdtr, foffset, flen, &bytes_sent);
3484
3485 #if APR_HAS_SENDFILE
3486             }
3487 #endif
3488         }
3489         else {
3490             rv = writev_it_all(c->client_socket, 
3491                                vec, nvec, 
3492                                nbytes, &bytes_sent);
3493         }
3494
3495         ap_brigade_destroy(b);
3496         if (rv != APR_SUCCESS) {
3497             /* XXX: log the error */
3498             if (more)
3499                 ap_brigade_destroy(more);
3500             return rv;
3501         }
3502         nvec = 0;
3503         nvec_trailers = 0;
3504
3505         b = more;
3506     }  /* end while () */
3507
3508     return APR_SUCCESS;
3509 }
3510
3511 static const handler_rec core_handlers[] = {
3512 { "*/*", default_handler },
3513 { "default-handler", default_handler },
3514 { NULL, NULL }
3515 };
3516
3517 static void core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
3518 {
3519     ap_init_bucket_types(pconf);
3520 }
3521
3522 static void core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
3523 {
3524     ap_set_version(pconf);
3525 }
3526
3527 static void core_open_logs(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
3528 {
3529     ap_open_logs(s, pconf);
3530 }
3531
3532 static const char *core_method(const request_rec *r)
3533     { return "http"; }
3534
3535 static unsigned short core_port(const request_rec *r)
3536     { return DEFAULT_HTTP_PORT; }
3537
3538 static void core_insert_filter(request_rec *r)
3539 {
3540     int i;
3541     core_dir_config *conf = (core_dir_config *)
3542                             ap_get_module_config(r->per_dir_config,
3543                                                    &core_module); 
3544     char **items = (char **)conf->output_filters->elts;
3545
3546     for (i = 0; i < conf->output_filters->nelts; i++) {
3547         char *foobar = items[i];
3548         ap_add_output_filter(foobar, NULL, r, r->connection);
3549     }
3550
3551     items = (char **)conf->input_filters->elts;
3552     for (i = 0; i < conf->input_filters->nelts; i++) {
3553         char *foobar = items[i];
3554         ap_add_input_filter(foobar, NULL, r, r->connection);
3555     }
3556 }
3557
3558 static void register_hooks(void)
3559 {
3560     ap_hook_pre_config(core_pre_config, NULL, NULL, AP_HOOK_REALLY_FIRST);
3561     ap_hook_post_config(core_post_config,NULL,NULL,AP_HOOK_REALLY_FIRST);
3562     ap_hook_translate_name(ap_core_translate,NULL,NULL,AP_HOOK_REALLY_LAST);
3563     ap_hook_pre_connection(ap_pre_http_connection,NULL,NULL,
3564                                AP_HOOK_REALLY_LAST);
3565     ap_hook_process_connection(ap_process_http_connection,NULL,NULL,
3566                                AP_HOOK_REALLY_LAST);
3567     ap_hook_http_method(core_method,NULL,NULL,AP_HOOK_REALLY_LAST);
3568     ap_hook_default_port(core_port,NULL,NULL,AP_HOOK_REALLY_LAST);
3569     ap_hook_open_logs(core_open_logs,NULL,NULL,AP_HOOK_MIDDLE);
3570     /* FIXME: I suspect we can eliminate the need for these - Ben */
3571     ap_hook_type_checker(do_nothing,NULL,NULL,AP_HOOK_REALLY_LAST);
3572     ap_hook_access_checker(do_nothing,NULL,NULL,AP_HOOK_REALLY_LAST);
3573
3574     /* register the core's insert_filter hook and register core-provided
3575      * filters
3576      */
3577     ap_hook_insert_filter(core_insert_filter, NULL, NULL, AP_HOOK_MIDDLE);
3578     ap_register_input_filter("HTTP_IN", ap_http_filter, AP_FTYPE_CONNECTION);
3579     ap_register_input_filter("DECHUNK", ap_dechunk_filter, AP_FTYPE_TRANSCODE);
3580     ap_register_input_filter("CORE_IN", core_input_filter, AP_FTYPE_NETWORK);
3581     ap_register_output_filter("HTTP_HEADER", ap_http_header_filter, AP_FTYPE_HTTP_HEADER);
3582     ap_register_output_filter("CONTENT_LENGTH", ap_content_length_filter, 
3583                               AP_FTYPE_HTTP_HEADER);
3584     ap_register_output_filter("CORE", core_output_filter, AP_FTYPE_NETWORK);
3585     ap_register_output_filter("SUBREQ_CORE", ap_sub_req_output_filter, 
3586                               AP_FTYPE_CONTENT);
3587     ap_register_output_filter("CHUNK", chunk_filter, AP_FTYPE_TRANSCODE);
3588     ap_register_output_filter("COALESCE", coalesce_filter, AP_FTYPE_CONNECTION);
3589 }
3590
3591 AP_DECLARE_DATA module core_module = {
3592     STANDARD20_MODULE_STUFF,
3593     create_core_dir_config,     /* create per-directory config structure */
3594     merge_core_dir_configs,     /* merge per-directory config structures */
3595     create_core_server_config,  /* create per-server config structure */
3596     merge_core_server_configs,  /* merge per-server config structures */
3597     core_cmds,                  /* command apr_table_t */
3598     core_handlers,              /* handlers */
3599     register_hooks              /* register hooks */
3600 };