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