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