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