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