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