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