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