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