]> granicus.if.org Git - apache/blob - modules/http/http_core.c
Get rid of an instance of ap_file_os_t from the Apache source. I will
[apache] / modules / http / http_core.c
1 /* ====================================================================
2  * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer. 
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * 3. All advertising materials mentioning features or use of this
17  *    software must display the following acknowledgment:
18  *    "This product includes software developed by the Apache Group
19  *    for use in the Apache HTTP server project (http://www.apache.org/)."
20  *
21  * 4. The names "Apache Server" and "Apache Group" must not be used to
22  *    endorse or promote products derived from this software without
23  *    prior written permission. For written permission, please contact
24  *    apache@apache.org.
25  *
26  * 5. Products derived from this software may not be called "Apache"
27  *    nor may "Apache" appear in their names without prior written
28  *    permission of the Apache Group.
29  *
30  * 6. Redistributions of any form whatsoever must retain the following
31  *    acknowledgment:
32  *    "This product includes software developed by the Apache Group
33  *    for use in the Apache HTTP server project (http://www.apache.org/)."
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
36  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46  * OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Group and was originally based
51  * on public domain software written at the National Center for
52  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
53  * For more information on the Apache Group and the Apache HTTP server
54  * project, please see <http://www.apache.org/>.
55  *
56  */
57
58 #define CORE_PRIVATE
59 #include "apr_lib.h"
60 #include "httpd.h"
61 #include "http_config.h"
62 #include "http_core.h"
63 #include "http_protocol.h"      /* For index_of_response().  Grump. */
64 #include "http_request.h"
65 #include "http_vhost.h"
66 #include "http_main.h"          /* For the default_handler below... */
67 #include "http_log.h"
68 #include "rfc1413.h"
69 #include "util_md5.h"
70 #include "apr_fnmatch.h"
71 #include "http_connection.h"
72
73 /* Allow Apache to use ap_mmap */
74 #ifdef USE_MMAP_FILES
75 #include "apr_mmap.h"
76
77 /* mmap support for static files based on ideas from John Heidemann's
78  * patch against 1.0.5.  See
79  * <http://www.isi.edu/~johnh/SOFTWARE/APACHE/index.html>.
80  */
81
82 /* Files have to be at least this big before they're mmap()d.  This is to deal
83  * with systems where the expense of doing an mmap() and an munmap() outweighs
84  * the benefit for small files.  It shouldn't be set lower than 1.
85  */
86 #ifndef MMAP_THRESHOLD
87   #ifdef SUNOS4
88   #define MMAP_THRESHOLD                (8*1024)
89   #else
90   #define MMAP_THRESHOLD                1
91   #endif /* SUNOS4 */
92 #endif /* MMAP_THRESHOLD */
93 #ifndef MMAP_LIMIT
94 #define MMAP_LIMIT              (4*1024*1024)
95 #endif
96 #endif /* USE_MMAP_FILES */
97
98 /* Server core module... This module provides support for really basic
99  * server operations, including options and commands which control the
100  * operation of other modules.  Consider this the bureaucracy module.
101  *
102  * The core module also defines handlers, etc., do handle just enough
103  * to allow a server with the core module ONLY to actually serve documents
104  * (though it slaps DefaultType on all of 'em); this was useful in testing,
105  * but may not be worth preserving.
106  *
107  * This file could almost be mod_core.c, except for the stuff which affects
108  * the http_conf_globals.
109  */
110
111 static void *create_core_dir_config(ap_context_t *a, char *dir)
112 {
113     core_dir_config *conf;
114
115     conf = (core_dir_config *)ap_pcalloc(a, sizeof(core_dir_config));
116     if (!dir || dir[strlen(dir) - 1] == '/') {
117         conf->d = dir;
118     }
119     else if (strncmp(dir, "proxy:", 6) == 0) {
120         conf->d = ap_pstrdup(a, dir);
121     }
122     else {
123         conf->d = ap_pstrcat(a, dir, "/", NULL);
124     }
125     conf->d_is_fnmatch = conf->d ? (ap_is_fnmatch(conf->d) != 0) : 0;
126     conf->d_components = conf->d ? ap_count_dirs(conf->d) : 0;
127
128     conf->opts = dir ? OPT_UNSET : OPT_UNSET|OPT_ALL;
129     conf->opts_add = conf->opts_remove = OPT_NONE;
130     conf->override = dir ? OR_UNSET : OR_UNSET|OR_ALL;
131
132     conf->content_md5 = 2;
133
134     conf->use_canonical_name = USE_CANONICAL_NAME_UNSET;
135
136     conf->hostname_lookups = HOSTNAME_LOOKUP_UNSET;
137     conf->do_rfc1413 = DEFAULT_RFC1413 | 2; /* set bit 1 to indicate default */
138     conf->satisfy = SATISFY_NOSPEC;
139
140     conf->limit_req_body = 0;
141     conf->sec = ap_make_array(a, 2, sizeof(void *));
142 #ifdef WIN32
143     conf->script_interpreter_source = INTERPRETER_SOURCE_UNSET;
144 #endif
145
146     conf->server_signature = srv_sig_unset;
147
148     return (void *)conf;
149 }
150
151 static void *merge_core_dir_configs(ap_context_t *a, void *basev, void *newv)
152 {
153     core_dir_config *base = (core_dir_config *)basev;
154     core_dir_config *new = (core_dir_config *)newv;
155     core_dir_config *conf;
156     int i;
157   
158     conf = (core_dir_config *)ap_palloc(a, sizeof(core_dir_config));
159     memcpy((char *)conf, (const char *)base, sizeof(core_dir_config));
160     if (base->response_code_strings) {
161         conf->response_code_strings =
162             ap_palloc(a, sizeof(*conf->response_code_strings)
163                       * RESPONSE_CODES);
164         memcpy(conf->response_code_strings, base->response_code_strings,
165                sizeof(*conf->response_code_strings) * RESPONSE_CODES);
166     }
167     
168     conf->d = new->d;
169     conf->d_is_fnmatch = new->d_is_fnmatch;
170     conf->d_components = new->d_components;
171     conf->r = new->r;
172     
173     if (new->opts & OPT_UNSET) {
174         /* there was no explicit setting of new->opts, so we merge
175          * preserve the invariant (opts_add & opts_remove) == 0
176          */
177         conf->opts_add = (conf->opts_add & ~new->opts_remove) | new->opts_add;
178         conf->opts_remove = (conf->opts_remove & ~new->opts_add)
179                             | new->opts_remove;
180         conf->opts = (conf->opts & ~conf->opts_remove) | conf->opts_add;
181         if ((base->opts & OPT_INCNOEXEC) && (new->opts & OPT_INCLUDES)) {
182             conf->opts = (conf->opts & ~OPT_INCNOEXEC) | OPT_INCLUDES;
183         }
184     }
185     else {
186         /* otherwise we just copy, because an explicit opts setting
187          * overrides all earlier +/- modifiers
188          */
189         conf->opts = new->opts;
190         conf->opts_add = new->opts_add;
191         conf->opts_remove = new->opts_remove;
192     }
193
194     if (!(new->override & OR_UNSET)) {
195         conf->override = new->override;
196     }
197     if (new->ap_default_type) {
198         conf->ap_default_type = new->ap_default_type;
199     }
200     
201     if (new->ap_auth_type) {
202         conf->ap_auth_type = new->ap_auth_type;
203     }
204     if (new->ap_auth_name) {
205         conf->ap_auth_name = new->ap_auth_name;
206     }
207     if (new->ap_requires) {
208         conf->ap_requires = new->ap_requires;
209     }
210
211     if (new->response_code_strings) {
212         if (conf->response_code_strings == NULL) {
213             conf->response_code_strings = ap_palloc(a,
214                 sizeof(*conf->response_code_strings) * RESPONSE_CODES);
215             memcpy(conf->response_code_strings, new->response_code_strings,
216                    sizeof(*conf->response_code_strings) * RESPONSE_CODES);
217         }
218         else {
219             for (i = 0; i < RESPONSE_CODES; ++i) {
220                 if (new->response_code_strings[i] != NULL) {
221                     conf->response_code_strings[i]
222                         = new->response_code_strings[i];
223                 }
224             }
225         }
226     }
227     if (new->hostname_lookups != HOSTNAME_LOOKUP_UNSET) {
228         conf->hostname_lookups = new->hostname_lookups;
229     }
230     if ((new->do_rfc1413 & 2) == 0) {
231         conf->do_rfc1413 = new->do_rfc1413;
232     }
233     if ((new->content_md5 & 2) == 0) {
234         conf->content_md5 = new->content_md5;
235     }
236     if (new->use_canonical_name != USE_CANONICAL_NAME_UNSET) {
237         conf->use_canonical_name = new->use_canonical_name;
238     }
239
240     if (new->limit_req_body) {
241         conf->limit_req_body = new->limit_req_body;
242     }
243     conf->sec = ap_append_arrays(a, base->sec, new->sec);
244
245     if (new->satisfy != SATISFY_NOSPEC) {
246         conf->satisfy = new->satisfy;
247     }
248
249 #ifdef WIN32
250     if (new->script_interpreter_source != INTERPRETER_SOURCE_UNSET) {
251         conf->script_interpreter_source = new->script_interpreter_source;
252     }
253 #endif
254
255     if (new->server_signature != srv_sig_unset) {
256         conf->server_signature = new->server_signature;
257     }
258
259     return (void*)conf;
260 }
261
262 static void *create_core_server_config(ap_context_t *a, server_rec *s)
263 {
264     core_server_config *conf;
265     int is_virtual = s->is_virtual;
266   
267     conf = (core_server_config *)ap_pcalloc(a, sizeof(core_server_config));
268 #ifdef GPROF
269     conf->gprof_dir = NULL;
270 #endif
271     conf->access_name = is_virtual ? NULL : DEFAULT_ACCESS_FNAME;
272     conf->ap_document_root = is_virtual ? NULL : DOCUMENT_LOCATION;
273     conf->sec = ap_make_array(a, 40, sizeof(void *));
274     conf->sec_url = ap_make_array(a, 40, sizeof(void *));
275     
276     return (void *)conf;
277 }
278
279 static void *merge_core_server_configs(ap_context_t *p, void *basev, void *virtv)
280 {
281     core_server_config *base = (core_server_config *)basev;
282     core_server_config *virt = (core_server_config *)virtv;
283     core_server_config *conf;
284
285     conf = (core_server_config *)ap_pcalloc(p, sizeof(core_server_config));
286     *conf = *virt;
287     if (!conf->access_name) {
288         conf->access_name = base->access_name;
289     }
290     if (!conf->ap_document_root) {
291         conf->ap_document_root = base->ap_document_root;
292     }
293     conf->sec = ap_append_arrays(p, base->sec, virt->sec);
294     conf->sec_url = ap_append_arrays(p, base->sec_url, virt->sec_url);
295
296     return conf;
297 }
298
299 /* Add per-directory configuration entry (for <directory> section);
300  * these are part of the core server config.
301  */
302
303 CORE_EXPORT(void) ap_add_per_dir_conf(server_rec *s, void *dir_config)
304 {
305     core_server_config *sconf = ap_get_module_config(s->module_config,
306                                                      &core_module);
307     void **new_space = (void **)ap_push_array(sconf->sec);
308     
309     *new_space = dir_config;
310 }
311
312 CORE_EXPORT(void) ap_add_per_url_conf(server_rec *s, void *url_config)
313 {
314     core_server_config *sconf = ap_get_module_config(s->module_config,
315                                                      &core_module);
316     void **new_space = (void **)ap_push_array(sconf->sec_url);
317     
318     *new_space = url_config;
319 }
320
321 CORE_EXPORT(void) ap_add_file_conf(core_dir_config *conf, void *url_config)
322 {
323     void **new_space = (void **)ap_push_array(conf->sec);
324     
325     *new_space = url_config;
326 }
327
328 /* core_reorder_directories reorders the directory sections such that the
329  * 1-component sections come first, then the 2-component, and so on, finally
330  * followed by the "special" sections.  A section is "special" if it's a regex,
331  * or if it doesn't start with / -- consider proxy: matching.  All movements
332  * are in-order to preserve the ordering of the sections from the config files.
333  * See directory_walk().
334  */
335
336 #ifdef HAVE_DRIVE_LETTERS
337 #define IS_SPECIAL(entry_core)  \
338     ((entry_core)->r != NULL \
339         || ((entry_core)->d[0] != '/' && (entry_core)->d[1] != ':'))
340 #else
341 #define IS_SPECIAL(entry_core)  \
342     ((entry_core)->r != NULL || (entry_core)->d[0] != '/')
343 #endif
344
345 /* We need to do a stable sort, qsort isn't stable.  So to make it stable
346  * we'll be maintaining the original index into the list, and using it
347  * as the minor key during sorting.  The major key is the number of
348  * components (where a "special" section has infinite components).
349  */
350 struct reorder_sort_rec {
351     void *elt;
352     int orig_index;
353 };
354
355 static int reorder_sorter(const void *va, const void *vb)
356 {
357     const struct reorder_sort_rec *a = va;
358     const struct reorder_sort_rec *b = vb;
359     core_dir_config *core_a;
360     core_dir_config *core_b;
361
362     core_a = (core_dir_config *)ap_get_module_config(a->elt, &core_module);
363     core_b = (core_dir_config *)ap_get_module_config(b->elt, &core_module);
364     if (IS_SPECIAL(core_a)) {
365         if (!IS_SPECIAL(core_b)) {
366             return 1;
367         }
368     }
369     else if (IS_SPECIAL(core_b)) {
370         return -1;
371     }
372     else {
373         /* we know they're both not special */
374         if (core_a->d_components < core_b->d_components) {
375             return -1;
376         }
377         else if (core_a->d_components > core_b->d_components) {
378             return 1;
379         }
380     }
381     /* Either they're both special, or they're both not special and have the
382      * same number of components.  In any event, we now have to compare
383      * the minor key. */
384     return a->orig_index - b->orig_index;
385 }
386
387 void ap_core_reorder_directories(ap_context_t *p, server_rec *s)
388 {
389     core_server_config *sconf;
390     ap_array_header_t *sec;
391     struct reorder_sort_rec *sortbin;
392     int nelts;
393     void **elts;
394     int i;
395     ap_context_t *tmp;
396
397     sconf = ap_get_module_config(s->module_config, &core_module);
398     sec = sconf->sec;
399     nelts = sec->nelts;
400     elts = (void **)sec->elts;
401
402     /* we have to allocate tmp space to do a stable sort */
403     ap_create_context(&tmp, p);
404     sortbin = ap_palloc(tmp, sec->nelts * sizeof(*sortbin));
405     for (i = 0; i < nelts; ++i) {
406         sortbin[i].orig_index = i;
407         sortbin[i].elt = elts[i];
408     }
409
410     qsort(sortbin, nelts, sizeof(*sortbin), reorder_sorter);
411
412     /* and now copy back to the original array */
413     for (i = 0; i < nelts; ++i) {
414       elts[i] = sortbin[i].elt;
415     }
416
417     ap_destroy_pool(tmp);
418 }
419
420 /*****************************************************************
421  *
422  * There are some elements of the core config structures in which
423  * other modules have a legitimate interest (this is ugly, but necessary
424  * to preserve NCSA back-compatibility).  So, we have a bunch of accessors
425  * here...
426  */
427
428 API_EXPORT(int) ap_allow_options(request_rec *r)
429 {
430     core_dir_config *conf = 
431       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module); 
432
433     return conf->opts; 
434
435
436 API_EXPORT(int) ap_allow_overrides(request_rec *r) 
437
438     core_dir_config *conf;
439     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
440                                                    &core_module); 
441
442     return conf->override; 
443
444
445 API_EXPORT(const char *) ap_auth_type(request_rec *r)
446 {
447     core_dir_config *conf;
448
449     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
450                                                    &core_module); 
451     return conf->ap_auth_type;
452 }
453
454 API_EXPORT(const char *) ap_auth_name(request_rec *r)
455 {
456     core_dir_config *conf;
457
458     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
459                                                    &core_module); 
460     return conf->ap_auth_name;
461 }
462
463 API_EXPORT(const char *) ap_default_type(request_rec *r)
464 {
465     core_dir_config *conf;
466
467     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
468                                                    &core_module); 
469     return conf->ap_default_type 
470                ? conf->ap_default_type 
471                : DEFAULT_CONTENT_TYPE;
472 }
473
474 API_EXPORT(const char *) ap_document_root(request_rec *r) /* Don't use this! */
475 {
476     core_server_config *conf;
477
478     conf = (core_server_config *)ap_get_module_config(r->server->module_config,
479                                                       &core_module); 
480     return conf->ap_document_root;
481 }
482
483 API_EXPORT(const ap_array_header_t *) ap_requires(request_rec *r)
484 {
485     core_dir_config *conf;
486
487     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
488                                                    &core_module); 
489     return conf->ap_requires;
490 }
491
492 API_EXPORT(int) ap_satisfies(request_rec *r)
493 {
494     core_dir_config *conf;
495
496     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
497                                                    &core_module);
498
499     return conf->satisfy;
500 }
501
502 /* Should probably just get rid of this... the only code that cares is
503  * part of the core anyway (and in fact, it isn't publicised to other
504  * modules).
505  */
506
507 char *ap_response_code_string(request_rec *r, int error_index)
508 {
509     core_dir_config *conf;
510
511     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
512                                                    &core_module); 
513
514     if (conf->response_code_strings == NULL) {
515         return NULL;
516     }
517     return conf->response_code_strings[error_index];
518 }
519
520
521 /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
522 static ap_inline void do_double_reverse (conn_rec *conn)
523 {
524     struct hostent *hptr;
525
526     if (conn->double_reverse) {
527         /* already done */
528         return;
529     }
530     if (conn->remote_host == NULL || conn->remote_host[0] == '\0') {
531         /* single reverse failed, so don't bother */
532         conn->double_reverse = -1;
533         return;
534     }
535     hptr = gethostbyname(conn->remote_host);   
536     if (hptr) {          
537         char **haddr;
538
539         for (haddr = hptr->h_addr_list; *haddr; haddr++) {
540             if (((struct in_addr *)(*haddr))->s_addr
541                 == conn->remote_addr.sin_addr.s_addr) {
542                 conn->double_reverse = 1;
543                 return;
544             }
545         }
546     }
547     conn->double_reverse = -1;
548 }
549
550 API_EXPORT(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config,
551                                             int type)
552 {
553     struct in_addr *iaddr;
554     struct hostent *hptr;
555     int hostname_lookups;
556
557     /* If we haven't checked the host name, and we want to */
558     if (dir_config) {
559         hostname_lookups =
560             ((core_dir_config *)ap_get_module_config(dir_config, &core_module))
561                 ->hostname_lookups;
562         if (hostname_lookups == HOSTNAME_LOOKUP_UNSET) {
563             hostname_lookups = HOSTNAME_LOOKUP_OFF;
564         }
565     }
566     else {
567         /* the default */
568         hostname_lookups = HOSTNAME_LOOKUP_OFF;
569     }
570
571     if (type != REMOTE_NOLOOKUP
572         && conn->remote_host == NULL
573         && (type == REMOTE_DOUBLE_REV
574             || hostname_lookups != HOSTNAME_LOOKUP_OFF)) {
575         iaddr = &(conn->remote_addr.sin_addr);
576         hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET);
577         if (hptr != NULL) {
578             conn->remote_host = ap_pstrdup(conn->pool, (void *)hptr->h_name);
579             ap_str_tolower(conn->remote_host);
580            
581             if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) {
582                 do_double_reverse(conn);
583                 if (conn->double_reverse != 1) {
584                     conn->remote_host = NULL;
585                 }
586             }
587         }
588         /* if failed, set it to the NULL string to indicate error */
589         if (conn->remote_host == NULL) {
590             conn->remote_host = "";
591         }
592     }
593     if (type == REMOTE_DOUBLE_REV) {
594         do_double_reverse(conn);
595         if (conn->double_reverse == -1) {
596             return NULL;
597         }
598     }
599
600 /*
601  * Return the desired information; either the remote DNS name, if found,
602  * or either NULL (if the hostname was requested) or the IP address
603  * (if any identifier was requested).
604  */
605     if (conn->remote_host != NULL && conn->remote_host[0] != '\0') {
606         return conn->remote_host;
607     }
608     else {
609         if (type == REMOTE_HOST || type == REMOTE_DOUBLE_REV) {
610             return NULL;
611         }
612         else {
613             return conn->remote_ip;
614         }
615     }
616 }
617
618 API_EXPORT(const char *) ap_get_remote_logname(request_rec *r)
619 {
620     core_dir_config *dir_conf;
621
622     if (r->connection->remote_logname != NULL) {
623         return r->connection->remote_logname;
624     }
625
626 /* If we haven't checked the identity, and we want to */
627     dir_conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
628                                                        &core_module);
629
630     if (dir_conf->do_rfc1413 & 1) {
631         return ap_rfc1413(r->connection, r->server);
632     }
633     else {
634         return NULL;
635     }
636 }
637
638 /* There are two options regarding what the "name" of a server is.  The
639  * "canonical" name as defined by ServerName and Port, or the "client's
640  * name" as supplied by a possible Host: header or full URI.  We never
641  * trust the port passed in the client's headers, we always use the
642  * port of the actual socket.
643  *
644  * The DNS option to UseCanonicalName causes this routine to do a
645  * reverse lookup on the local IP address of the connectiona and use
646  * that for the ServerName. This makes its value more reliable while
647  * at the same time allowing Demon's magic virtual hosting to work.
648  * The assumption is that DNS lookups are sufficiently quick...
649  * -- fanf 1998-10-03
650  */
651 API_EXPORT(const char *) ap_get_server_name(request_rec *r)
652 {
653     conn_rec *conn = r->connection;
654     core_dir_config *d;
655
656     d = (core_dir_config *)ap_get_module_config(r->per_dir_config,
657                                                 &core_module);
658
659     if (d->use_canonical_name == USE_CANONICAL_NAME_OFF) {
660         return r->hostname ? r->hostname : r->server->server_hostname;
661     }
662     if (d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
663         if (conn->local_host == NULL) {
664             struct in_addr *iaddr;
665             struct hostent *hptr;
666             iaddr = &(conn->local_addr.sin_addr);
667             hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr),
668                                  AF_INET);
669             if (hptr != NULL) {
670                 conn->local_host = ap_pstrdup(conn->pool,
671                                               (void *)hptr->h_name);
672                 ap_str_tolower(conn->local_host);
673             }
674             else {
675                 conn->local_host = ap_pstrdup(conn->pool,
676                                               r->server->server_hostname);
677             }
678         }
679         return conn->local_host;
680     }
681     /* default */
682     return r->server->server_hostname;
683 }
684
685 API_EXPORT(unsigned) ap_get_server_port(const request_rec *r)
686 {
687     unsigned port;
688     core_dir_config *d =
689       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
690     
691     port = r->server->port ? r->server->port : ap_default_port(r);
692
693     if (d->use_canonical_name == USE_CANONICAL_NAME_OFF
694         || d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
695         return r->hostname ? ntohs(r->connection->local_addr.sin_port)
696                            : port;
697     }
698     /* default */
699     return port;
700 }
701
702 API_EXPORT(char *) ap_construct_url(ap_context_t *p, const char *uri,
703                                     request_rec *r)
704 {
705     unsigned port = ap_get_server_port(r);
706     const char *host = ap_get_server_name(r);
707
708     if (ap_is_default_port(port, r)) {
709         return ap_pstrcat(p, ap_http_method(r), "://", host, uri, NULL);
710     }
711     return ap_psprintf(p, "%s://%s:%u%s", ap_http_method(r), host, port, uri);
712 }
713
714 API_EXPORT(unsigned long) ap_get_limit_req_body(const request_rec *r)
715 {
716     core_dir_config *d =
717       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
718     
719     return d->limit_req_body;
720 }
721
722 #ifdef WIN32
723 static char* get_interpreter_from_win32_registry(ap_context_t *p, const char* ext) 
724 {
725     char extension_path[] = "SOFTWARE\\Classes\\";
726     char executable_path[] = "\\SHELL\\OPEN\\COMMAND";
727
728     HKEY hkeyOpen;
729     DWORD type;
730     int size;
731     int result;
732     char *keyName;
733     char *buffer;
734     char *s;
735
736     if (!ext)
737         return NULL;
738     /* 
739      * Future optimization:
740      * When the registry is successfully searched, store the interpreter
741      * string in a ap_table_t to make subsequent look-ups faster
742      */
743
744     /* Open the key associated with the script extension */
745     keyName = ap_pstrcat(p, extension_path, ext, NULL);
746
747     result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, 
748                           &hkeyOpen);
749
750     if (result != ERROR_SUCCESS) 
751         return NULL;
752
753     /* Read to NULL buffer to find value size */
754     size = 0;
755     result = RegQueryValueEx(hkeyOpen, "", NULL, &type, NULL, &size);
756
757     if (result == ERROR_SUCCESS) {
758         buffer = ap_palloc(p, size);
759         result = RegQueryValueEx(hkeyOpen, "", NULL, &type, buffer, &size);
760     }
761
762     RegCloseKey(hkeyOpen);
763
764     if (result != ERROR_SUCCESS)
765         return NULL;
766
767     /* Open the key associated with the interpreter path */
768     keyName = ap_pstrcat(p, extension_path, buffer, executable_path, NULL);
769
770     result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, 
771                           &hkeyOpen);
772
773     if (result != ERROR_SUCCESS)
774         return NULL;
775
776     /* Read to NULL buffer to find value size */
777     size = 0;
778     result = RegQueryValueEx(hkeyOpen, "", 0, &type, NULL, &size);
779
780     if (result == ERROR_SUCCESS) {
781         buffer = ap_palloc(p, size);
782         result = RegQueryValueEx(hkeyOpen, "", 0, &type, buffer, &size);
783     }
784
785     RegCloseKey(hkeyOpen);
786
787     if (result != ERROR_SUCCESS)
788         return NULL;
789
790     /*
791      * The canonical way shell command entries are entered in the Win32 
792      * registry is as follows:
793      *   shell [options] "%1"
794      * where
795      *   shell - full path name to interpreter or shell to run.
796      *           E.g., c:\usr\local\ntreskit\perl\bin\perl.exe
797      *   options - optional switches
798      *              E.g., \C
799      *   "%1" - Place holder for file to run the shell against. 
800      *          Typically quoted.
801      *
802      * If we find a %1 or a quoted %1, lop it off. 
803      */
804     if (buffer && *buffer) {
805         if ((s = strstr(buffer, "\"%1")))
806             *s = '\0';
807         else if ((s = strstr(buffer, "%1"))) 
808             *s = '\0';
809     }
810
811     return buffer;
812 }
813
814 API_EXPORT (file_type_e) ap_get_win32_interpreter(const  request_rec *r, 
815                                                   char** interpreter )
816 {
817     HANDLE hFile;
818     DWORD nBytesRead;
819     BOOLEAN bResult;
820     char buffer[1024];
821     core_dir_config *d;
822     int i;
823     file_type_e fileType = eFileTypeUNKNOWN;
824     char *ext = NULL;
825     char *exename = NULL;
826
827     d = (core_dir_config *)ap_get_module_config(r->per_dir_config, 
828                                                 &core_module);
829
830     /* Find the file extension */
831     exename = strrchr(r->filename, '/');
832     if (!exename) {
833         exename = strrchr(r->filename, '\\');
834     }
835     if (!exename) {
836         exename = r->filename;
837     }
838     else {
839         exename++;
840     }
841     ext = strrchr(exename, '.');
842
843     if (ext && (!strcasecmp(ext,".bat") || !strcasecmp(ext,".cmd"))) {
844         return eFileTypeEXE32;
845     }
846
847     /* If the file has an extension and it is not .com and not .exe and
848      * we've been instructed to search the registry, then do it!
849      */
850     if (ext && strcasecmp(ext,".exe") && strcasecmp(ext,".com") &&
851         d->script_interpreter_source == INTERPRETER_SOURCE_REGISTRY) {
852          /* Check the registry */
853         *interpreter = get_interpreter_from_win32_registry(r->pool, ext);
854         if (*interpreter)
855             return eFileTypeSCRIPT;
856         else {
857             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r->server,
858              "ScriptInterpreterSource config directive set to \"registry\".\n\t"
859              "Registry was searched but interpreter not found. Trying the shebang line.");
860         }
861     }        
862
863     /* Need to peek into the file figure out what it really is... */
864     hFile = CreateFile(r->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
865                        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
866     if (hFile == INVALID_HANDLE_VALUE) {
867         return eFileTypeUNKNOWN;
868     }
869     bResult = ReadFile(hFile, (void*) &buffer, sizeof(buffer) - 1, 
870                        &nBytesRead, NULL);
871     if (!bResult || (nBytesRead == 0)) {
872         ap_log_rerror(APLOG_MARK, APLOG_ERR, GetLastError(), r,
873                       "ReadFile(%s) failed", r->filename);
874         CloseHandle(hFile);
875         return eFileTypeUNKNOWN;
876     }
877     CloseHandle(hFile);
878     buffer[nBytesRead] = '\0';
879
880     /* Script or executable, that is the question... */
881     if ((buffer[0] == '#') && (buffer[1] == '!')) {
882         /* Assuming file is a script since it starts with a shebang */
883         fileType = eFileTypeSCRIPT;
884         for (i = 2; i < sizeof(buffer); i++) {
885             if ((buffer[i] == '\r')
886                 || (buffer[i] == '\n')) {
887                 break;
888             }
889         }
890         buffer[i] = '\0';
891         for (i = 2; buffer[i] == ' ' ; ++i)
892             ;
893         *interpreter = ap_pstrdup(r->pool, buffer + i ); 
894     }
895     else {
896         /* Not a script, is it an executable? */
897         IMAGE_DOS_HEADER *hdr = (IMAGE_DOS_HEADER*)buffer;    
898         if ((nBytesRead >= sizeof(IMAGE_DOS_HEADER)) && (hdr->e_magic == IMAGE_DOS_SIGNATURE)) {
899             if (hdr->e_lfarlc < 0x40)
900                 fileType = eFileTypeEXE16;
901             else
902                 fileType = eFileTypeEXE32;
903         }
904         else
905             fileType = eFileTypeUNKNOWN;
906     }
907
908     return fileType;
909 }
910 #endif
911
912 /*****************************************************************
913  *
914  * Commands... this module handles almost all of the NCSA httpd.conf
915  * commands, but most of the old srm.conf is in the the modules.
916  */
917
918 static const char end_directory_section[] = "</Directory>";
919 static const char end_directorymatch_section[] = "</DirectoryMatch>";
920 static const char end_location_section[] = "</Location>";
921 static const char end_locationmatch_section[] = "</LocationMatch>";
922 static const char end_files_section[] = "</Files>";
923 static const char end_filesmatch_section[] = "</FilesMatch>";
924 static const char end_virtualhost_section[] = "</VirtualHost>";
925 static const char end_ifmodule_section[] = "</IfModule>";
926 static const char end_ifdefine_section[] = "</IfDefine>";
927
928
929 API_EXPORT(const char *) ap_check_cmd_context(cmd_parms *cmd,
930                                               unsigned forbidden)
931 {
932     const char *gt = (cmd->cmd->name[0] == '<'
933                       && cmd->cmd->name[strlen(cmd->cmd->name)-1] != '>')
934                          ? ">" : "";
935
936     if ((forbidden & NOT_IN_VIRTUALHOST) && cmd->server->is_virtual) {
937         return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
938                           " cannot occur within <VirtualHost> section", NULL);
939     }
940
941     if ((forbidden & NOT_IN_LIMIT) && cmd->limited != -1) {
942         return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
943                           " cannot occur within <Limit> section", NULL);
944     }
945
946     if ((forbidden & NOT_IN_DIR_LOC_FILE) == NOT_IN_DIR_LOC_FILE
947         && cmd->path != NULL) {
948         return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
949                           " cannot occur within <Directory/Location/Files> "
950                           "section", NULL);
951     }
952     
953     if (((forbidden & NOT_IN_DIRECTORY)
954          && (cmd->end_token == end_directory_section
955              || cmd->end_token == end_directorymatch_section)) 
956         || ((forbidden & NOT_IN_LOCATION)
957             && (cmd->end_token == end_location_section
958                 || cmd->end_token == end_locationmatch_section)) 
959         || ((forbidden & NOT_IN_FILES)
960             && (cmd->end_token == end_files_section
961                 || cmd->end_token == end_filesmatch_section))) {
962         return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
963                           " cannot occur within <", cmd->end_token+2,
964                           " section", NULL);
965     }
966
967     return NULL;
968 }
969
970 static const char *set_access_name(cmd_parms *cmd, void *dummy, char *arg)
971 {
972     void *sconf = cmd->server->module_config;
973     core_server_config *conf = ap_get_module_config(sconf, &core_module);
974
975     const char *err = ap_check_cmd_context(cmd,
976                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
977     if (err != NULL) {
978         return err;
979     }
980
981     conf->access_name = ap_pstrdup(cmd->pool, arg);
982     return NULL;
983 }
984
985 #ifdef GPROF
986 static const char *set_gprof_dir(cmd_parms *cmd, void *dummy, char *arg)
987 {
988     void *sconf = cmd->server->module_config;
989     core_server_config *conf = ap_get_module_config(sconf, &core_module);
990
991     const char *err = ap_check_cmd_context(cmd,
992                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
993     if (err != NULL) {
994         return err;
995     }
996
997     conf->gprof_dir = ap_pstrdup(cmd->pool, arg);
998     return NULL;
999 }
1000 #endif /*GPROF*/
1001
1002 static const char *set_document_root(cmd_parms *cmd, void *dummy, char *arg)
1003 {
1004     void *sconf = cmd->server->module_config;
1005     core_server_config *conf = ap_get_module_config(sconf, &core_module);
1006   
1007     const char *err = ap_check_cmd_context(cmd,
1008                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1009     if (err != NULL) {
1010         return err;
1011     }
1012
1013     arg = ap_os_canonical_filename(cmd->pool, arg);
1014     if (/* TODO: ap_configtestonly && ap_docrootcheck && */ !ap_is_directory(arg)) {
1015         if (cmd->server->is_virtual) {
1016             ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
1017                          "Warning: DocumentRoot [%s] does not exist",
1018                          arg);
1019         }
1020         else {
1021             return "DocumentRoot must be a directory";
1022         }
1023     }
1024     
1025     conf->ap_document_root = arg;
1026     return NULL;
1027 }
1028
1029 API_EXPORT(void) ap_custom_response(request_rec *r, int status, char *string)
1030 {
1031     core_dir_config *conf = 
1032         ap_get_module_config(r->per_dir_config, &core_module);
1033     int idx;
1034
1035     if(conf->response_code_strings == NULL) {
1036         conf->response_code_strings = 
1037             ap_pcalloc(r->pool,
1038                     sizeof(*conf->response_code_strings) * 
1039                     RESPONSE_CODES);
1040     }
1041
1042     idx = ap_index_of_response(status);
1043
1044     conf->response_code_strings[idx] = 
1045        ((ap_is_url(string) || (*string == '/')) && (*string != '"')) ? 
1046        ap_pstrdup(r->pool, string) : ap_pstrcat(r->pool, "\"", string, NULL);
1047 }
1048
1049 static const char *set_error_document(cmd_parms *cmd, core_dir_config *conf,
1050                                       char *line)
1051 {
1052     int error_number, index_number, idx500;
1053     char *w;
1054                 
1055     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1056     if (err != NULL) {
1057         return err;
1058     }
1059
1060     /* 1st parameter should be a 3 digit number, which we recognize;
1061      * convert it into an array index
1062      */
1063   
1064     w = ap_getword_conf_nc(cmd->pool, &line);
1065     error_number = atoi(w);
1066
1067     idx500 = ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR);
1068
1069     if (error_number == HTTP_INTERNAL_SERVER_ERROR) {
1070         index_number = idx500;
1071     }
1072     else if ((index_number = ap_index_of_response(error_number)) == idx500) {
1073         return ap_pstrcat(cmd->pool, "Unsupported HTTP response code ",
1074                           w, NULL);
1075     }
1076
1077     /* The entry should be ignored if it is a full URL for a 401 error */
1078
1079     if (error_number == 401 &&
1080         line[0] != '/' && line[0] != '"') { /* Ignore it... */
1081         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, cmd->server,
1082                      "cannot use a full URL in a 401 ErrorDocument "
1083                      "directive --- ignoring!");
1084     }
1085     else { /* Store it... */
1086         if (conf->response_code_strings == NULL) {
1087             conf->response_code_strings =
1088                 ap_pcalloc(cmd->pool,
1089                            sizeof(*conf->response_code_strings) * RESPONSE_CODES);
1090         }
1091         conf->response_code_strings[index_number] = ap_pstrdup(cmd->pool, line);
1092     }   
1093
1094     return NULL;
1095 }
1096
1097 /* access.conf commands...
1098  *
1099  * The *only* thing that can appear in access.conf at top level is a
1100  * <Directory> section.  NB we need to have a way to cut the srm_command_loop
1101  * invoked by dirsection (i.e., <Directory>) short when </Directory> is seen.
1102  * We do that by returning an error, which dirsection itself recognizes and
1103  * discards as harmless.  Cheesy, but it works.
1104  */
1105
1106 static const char *set_override(cmd_parms *cmd, core_dir_config *d,
1107                                 const char *l)
1108 {
1109     char *w;
1110   
1111     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1112     if (err != NULL) {
1113         return err;
1114     }
1115
1116     d->override = OR_NONE;
1117     while (l[0]) {
1118         w = ap_getword_conf(cmd->pool, &l);
1119         if (!strcasecmp(w, "Limit")) {
1120             d->override |= OR_LIMIT;
1121         }
1122         else if (!strcasecmp(w, "Options")) {
1123             d->override |= OR_OPTIONS;
1124         }
1125         else if (!strcasecmp(w, "FileInfo")) {
1126             d->override |= OR_FILEINFO;
1127         }
1128         else if (!strcasecmp(w, "AuthConfig")) {
1129             d->override |= OR_AUTHCFG;
1130         }
1131         else if (!strcasecmp(w, "Indexes")) {
1132             d->override |= OR_INDEXES;
1133         }
1134         else if (!strcasecmp(w, "None")) {
1135             d->override = OR_NONE;
1136         }
1137         else if (!strcasecmp(w, "All")) {
1138             d->override = OR_ALL;
1139         }
1140         else {
1141             return ap_pstrcat(cmd->pool, "Illegal override option ", w, NULL);
1142         }
1143         d->override &= ~OR_UNSET;
1144     }
1145
1146     return NULL;
1147 }
1148
1149 static const char *set_options(cmd_parms *cmd, core_dir_config *d,
1150                                const char *l)
1151 {
1152     allow_options_t opt;
1153     int first = 1;
1154     char action;
1155
1156     while (l[0]) {
1157         char *w = ap_getword_conf(cmd->pool, &l);
1158         action = '\0';
1159
1160         if (*w == '+' || *w == '-') {
1161             action = *(w++);
1162         }
1163         else if (first) {
1164             d->opts = OPT_NONE;
1165             first = 0;
1166         }
1167             
1168         if (!strcasecmp(w, "Indexes")) {
1169             opt = OPT_INDEXES;
1170         }
1171         else if (!strcasecmp(w, "Includes")) {
1172             opt = OPT_INCLUDES;
1173         }
1174         else if (!strcasecmp(w, "IncludesNOEXEC")) {
1175             opt = (OPT_INCLUDES | OPT_INCNOEXEC);
1176         }
1177         else if (!strcasecmp(w, "FollowSymLinks")) {
1178             opt = OPT_SYM_LINKS;
1179         }
1180         else if (!strcasecmp(w, "SymLinksIfOwnerMatch")) {
1181             opt = OPT_SYM_OWNER;
1182         }
1183         else if (!strcasecmp(w, "execCGI")) {
1184             opt = OPT_EXECCGI;
1185         }
1186         else if (!strcasecmp(w, "MultiViews")) {
1187             opt = OPT_MULTI;
1188         }
1189         else if (!strcasecmp(w, "RunScripts")) { /* AI backcompat. Yuck */
1190             opt = OPT_MULTI|OPT_EXECCGI;
1191         }
1192         else if (!strcasecmp(w, "None")) {
1193             opt = OPT_NONE;
1194         }
1195         else if (!strcasecmp(w, "All")) {
1196             opt = OPT_ALL;
1197         }
1198         else {
1199             return ap_pstrcat(cmd->pool, "Illegal option ", w, NULL);
1200         }
1201
1202         /* we ensure the invariant (d->opts_add & d->opts_remove) == 0 */
1203         if (action == '-') {
1204             d->opts_remove |= opt;
1205             d->opts_add &= ~opt;
1206             d->opts &= ~opt;
1207         }
1208         else if (action == '+') {
1209             d->opts_add |= opt;
1210             d->opts_remove &= ~opt;
1211             d->opts |= opt;
1212         }
1213         else {
1214             d->opts |= opt;
1215         }
1216     }
1217
1218     return NULL;
1219 }
1220
1221 static const char *satisfy(cmd_parms *cmd, core_dir_config *c, char *arg)
1222 {
1223     if (!strcasecmp(arg, "all")) {
1224         c->satisfy = SATISFY_ALL;
1225     }
1226     else if (!strcasecmp(arg, "any")) {
1227         c->satisfy = SATISFY_ANY;
1228     }
1229     else {
1230         return "Satisfy either 'any' or 'all'.";
1231     }
1232     return NULL;
1233 }
1234
1235 static const char *require(cmd_parms *cmd, core_dir_config *c, char *arg)
1236 {
1237     require_line *r;
1238   
1239     if (!c->ap_requires) {
1240         c->ap_requires = ap_make_array(cmd->pool, 2, sizeof(require_line));
1241     }
1242     r = (require_line *)ap_push_array(c->ap_requires);
1243     r->requirement = ap_pstrdup(cmd->pool, arg);
1244     r->method_mask = cmd->limited;
1245     return NULL;
1246 }
1247
1248 CORE_EXPORT_NONSTD(const char *) ap_limit_section(cmd_parms *cmd, void *dummy,
1249                                                   const char *arg)
1250 {
1251     const char *limited_methods = ap_getword(cmd->pool, &arg, '>');
1252     void *tog = cmd->cmd->cmd_data;
1253     int limited = 0;
1254   
1255     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1256     if (err != NULL) {
1257         return err;
1258     }
1259
1260     /* XXX: NB: Currently, we have no way of checking
1261      * whether <Limit> or <LimitExcept> sections are closed properly.
1262      * (If we would add a srm_command_loop() here we might...)
1263      */
1264     
1265     while (limited_methods[0]) {
1266         char *method = ap_getword_conf(cmd->pool, &limited_methods);
1267         int  methnum = ap_method_number_of(method);
1268
1269         if (methnum == M_TRACE && !tog) {
1270             return "TRACE cannot be controlled by <Limit>";
1271         }
1272         else if (methnum == M_INVALID) {
1273             return ap_pstrcat(cmd->pool, "unknown method \"", method,
1274                               "\" in <Limit", tog ? "Except>" : ">", NULL);
1275         }
1276         else {
1277             limited |= (1 << methnum);
1278         }
1279     }
1280
1281     /* Killing two features with one function,
1282      * if (tog == NULL) <Limit>, else <LimitExcept>
1283      */
1284     cmd->limited = tog ? ~limited : limited;
1285     return NULL;
1286 }
1287
1288 static const char *endlimit_section(cmd_parms *cmd, void *dummy, void *dummy2)
1289 {
1290     void *tog = cmd->cmd->cmd_data;
1291
1292     if (cmd->limited == -1) {
1293         return tog ? "</LimitExcept> unexpected" : "</Limit> unexpected";
1294     }
1295     
1296     cmd->limited = -1;
1297     return NULL;
1298 }
1299
1300 /*
1301  * When a section is not closed properly when end-of-file is reached,
1302  * then an error message should be printed:
1303  */
1304 static const char *missing_endsection(cmd_parms *cmd, int nest)
1305 {
1306     if (nest < 2) {
1307         return ap_psprintf(cmd->pool, "Missing %s directive at end-of-file",
1308                            cmd->end_token);
1309     }
1310     return ap_psprintf(cmd->pool, "%d missing %s directives at end-of-file",
1311                        nest, cmd->end_token);
1312 }
1313
1314 /* We use this in <DirectoryMatch> and <FilesMatch>, to ensure that 
1315  * people don't get bitten by wrong-cased regex matches
1316  */
1317
1318 #ifdef WIN32
1319 #define USE_ICASE REG_ICASE
1320 #else
1321 #define USE_ICASE 0
1322 #endif
1323
1324 static const char *end_nested_section(cmd_parms *cmd, void *dummy)
1325 {
1326     if (cmd->end_token == NULL) {
1327         return ap_pstrcat(cmd->pool, cmd->cmd->name,
1328                           " without matching <", cmd->cmd->name + 2, 
1329                           " section", NULL);
1330     }
1331     /*
1332      * This '!=' may look weird on a string comparison, but it's correct --
1333      * it's been set up so that checking for two pointers to the same datum
1334      * is valid here.  And faster.
1335      */
1336     if (cmd->cmd->name != cmd->end_token) {
1337         return ap_pstrcat(cmd->pool, "Expected ", cmd->end_token, " but saw ",
1338                           cmd->cmd->name, NULL);
1339     }
1340     return cmd->end_token;
1341 }
1342
1343 /*
1344  * Report a missing-'>' syntax error.
1345  */
1346 static char *unclosed_directive(cmd_parms *cmd)
1347 {
1348     return ap_pstrcat(cmd->pool, cmd->cmd->name,
1349                       "> directive missing closing '>'", NULL);
1350 }
1351
1352 static const char *dirsection(cmd_parms *cmd, void *dummy, const char *arg)
1353 {
1354     const char *errmsg;
1355     char *endp = strrchr(arg, '>');
1356     int old_overrides = cmd->override;
1357     char *old_path = cmd->path;
1358     core_dir_config *conf;
1359     void *new_dir_conf = ap_create_per_dir_config(cmd->pool);
1360     regex_t *r = NULL;
1361     const char *old_end_token;
1362     const command_rec *thiscmd = cmd->cmd;
1363
1364     const char *err = ap_check_cmd_context(cmd,
1365                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1366     if (err != NULL) {
1367         return err;
1368     }
1369
1370     if (endp == NULL) {
1371         return unclosed_directive(cmd);
1372     }
1373
1374     *endp = '\0';
1375
1376     cmd->path = ap_getword_conf(cmd->pool, &arg);
1377     cmd->override = OR_ALL|ACCESS_CONF;
1378
1379     if (thiscmd->cmd_data) { /* <DirectoryMatch> */
1380         r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1381     }
1382     else if (!strcmp(cmd->path, "~")) {
1383         cmd->path = ap_getword_conf(cmd->pool, &arg);
1384         r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1385     }
1386     else {
1387         /* Ensure that the pathname is canonical */
1388         cmd->path = ap_os_canonical_filename(cmd->pool, cmd->path);
1389     }
1390
1391     old_end_token = cmd->end_token;
1392     cmd->end_token = thiscmd->cmd_data ? end_directorymatch_section : end_directory_section;
1393     errmsg = ap_srm_command_loop(cmd, new_dir_conf);
1394     if (errmsg == NULL) {
1395         errmsg = missing_endsection(cmd, 1);
1396     }
1397     cmd->end_token = old_end_token;
1398     if (errmsg != (thiscmd->cmd_data 
1399                        ? end_directorymatch_section 
1400                    : end_directory_section)) {
1401         return errmsg;
1402     }
1403
1404     conf = (core_dir_config *)ap_get_module_config(new_dir_conf, &core_module);
1405     conf->r = r;
1406
1407     ap_add_per_dir_conf(cmd->server, new_dir_conf);
1408
1409     if (*arg != '\0') {
1410         return ap_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1411                           "> arguments not (yet) supported.", NULL);
1412     }
1413
1414     cmd->path = old_path;
1415     cmd->override = old_overrides;
1416
1417     return NULL;
1418 }
1419
1420 static const char *urlsection(cmd_parms *cmd, void *dummy, const char *arg)
1421 {
1422     const char *errmsg;
1423     char *endp = strrchr(arg, '>');
1424     int old_overrides = cmd->override;
1425     char *old_path = cmd->path;
1426     core_dir_config *conf;
1427     regex_t *r = NULL;
1428     const char *old_end_token;
1429     const command_rec *thiscmd = cmd->cmd;
1430
1431     void *new_url_conf = ap_create_per_dir_config(cmd->pool);
1432
1433     const char *err = ap_check_cmd_context(cmd,
1434                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1435     if (err != NULL) {
1436         return err;
1437     }
1438
1439     if (endp == NULL) {
1440         return unclosed_directive(cmd);
1441     }
1442
1443     *endp = '\0';
1444
1445     cmd->path = ap_getword_conf(cmd->pool, &arg);
1446     cmd->override = OR_ALL|ACCESS_CONF;
1447
1448     if (thiscmd->cmd_data) { /* <LocationMatch> */
1449         r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
1450     }
1451     else if (!strcmp(cmd->path, "~")) {
1452         cmd->path = ap_getword_conf(cmd->pool, &arg);
1453         r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
1454     }
1455
1456     old_end_token = cmd->end_token;
1457     cmd->end_token = thiscmd->cmd_data ? end_locationmatch_section
1458                                        : end_location_section;
1459     errmsg = ap_srm_command_loop(cmd, new_url_conf);
1460     if (errmsg == NULL) {
1461         errmsg = missing_endsection(cmd, 1);
1462     }
1463     cmd->end_token = old_end_token;
1464     if (errmsg != (thiscmd->cmd_data 
1465                        ? end_locationmatch_section 
1466                        : end_location_section)) {
1467         return errmsg;
1468     }
1469
1470     conf = (core_dir_config *)ap_get_module_config(new_url_conf, &core_module);
1471     conf->d = ap_pstrdup(cmd->pool, cmd->path); /* No mangling, please */
1472     conf->d_is_fnmatch = ap_is_fnmatch(conf->d) != 0;
1473     conf->r = r;
1474
1475     ap_add_per_url_conf(cmd->server, new_url_conf);
1476     
1477     if (*arg != '\0') {
1478         return ap_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1479                           "> arguments not (yet) supported.", NULL);
1480     }
1481
1482     cmd->path = old_path;
1483     cmd->override = old_overrides;
1484
1485     return NULL;
1486 }
1487
1488 static const char *filesection(cmd_parms *cmd, core_dir_config *c,
1489                                const char *arg)
1490 {
1491     const char *errmsg;
1492     char *endp = strrchr(arg, '>');
1493     int old_overrides = cmd->override;
1494     char *old_path = cmd->path;
1495     core_dir_config *conf;
1496     regex_t *r = NULL;
1497     const char *old_end_token;
1498     const command_rec *thiscmd = cmd->cmd;
1499
1500     void *new_file_conf = ap_create_per_dir_config(cmd->pool);
1501
1502     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_LOCATION);
1503     if (err != NULL) {
1504         return err;
1505     }
1506
1507     if (endp == NULL) {
1508         return unclosed_directive(cmd);
1509     }
1510
1511     *endp = '\0';
1512
1513     cmd->path = ap_getword_conf(cmd->pool, &arg);
1514     /* Only if not an .htaccess file */
1515     if (!old_path) {
1516         cmd->override = OR_ALL|ACCESS_CONF;
1517     }
1518
1519     if (thiscmd->cmd_data) { /* <FilesMatch> */
1520         r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1521     }
1522     else if (!strcmp(cmd->path, "~")) {
1523         cmd->path = ap_getword_conf(cmd->pool, &arg);
1524         r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
1525     }
1526     else {
1527         /* Ensure that the pathname is canonical */
1528         cmd->path = ap_os_canonical_filename(cmd->pool, cmd->path);
1529     }
1530
1531     old_end_token = cmd->end_token;
1532     cmd->end_token = thiscmd->cmd_data ? end_filesmatch_section : end_files_section;
1533     errmsg = ap_srm_command_loop(cmd, new_file_conf);
1534     if (errmsg == NULL) {
1535         errmsg = missing_endsection(cmd, 1);
1536     }
1537     cmd->end_token = old_end_token;
1538     if (errmsg != (thiscmd->cmd_data 
1539                        ? end_filesmatch_section 
1540                    : end_files_section)) {
1541         return errmsg;
1542     }
1543
1544     conf = (core_dir_config *)ap_get_module_config(new_file_conf,
1545                                                    &core_module);
1546     conf->d = cmd->path;
1547     conf->d_is_fnmatch = ap_is_fnmatch(conf->d) != 0;
1548     conf->r = r;
1549
1550     ap_add_file_conf(c, new_file_conf);
1551
1552     if (*arg != '\0') {
1553         return ap_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1554                           "> arguments not (yet) supported.", NULL);
1555     }
1556
1557     cmd->path = old_path;
1558     cmd->override = old_overrides;
1559
1560     return NULL;
1561 }
1562
1563 /* XXX: NB: Currently, we have no way of checking
1564  * whether <IfModule> sections are closed properly.
1565  * Extra (redundant, unpaired) </IfModule> directives are
1566  * simply silently ignored.
1567  */
1568 static const char *end_ifmod(cmd_parms *cmd, void *dummy)
1569 {
1570     return NULL;
1571 }
1572
1573 static const char *start_ifmod(cmd_parms *cmd, void *dummy, char *arg)
1574 {
1575     char *endp = strrchr(arg, '>');
1576     char l[MAX_STRING_LEN];
1577     int not = (arg[0] == '!');
1578     module *found;
1579     int nest = 1;
1580
1581     if (endp == NULL) {
1582         return unclosed_directive(cmd);
1583     }
1584
1585     *endp = '\0';
1586
1587     if (not) {
1588         arg++;
1589     }
1590
1591     found = ap_find_linked_module(arg);
1592
1593     if ((!not && found) || (not && !found)) {
1594         return NULL;
1595     }
1596
1597     while (nest && !(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) {
1598         if (!strncasecmp(l, "<IfModule", 9)) {
1599             nest++;
1600         }
1601         if (!strcasecmp(l, "</IfModule>")) {
1602           nest--;
1603         }
1604     }
1605
1606     if (nest) {
1607         cmd->end_token = end_ifmodule_section;
1608         return missing_endsection(cmd, nest);
1609     }
1610     return NULL;
1611 }
1612
1613 API_EXPORT(int) ap_exists_config_define(char *name)
1614 {
1615     char **defines;
1616     int i;
1617
1618     defines = (char **)ap_server_config_defines->elts;
1619     for (i = 0; i < ap_server_config_defines->nelts; i++) {
1620         if (strcmp(defines[i], name) == 0) {
1621             return 1;
1622         }
1623     }
1624     return 0;
1625 }
1626
1627 static const char *end_ifdefine(cmd_parms *cmd, void *dummy) 
1628 {
1629     return NULL;
1630 }
1631
1632 static const char *start_ifdefine(cmd_parms *cmd, void *dummy, char *arg)
1633 {
1634     char *endp;
1635     char l[MAX_STRING_LEN];
1636     int defined;
1637     int not = 0;
1638     int nest = 1;
1639
1640     endp = strrchr(arg, '>');
1641     if (endp == NULL) {
1642         return unclosed_directive(cmd);
1643     }
1644
1645     *endp = '\0';
1646
1647     if (arg[0] == '!') {
1648         not = 1;
1649         arg++;
1650     }
1651
1652     defined = ap_exists_config_define(arg);
1653
1654     if ((!not && defined) || (not && !defined)) {
1655         return NULL;
1656     }
1657
1658     while (nest && !(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) {
1659         if (!strncasecmp(l, "<IfDefine", 9)) {
1660             nest++;
1661         }
1662         if (!strcasecmp(l, "</IfDefine>")) {
1663             nest--;
1664         }
1665     }
1666     if (nest) {
1667         cmd->end_token = end_ifdefine_section;
1668         return missing_endsection(cmd, nest);
1669     }
1670     return NULL;
1671 }
1672
1673 /* httpd.conf commands... beginning with the <VirtualHost> business */
1674
1675 static const char *virtualhost_section(cmd_parms *cmd, void *dummy, char *arg)
1676 {
1677     server_rec *main_server = cmd->server, *s;
1678     const char *errmsg;
1679     char *endp = strrchr(arg, '>');
1680     ap_context_t *p = cmd->pool, *ptemp = cmd->temp_pool;
1681     const char *old_end_token;
1682
1683     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1684     if (err != NULL) {
1685         return err;
1686     }
1687
1688     if (endp == NULL) {
1689         return unclosed_directive(cmd);
1690     }
1691
1692     *endp = '\0';
1693     
1694     /* FIXME: There's another feature waiting to happen here -- since you
1695         can now put multiple addresses/names on a single <VirtualHost>
1696         you might want to use it to group common definitions and then
1697         define other "subhosts" with their individual differences.  But
1698         personally I'd rather just do it with a macro preprocessor. -djg */
1699     if (main_server->is_virtual) {
1700         return "<VirtualHost> doesn't nest!";
1701     }
1702     
1703     errmsg = ap_init_virtual_host(p, arg, main_server, &s);
1704     if (errmsg) {
1705         return errmsg;
1706     }
1707
1708     s->next = main_server->next;
1709     main_server->next = s;
1710
1711     s->defn_name = cmd->config_file->name;
1712     s->defn_line_number = cmd->config_file->line_number;
1713
1714     old_end_token = cmd->end_token;
1715     cmd->end_token = end_virtualhost_section;
1716     cmd->server = s;
1717     errmsg = ap_srm_command_loop(cmd, s->lookup_defaults);
1718     cmd->server = main_server;
1719     if (errmsg == NULL) {
1720         errmsg = missing_endsection(cmd, 1);
1721     }
1722     cmd->end_token = old_end_token;
1723
1724     if (s->srm_confname) {
1725         ap_process_resource_config(s, s->srm_confname, p, ptemp);
1726     }
1727
1728     if (s->access_confname) {
1729         ap_process_resource_config(s, s->access_confname, p, ptemp);
1730     }
1731     
1732     if (errmsg == end_virtualhost_section) {
1733         return NULL;
1734     }
1735     return errmsg;
1736 }
1737
1738 static const char *set_server_alias(cmd_parms *cmd, void *dummy,
1739                                     const char *arg)
1740 {
1741     if (!cmd->server->names) {
1742         return "ServerAlias only used in <VirtualHost>";
1743     }
1744     while (*arg) {
1745         char **item, *name = ap_getword_conf(cmd->pool, &arg);
1746         if (ap_is_matchexp(name)) {
1747             item = (char **)ap_push_array(cmd->server->wild_names);
1748         }
1749         else {
1750             item = (char **)ap_push_array(cmd->server->names);
1751         }
1752         *item = name;
1753     }
1754     return NULL;
1755 }
1756
1757 static const char *add_module_command(cmd_parms *cmd, void *dummy, char *arg)
1758 {
1759     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1760     if (err != NULL) {
1761         return err;
1762     }
1763
1764     if (!ap_add_named_module(arg)) {
1765         return ap_pstrcat(cmd->pool, "Cannot add module via name '", arg, 
1766                           "': not in list of loaded modules", NULL);
1767     }
1768     return NULL;
1769 }
1770
1771 static const char *clear_module_list_command(cmd_parms *cmd, void *dummy)
1772 {
1773     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1774     if (err != NULL) {
1775         return err;
1776     }
1777
1778     ap_clear_module_list();
1779     return NULL;
1780 }
1781
1782 static const char *set_server_string_slot(cmd_parms *cmd, void *dummy,
1783                                           char *arg)
1784 {
1785     /* This one's pretty generic... */
1786   
1787     int offset = (int)(long)cmd->info;
1788     char *struct_ptr = (char *)cmd->server;
1789     
1790     const char *err = ap_check_cmd_context(cmd, 
1791                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1792     if (err != NULL) {
1793         return err;
1794     }
1795
1796     *(char **)(struct_ptr + offset) = arg;
1797     return NULL;
1798 }
1799
1800 static const char *server_port(cmd_parms *cmd, void *dummy, char *arg)
1801 {
1802     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1803     int port;
1804
1805     if (err != NULL) {
1806         return err;
1807     }
1808     port = atoi(arg);
1809     if (port <= 0 || port >= 65536) { /* 65536 == 1<<16 */
1810         return ap_pstrcat(cmd->temp_pool, "The port number \"", arg, 
1811                           "\" is outside the appropriate range "
1812                           "(i.e., 1..65535).", NULL);
1813     }
1814     cmd->server->port = port;
1815     return NULL;
1816 }
1817
1818 static const char *set_signature_flag(cmd_parms *cmd, core_dir_config *d, 
1819                                       char *arg)
1820 {
1821     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1822     if (err != NULL) {
1823         return err;
1824     }
1825
1826     if (strcasecmp(arg, "On") == 0) {
1827         d->server_signature = srv_sig_on;
1828     }
1829     else if (strcasecmp(arg, "Off") == 0) {
1830         d->server_signature = srv_sig_off;
1831     }
1832     else if (strcasecmp(arg, "EMail") == 0) {
1833         d->server_signature = srv_sig_withmail;
1834     }
1835     else {
1836         return "ServerSignature: use one of: off | on | email";
1837     }
1838     return NULL;
1839 }
1840
1841 static const char *set_server_root(cmd_parms *cmd, void *dummy, char *arg) 
1842 {
1843     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1844
1845     if (err != NULL) {
1846         return err;
1847     }
1848
1849     arg = ap_os_canonical_filename(cmd->pool, arg);
1850
1851     if (!ap_is_directory(arg)) {
1852         return "ServerRoot must be a valid directory";
1853     }
1854     ap_server_root = arg;
1855     return NULL;
1856 }
1857
1858 static const char *set_timeout(cmd_parms *cmd, void *dummy, char *arg)
1859 {
1860     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1861     if (err != NULL) {
1862         return err;
1863     }
1864
1865     cmd->server->timeout = atoi(arg);
1866     return NULL;
1867 }
1868
1869 static const char *set_keep_alive_timeout(cmd_parms *cmd, void *dummy,
1870                                           char *arg)
1871 {
1872     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1873     if (err != NULL) {
1874         return err;
1875     }
1876
1877     cmd->server->keep_alive_timeout = atoi(arg);
1878     return NULL;
1879 }
1880
1881 static const char *set_keep_alive(cmd_parms *cmd, void *dummy, char *arg) 
1882 {
1883     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1884     if (err != NULL) {
1885         return err;
1886     }
1887
1888     /* We've changed it to On/Off, but used to use numbers
1889      * so we accept anything but "Off" or "0" as "On"
1890      */
1891     if (!strcasecmp(arg, "off") || !strcmp(arg, "0")) {
1892         cmd->server->keep_alive = 0;
1893     }
1894     else {
1895         cmd->server->keep_alive = 1;
1896     }
1897     return NULL;
1898 }
1899
1900 static const char *set_keep_alive_max(cmd_parms *cmd, void *dummy, char *arg) 
1901 {
1902     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1903     if (err != NULL) {
1904         return err;
1905     }
1906
1907     cmd->server->keep_alive_max = atoi(arg);
1908     return NULL;
1909 }
1910
1911 static const char *set_idcheck(cmd_parms *cmd, core_dir_config *d, int arg) 
1912 {
1913     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1914     if (err != NULL) {
1915         return err;
1916     }
1917
1918     d->do_rfc1413 = arg != 0;
1919     return NULL;
1920 }
1921
1922 static const char *set_hostname_lookups(cmd_parms *cmd, core_dir_config *d,
1923                                         char *arg)
1924 {
1925     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1926     if (err != NULL) {
1927         return err;
1928     }
1929
1930     if (!strcasecmp(arg, "on")) {
1931         d->hostname_lookups = HOSTNAME_LOOKUP_ON;
1932     }
1933     else if (!strcasecmp(arg, "off")) {
1934         d->hostname_lookups = HOSTNAME_LOOKUP_OFF;
1935     }
1936     else if (!strcasecmp(arg, "double")) {
1937         d->hostname_lookups = HOSTNAME_LOOKUP_DOUBLE;
1938     }
1939     else {
1940         return "parameter must be 'on', 'off', or 'double'";
1941     }
1942     return NULL;
1943 }
1944
1945 static const char *set_serverpath(cmd_parms *cmd, void *dummy, char *arg) 
1946 {
1947     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1948     if (err != NULL) {
1949         return err;
1950     }
1951
1952     cmd->server->path = arg;
1953     cmd->server->pathlen = strlen(arg);
1954     return NULL;
1955 }
1956
1957 static const char *set_content_md5(cmd_parms *cmd, core_dir_config *d, int arg)
1958 {
1959     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1960     if (err != NULL) {
1961         return err;
1962     }
1963
1964     d->content_md5 = arg != 0;
1965     return NULL;
1966 }
1967
1968 static const char *set_use_canonical_name(cmd_parms *cmd, core_dir_config *d, 
1969                                           char *arg)
1970 {
1971     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1972     if (err != NULL) {
1973         return err;
1974     }
1975
1976     if (strcasecmp(arg, "on") == 0) {
1977         d->use_canonical_name = USE_CANONICAL_NAME_ON;
1978     }
1979     else if (strcasecmp(arg, "off") == 0) {
1980         d->use_canonical_name = USE_CANONICAL_NAME_OFF;
1981     }
1982     else if (strcasecmp(arg, "dns") == 0) {
1983         d->use_canonical_name = USE_CANONICAL_NAME_DNS;
1984     }
1985     else {
1986         return "parameter must be 'on', 'off', or 'dns'";
1987     }
1988     return NULL;
1989 }
1990
1991
1992 static const char *include_config (cmd_parms *cmd, void *dummy, char *name)
1993 {
1994     ap_process_resource_config(cmd->server,
1995         ap_server_root_relative(cmd->pool, name),
1996         cmd->pool, cmd->temp_pool);
1997     return NULL;
1998 }
1999
2000 static const char *set_loglevel(cmd_parms *cmd, void *dummy, const char *arg) 
2001 {
2002     char *str;
2003     
2004     const char *err = ap_check_cmd_context(cmd,
2005                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2006     if (err != NULL) {
2007         return err;
2008     }
2009
2010     if ((str = ap_getword_conf(cmd->pool, &arg))) {
2011         if (!strcasecmp(str, "emerg")) {
2012             cmd->server->loglevel = APLOG_EMERG;
2013         }
2014         else if (!strcasecmp(str, "alert")) {
2015             cmd->server->loglevel = APLOG_ALERT;
2016         }
2017         else if (!strcasecmp(str, "crit")) {
2018             cmd->server->loglevel = APLOG_CRIT;
2019         }
2020         else if (!strcasecmp(str, "error")) {
2021             cmd->server->loglevel = APLOG_ERR;
2022         }
2023         else if (!strcasecmp(str, "warn")) {
2024             cmd->server->loglevel = APLOG_WARNING;
2025         }
2026         else if (!strcasecmp(str, "notice")) {
2027             cmd->server->loglevel = APLOG_NOTICE;
2028         }
2029         else if (!strcasecmp(str, "info")) {
2030             cmd->server->loglevel = APLOG_INFO;
2031         }
2032         else if (!strcasecmp(str, "debug")) {
2033             cmd->server->loglevel = APLOG_DEBUG;
2034         }
2035         else {
2036             return "LogLevel requires level keyword: one of "
2037                    "emerg/alert/crit/error/warn/notice/info/debug";
2038         }
2039     }
2040     else {
2041         return "LogLevel requires level keyword";
2042     }
2043
2044     return NULL;
2045 }
2046
2047 API_EXPORT(const char *) ap_psignature(const char *prefix, request_rec *r)
2048 {
2049     char sport[20];
2050     core_dir_config *conf;
2051
2052     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
2053                                                    &core_module);
2054     if ((conf->server_signature == srv_sig_off)
2055             || (conf->server_signature == srv_sig_unset)) {
2056         return "";
2057     }
2058
2059     ap_snprintf(sport, sizeof sport, "%u", (unsigned) ap_get_server_port(r));
2060
2061     if (conf->server_signature == srv_sig_withmail) {
2062         return ap_pstrcat(r->pool, prefix, "<ADDRESS>" SERVER_BASEVERSION
2063                           " Server at <A HREF=\"mailto:",
2064                           r->server->server_admin, "\">",
2065                           ap_get_server_name(r), "</A> Port ", sport,
2066                           "</ADDRESS>\n", NULL);
2067     }
2068     return ap_pstrcat(r->pool, prefix, "<ADDRESS>" SERVER_BASEVERSION
2069                       " Server at ", ap_get_server_name(r), " Port ", sport,
2070                       "</ADDRESS>\n", NULL);
2071 }
2072
2073 /*
2074  * Load an authorisation realm into our location configuration, applying the
2075  * usual rules that apply to realms.
2076  */
2077 static const char *set_authname(cmd_parms *cmd, void *mconfig, char *word1)
2078 {
2079     core_dir_config *aconfig = (core_dir_config *)mconfig;
2080
2081     aconfig->ap_auth_name = ap_escape_quotes(cmd->pool, word1);
2082     return NULL;
2083 }
2084
2085 #ifdef _OSD_POSIX /* BS2000 Logon Passwd file */
2086 static const char *set_bs2000_account(cmd_parms *cmd, void *dummy, char *name)
2087 {
2088     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2089     if (err != NULL) {
2090         return err;
2091     }
2092
2093     return os_set_account(cmd->pool, name);
2094 }
2095 #endif /*_OSD_POSIX*/
2096
2097 /*
2098  * Handle a request to include the server's OS platform in the Server
2099  * response header field (the ServerTokens directive).  Unfortunately
2100  * this requires a new global in order to communicate the setting back to
2101  * http_main so it can insert the information in the right place in the
2102  * string.
2103  */
2104
2105 static const char *set_serv_tokens(cmd_parms *cmd, void *dummy, char *arg) 
2106 {
2107     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2108     if (err != NULL) {
2109         return err;
2110     }
2111
2112     /* TODO: reimplement the server token stuff. */
2113 #if 0
2114     if (!strcasecmp(arg, "OS")) {
2115         ap_server_tokens = SrvTk_OS;
2116     }
2117     else if (!strcasecmp(arg, "Min") || !strcasecmp(arg, "Minimal")) {
2118         ap_server_tokens = SrvTk_MIN;
2119     }
2120     else {
2121         ap_server_tokens = SrvTk_FULL;
2122     }
2123 #endif
2124     return NULL;
2125 }
2126
2127 static const char *set_limit_req_line(cmd_parms *cmd, void *dummy, char *arg)
2128 {
2129     const char *err = ap_check_cmd_context(cmd,
2130                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2131     int lim;
2132
2133     if (err != NULL) {
2134         return err;
2135     }
2136     lim = atoi(arg);
2137     if (lim < 0) {
2138         return ap_pstrcat(cmd->temp_pool, "LimitRequestLine \"", arg, 
2139                           "\" must be a non-negative integer", NULL);
2140     }
2141     if (lim > DEFAULT_LIMIT_REQUEST_LINE) {
2142         return ap_psprintf(cmd->temp_pool, "LimitRequestLine \"%s\" "
2143                            "must not exceed the precompiled maximum of %d",
2144                            arg, DEFAULT_LIMIT_REQUEST_LINE);
2145     }
2146     cmd->server->limit_req_line = lim;
2147     return NULL;
2148 }
2149
2150 static const char *set_limit_req_fieldsize(cmd_parms *cmd, void *dummy,
2151                                            char *arg)
2152 {
2153     const char *err = ap_check_cmd_context(cmd,
2154                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2155     int lim;
2156
2157     if (err != NULL) {
2158         return err;
2159     }
2160     lim = atoi(arg);
2161     if (lim < 0) {
2162         return ap_pstrcat(cmd->temp_pool, "LimitRequestFieldsize \"", arg, 
2163                           "\" must be a non-negative integer (0 = no limit)",
2164                           NULL);
2165     }
2166     if (lim > DEFAULT_LIMIT_REQUEST_FIELDSIZE) {
2167         return ap_psprintf(cmd->temp_pool, "LimitRequestFieldsize \"%s\" "
2168                           "must not exceed the precompiled maximum of %d",
2169                            arg, DEFAULT_LIMIT_REQUEST_FIELDSIZE);
2170     }
2171     cmd->server->limit_req_fieldsize = lim;
2172     return NULL;
2173 }
2174
2175 static const char *set_limit_req_fields(cmd_parms *cmd, void *dummy, char *arg)
2176 {
2177     const char *err = ap_check_cmd_context(cmd,
2178                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2179     int lim;
2180
2181     if (err != NULL) {
2182         return err;
2183     }
2184     lim = atoi(arg);
2185     if (lim < 0) {
2186         return ap_pstrcat(cmd->temp_pool, "LimitRequestFields \"", arg, 
2187                           "\" must be a non-negative integer (0 = no limit)",
2188                           NULL);
2189     }
2190     cmd->server->limit_req_fields = lim;
2191     return NULL;
2192 }
2193
2194 static const char *set_limit_req_body(cmd_parms *cmd, core_dir_config *conf,
2195                                       char *arg) 
2196 {
2197     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2198     if (err != NULL) {
2199         return err;
2200     }
2201
2202     /* WTF: If strtoul is not portable, then write a replacement.
2203      *      Instead we have an idiotic define in httpd.h that prevents
2204      *      it from being used even when it is available. Sheesh.
2205      */
2206     conf->limit_req_body = (unsigned long)strtol(arg, (char **)NULL, 10);
2207     return NULL;
2208 }
2209
2210 #ifdef WIN32
2211 static const char *set_interpreter_source(cmd_parms *cmd, core_dir_config *d,
2212                                                 char *arg)
2213 {
2214     if (!strcasecmp(arg, "registry")) {
2215         d->script_interpreter_source = INTERPRETER_SOURCE_REGISTRY;
2216     } else if (!strcasecmp(arg, "script")) {
2217         d->script_interpreter_source = INTERPRETER_SOURCE_SHEBANG;
2218     } else {
2219         d->script_interpreter_source = INTERPRETER_SOURCE_SHEBANG;
2220     }
2221     return NULL;
2222 }
2223 #endif
2224
2225 /* Note --- ErrorDocument will now work from .htaccess files.  
2226  * The AllowOverride of Fileinfo allows webmasters to turn it off
2227  */
2228
2229 static const command_rec core_cmds[] = {
2230
2231 /* Old access config file commands */
2232
2233 { "<Directory", dirsection, NULL, RSRC_CONF, RAW_ARGS,
2234   "Container for directives affecting resources located in the specified "
2235   "directories" },
2236 { end_directory_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
2237   "Marks end of <Directory>" },
2238 { "<Location", urlsection, NULL, RSRC_CONF, RAW_ARGS,
2239   "Container for directives affecting resources accessed through the "
2240   "specified URL paths" },
2241 { end_location_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
2242   "Marks end of <Location>" },
2243 { "<VirtualHost", virtualhost_section, NULL, RSRC_CONF, RAW_ARGS,
2244   "Container to map directives to a particular virtual host, takes one or "
2245   "more host addresses" },
2246 { end_virtualhost_section, end_nested_section, NULL, RSRC_CONF, NO_ARGS,
2247   "Marks end of <VirtualHost>" },
2248 { "<Files", filesection, NULL, OR_ALL, RAW_ARGS, "Container for directives "
2249   "affecting files matching specified patterns" },
2250 { end_files_section, end_nested_section, NULL, OR_ALL, NO_ARGS,
2251   "Marks end of <Files>" },
2252 { "<Limit", ap_limit_section, NULL, OR_ALL, RAW_ARGS, "Container for "
2253   "authentication directives when accessed using specified HTTP methods" },
2254 { "</Limit>", endlimit_section, NULL, OR_ALL, NO_ARGS,
2255   "Marks end of <Limit>" },
2256 { "<LimitExcept", ap_limit_section, (void*)1, OR_ALL, RAW_ARGS,
2257   "Container for authentication directives to be applied when any HTTP "
2258   "method other than those specified is used to access the resource" },
2259 { "</LimitExcept>", endlimit_section, (void*)1, OR_ALL, NO_ARGS,
2260   "Marks end of <LimitExcept>" },
2261 { "<IfModule", start_ifmod, NULL, OR_ALL, TAKE1,
2262   "Container for directives based on existance of specified modules" },
2263 { end_ifmodule_section, end_ifmod, NULL, OR_ALL, NO_ARGS,
2264   "Marks end of <IfModule>" },
2265 { "<IfDefine", start_ifdefine, NULL, OR_ALL, TAKE1,
2266   "Container for directives based on existance of command line defines" },
2267 { end_ifdefine_section, end_ifdefine, NULL, OR_ALL, NO_ARGS,
2268   "Marks end of <IfDefine>" },
2269 { "<DirectoryMatch", dirsection, (void*)1, RSRC_CONF, RAW_ARGS,
2270   "Container for directives affecting resources located in the "
2271   "specified directories" },
2272 { end_directorymatch_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
2273   "Marks end of <DirectoryMatch>" },
2274 { "<LocationMatch", urlsection, (void*)1, RSRC_CONF, RAW_ARGS,
2275   "Container for directives affecting resources accessed through the "
2276   "specified URL paths" },
2277 { end_locationmatch_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
2278   "Marks end of <LocationMatch>" },
2279 { "<FilesMatch", filesection, (void*)1, OR_ALL, RAW_ARGS,
2280   "Container for directives affecting files matching specified patterns" },
2281 { end_filesmatch_section, end_nested_section, NULL, OR_ALL, NO_ARGS,
2282   "Marks end of <FilesMatch>" },
2283 { "AuthType", ap_set_string_slot,
2284   (void*)XtOffsetOf(core_dir_config, ap_auth_type), OR_AUTHCFG, TAKE1,
2285   "An HTTP authorization type (e.g., \"Basic\")" },
2286 { "AuthName", set_authname, NULL, OR_AUTHCFG, TAKE1,
2287   "The authentication realm (e.g. \"Members Only\")" },
2288 { "Require", require, NULL, OR_AUTHCFG, RAW_ARGS,
2289   "Selects which authenticated users or groups may access a protected space" },
2290 { "Satisfy", satisfy, NULL, OR_AUTHCFG, TAKE1,
2291   "access policy if both allow and require used ('all' or 'any')" },    
2292 #ifdef GPROF
2293 { "GprofDir", set_gprof_dir, NULL, RSRC_CONF, TAKE1,
2294   "Directory to plop gmon.out files" },
2295 #endif
2296
2297 /* Old resource config file commands */
2298   
2299 { "AccessFileName", set_access_name, NULL, RSRC_CONF, RAW_ARGS,
2300   "Name(s) of per-directory config files (default: .htaccess)" },
2301 { "DocumentRoot", set_document_root, NULL, RSRC_CONF, TAKE1,
2302   "Root directory of the document tree"  },
2303 { "ErrorDocument", set_error_document, NULL, OR_FILEINFO, RAW_ARGS,
2304   "Change responses for HTTP errors" },
2305 { "AllowOverride", set_override, NULL, ACCESS_CONF, RAW_ARGS,
2306   "Controls what groups of directives can be configured by per-directory "
2307   "config files" },
2308 { "Options", set_options, NULL, OR_OPTIONS, RAW_ARGS,
2309   "Set a number of attributes for a given directory" },
2310 { "DefaultType", ap_set_string_slot,
2311   (void*)XtOffsetOf (core_dir_config, ap_default_type),
2312   OR_FILEINFO, TAKE1, "the default MIME type for untypable files" },
2313
2314 /* Old server config file commands */
2315
2316 { "Port", server_port, NULL, RSRC_CONF, TAKE1, "A TCP port number"},
2317 { "HostnameLookups", set_hostname_lookups, NULL, ACCESS_CONF|RSRC_CONF, TAKE1,
2318   "\"on\" to enable, \"off\" to disable reverse DNS lookups, or \"double\" to "
2319   "enable double-reverse DNS lookups" },
2320 { "ServerAdmin", set_server_string_slot,
2321   (void *)XtOffsetOf (server_rec, server_admin), RSRC_CONF, TAKE1,
2322   "The email address of the server administrator" },
2323 { "ServerName", set_server_string_slot,
2324   (void *)XtOffsetOf (server_rec, server_hostname), RSRC_CONF, TAKE1,
2325   "The hostname of the server" },
2326 { "ServerSignature", set_signature_flag, NULL, OR_ALL, TAKE1,
2327   "En-/disable server signature (on|off|email)" },
2328 { "ServerRoot", set_server_root, NULL, RSRC_CONF, TAKE1,
2329   "Common directory of server-related files (logs, confs, etc.)" },
2330 { "ErrorLog", set_server_string_slot,
2331   (void *)XtOffsetOf (server_rec, error_fname), RSRC_CONF, TAKE1,
2332   "The filename of the error log" },
2333 { "AccessConfig", set_server_string_slot,
2334   (void *)XtOffsetOf (server_rec, access_confname), RSRC_CONF, TAKE1,
2335   "The filename of the access config file" },
2336 { "ResourceConfig", set_server_string_slot,
2337   (void *)XtOffsetOf (server_rec, srm_confname), RSRC_CONF, TAKE1,
2338   "The filename of the resource config file" },
2339 { "ServerAlias", set_server_alias, NULL, RSRC_CONF, RAW_ARGS,
2340   "A name or names alternately used to access the server" },
2341 { "ServerPath", set_serverpath, NULL, RSRC_CONF, TAKE1,
2342   "The pathname the server can be reached at" },
2343 { "Timeout", set_timeout, NULL, RSRC_CONF, TAKE1, "Timeout duration (sec)" },
2344 { "KeepAliveTimeout", set_keep_alive_timeout, NULL, RSRC_CONF, TAKE1,
2345   "Keep-Alive timeout duration (sec)"},
2346 { "MaxKeepAliveRequests", set_keep_alive_max, NULL, RSRC_CONF, TAKE1,
2347   "Maximum number of Keep-Alive requests per connection, or 0 for infinite" },
2348 { "KeepAlive", set_keep_alive, NULL, RSRC_CONF, TAKE1,
2349   "Whether persistent connections should be On or Off" },
2350 { "IdentityCheck", set_idcheck, NULL, RSRC_CONF|ACCESS_CONF, FLAG,
2351   "Enable identd (RFC 1413) user lookups - SLOW" },
2352 { "ContentDigest", set_content_md5, NULL, OR_OPTIONS,
2353   FLAG, "whether or not to send a Content-MD5 header with each request" },
2354 { "UseCanonicalName", set_use_canonical_name, NULL,
2355   RSRC_CONF, TAKE1,
2356   "How to work out the ServerName : Port when constructing URLs" },
2357 /* TODOC: MaxServers is deprecated */
2358 /* TODOC: ServersSafetyLimit is deprecated */
2359 /* TODO: RlimitFoo should all be part of mod_cgi, not in the core */
2360 /* TODOC: BindAddress deprecated */
2361 { "AddModule", add_module_command, NULL, RSRC_CONF, ITERATE,
2362   "The name of a module" },
2363 { "ClearModuleList", clear_module_list_command, NULL, RSRC_CONF, NO_ARGS, 
2364   NULL },
2365 /* TODO: ListenBacklog in MPM */
2366 { "Include", include_config, NULL, (RSRC_CONF | ACCESS_CONF), TAKE1,
2367   "Name of the config file to be included" },
2368 { "LogLevel", set_loglevel, NULL, RSRC_CONF, TAKE1,
2369   "Level of verbosity in error logging" },
2370 { "NameVirtualHost", ap_set_name_virtual_host, NULL, RSRC_CONF, TAKE1,
2371   "A numeric IP address:port, or the name of a host" },
2372 #ifdef _OSD_POSIX
2373 { "BS2000Account", set_bs2000_account, NULL, RSRC_CONF, TAKE1,
2374   "Name of server User's bs2000 logon account name" },
2375 #endif
2376 #ifdef WIN32
2377 { "ScriptInterpreterSource", set_interpreter_source, NULL, OR_FILEINFO, TAKE1,
2378   "Where to find interpreter to run Win32 scripts (Registry or script shebang line)" },
2379 #endif
2380 { "ServerTokens", set_serv_tokens, NULL, RSRC_CONF, TAKE1,
2381   "Determine tokens displayed in the Server: header - Min(imal), OS or Full" },
2382 { "LimitRequestLine", set_limit_req_line, NULL, RSRC_CONF, TAKE1,
2383   "Limit on maximum size of an HTTP request line"},
2384 { "LimitRequestFieldsize", set_limit_req_fieldsize, NULL, RSRC_CONF, TAKE1,
2385   "Limit on maximum size of an HTTP request header field"},
2386 { "LimitRequestFields", set_limit_req_fields, NULL, RSRC_CONF, TAKE1,
2387   "Limit (0 = unlimited) on max number of header fields in a request message"},
2388 { "LimitRequestBody", set_limit_req_body,
2389   (void*)XtOffsetOf(core_dir_config, limit_req_body),
2390   OR_ALL, TAKE1,
2391   "Limit (in bytes) on maximum size of request message body" },
2392 { NULL }
2393 };
2394
2395 /*****************************************************************
2396  *
2397  * Core handlers for various phases of server operation...
2398  */
2399
2400 static int core_translate(request_rec *r)
2401 {
2402     void *sconf = r->server->module_config;
2403     core_server_config *conf = ap_get_module_config(sconf, &core_module);
2404   
2405     if (r->proxyreq) {
2406         return HTTP_FORBIDDEN;
2407     }
2408     if ((r->uri[0] != '/') && strcmp(r->uri, "*")) {
2409         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
2410                      "Invalid URI in request %s", r->the_request);
2411         return BAD_REQUEST;
2412     }
2413     
2414     if (r->server->path 
2415         && !strncmp(r->uri, r->server->path, r->server->pathlen)
2416         && (r->server->path[r->server->pathlen - 1] == '/'
2417             || r->uri[r->server->pathlen] == '/'
2418             || r->uri[r->server->pathlen] == '\0')) {
2419         r->filename = ap_pstrcat(r->pool, conf->ap_document_root,
2420                                  (r->uri + r->server->pathlen), NULL);
2421     }
2422     else {
2423         /*
2424          * Make sure that we do not mess up the translation by adding two
2425          * /'s in a row.  This happens under windows when the document
2426          * root ends with a /
2427          */
2428         if ((conf->ap_document_root[strlen(conf->ap_document_root)-1] == '/')
2429             && (*(r->uri) == '/')) {
2430             r->filename = ap_pstrcat(r->pool, conf->ap_document_root, r->uri+1,
2431                                      NULL);
2432         }
2433         else {
2434             r->filename = ap_pstrcat(r->pool, conf->ap_document_root, r->uri,
2435                                      NULL);
2436         }
2437     }
2438
2439     return OK;
2440 }
2441
2442 static int do_nothing(request_rec *r) { return OK; }
2443
2444 /*
2445  * Default handler for MIME types without other handlers.  Only GET
2446  * and OPTIONS at this point... anyone who wants to write a generic
2447  * handler for PUT or POST is free to do so, but it seems unwise to provide
2448  * any defaults yet... So, for now, we assume that this will always be
2449  * the last handler called and return 405 or 501.
2450  */
2451
2452 static int default_handler(request_rec *r)
2453 {
2454     core_dir_config *d =
2455             (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
2456     int rangestatus, errstatus;
2457     ap_file_t *fd = NULL;
2458     ap_status_t status;
2459 #ifdef USE_MMAP_FILES
2460     ap_mmap_t *mm = NULL;
2461 #endif
2462 #ifdef CHARSET_EBCDIC
2463     /* To make serving of "raw ASCII text" files easy (they serve faster
2464      * since they don't have to be converted from EBCDIC), a new
2465      * "magic" type prefix was invented: text/x-ascii-{plain,html,...}
2466      * If we detect one of these content types here, we simply correct
2467      * the type to the real text/{plain,html,...} type. Otherwise, we
2468      * set a flag that translation is required later on.
2469      */
2470     int convert_flag = ap_checkconv(r);
2471 #endif
2472
2473     /* This handler has no use for a request body (yet), but we still
2474      * need to read and discard it if the client sent one.
2475      */
2476     if ((errstatus = ap_discard_request_body(r)) != OK) {
2477         return errstatus;
2478     }
2479
2480     r->allowed |= (1 << M_GET) | (1 << M_OPTIONS);
2481
2482     if (r->method_number == M_INVALID) {
2483         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
2484                     "Invalid method in request %s", r->the_request);
2485         return NOT_IMPLEMENTED;
2486     }
2487     if (r->method_number == M_OPTIONS) {
2488         return ap_send_http_options(r);
2489     }
2490     if (r->method_number == M_PUT) {
2491         return METHOD_NOT_ALLOWED;
2492     }
2493     if (r->finfo.st_mode == 0 || (r->path_info && *r->path_info)) {
2494         ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r,
2495                       "File does not exist: %s",r->path_info ?
2496                       ap_pstrcat(r->pool, r->filename, r->path_info, NULL)
2497                       : r->filename);
2498         return HTTP_NOT_FOUND;
2499     }
2500     if (r->method_number != M_GET) {
2501         return METHOD_NOT_ALLOWED;
2502     }
2503         
2504     if ((status = ap_open(&fd, r->filename, APR_READ | APR_BINARY, 0, r->pool)) != APR_SUCCESS) {
2505         ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
2506                      "file permissions deny server access: %s", r->filename);
2507         return FORBIDDEN;
2508     }
2509         
2510     ap_update_mtime(r, r->finfo.st_mtime);
2511     ap_set_last_modified(r);
2512     ap_set_etag(r);
2513     ap_table_setn(r->headers_out, "Accept-Ranges", "bytes");
2514     if (((errstatus = ap_meets_conditions(r)) != OK)
2515         || (errstatus = ap_set_content_length(r, r->finfo.st_size))) {
2516         ap_close(fd);
2517         return errstatus;
2518     }
2519
2520 #ifdef USE_MMAP_FILES
2521     if ((r->finfo.st_size >= MMAP_THRESHOLD)
2522         && (r->finfo.st_size < MMAP_LIMIT)
2523         && (!r->header_only || (d->content_md5 & 1))) {
2524         /* we need to protect ourselves in case we die while we've got the
2525          * file mmapped */
2526     if (ap_mmap_create(&mm, fd, 0, r->finfo.st_size, r->pool) != APR_SUCCESS){
2527             ap_log_rerror(APLOG_MARK, APLOG_CRIT, errno, r,
2528                          "default_handler: mmap failed: %s", r->filename);
2529             mm = NULL;
2530         }
2531     }
2532     else {
2533         mm = NULL;
2534     }
2535
2536     if (mm == NULL) {
2537 #endif
2538
2539 #ifdef CHARSET_EBCDIC
2540         if (d->content_md5 & 1) {
2541             ap_table_setn(r->headers_out, "Content-MD5",
2542                           ap_md5digest(r->pool, fd, convert_flag));
2543         }
2544 #else
2545         if (d->content_md5 & 1) {
2546             ap_table_setn(r->headers_out, "Content-MD5",
2547                           ap_md5digest(r->pool, fd));
2548         }
2549 #endif /* CHARSET_EBCDIC */
2550
2551         rangestatus = ap_set_byterange(r);
2552
2553         ap_send_http_header(r);
2554         
2555         if (!r->header_only) {
2556             if (!rangestatus) {
2557                 ap_send_fd(fd, r);
2558             }
2559             else {
2560                 long     length;
2561                 ap_off_t offset;
2562
2563                 while (ap_each_byterange(r, &offset, &length)) {
2564                     if ((status = ap_seek(fd, APR_SET, &offset)) != APR_SUCCESS) {
2565                         ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
2566                                   "error byteserving file: %s", r->filename);
2567                         ap_close(fd);
2568                         return HTTP_INTERNAL_SERVER_ERROR;
2569                     }
2570                     ap_send_fd_length(fd, r, length);
2571                 }
2572             }
2573         }
2574
2575 #ifdef USE_MMAP_FILES
2576     }
2577     else {
2578         char *addr;
2579     ap_mmap_offset((void**)&addr, mm ,0);
2580
2581         if (d->content_md5 & 1) {
2582             AP_MD5_CTX context;
2583             
2584             ap_MD5Init(&context);
2585             ap_MD5Update(&context, addr, (unsigned int)r->finfo.st_size);
2586             ap_table_setn(r->headers_out, "Content-MD5",
2587                           ap_md5contextTo64(r->pool, &context));
2588         }
2589
2590         rangestatus = ap_set_byterange(r);
2591         ap_send_http_header(r);
2592         
2593         if (!r->header_only) {
2594             if (!rangestatus) {
2595                 ap_send_mmap(mm, r, 0, r->finfo.st_size);
2596             }
2597             else {
2598                 ap_off_t offset;
2599                 long length;
2600                 while (ap_each_byterange(r, &offset, &length)) {
2601                     ap_send_mmap(mm, r, offset, length);
2602                 }
2603             }
2604         }
2605     }
2606 #endif
2607
2608     ap_close(fd);
2609     return OK;
2610 }
2611
2612 static const handler_rec core_handlers[] = {
2613 { "*/*", default_handler },
2614 { "default-handler", default_handler },
2615 { NULL, NULL }
2616 };
2617
2618 static void core_open_logs(ap_context_t *pconf, ap_context_t *plog, ap_context_t *ptemp, server_rec *s)
2619 {
2620     ap_open_logs(s, pconf);
2621 }
2622
2623 static const char *core_method(const request_rec *r)
2624     { return "http"; }
2625
2626 static unsigned short core_port(const request_rec *r)
2627     { return DEFAULT_HTTP_PORT; }
2628
2629 static void register_hooks(void)
2630 {
2631     ap_hook_translate_name(core_translate,NULL,NULL,HOOK_REALLY_LAST);
2632     ap_hook_process_connection(ap_process_http_connection,NULL,NULL,
2633                                HOOK_REALLY_LAST);
2634     ap_hook_http_method(core_method,NULL,NULL,HOOK_REALLY_LAST);
2635     ap_hook_default_port(core_port,NULL,NULL,HOOK_REALLY_LAST);
2636     ap_hook_open_logs(core_open_logs,NULL,NULL,HOOK_MIDDLE);
2637     /* FIXME: I suspect we can eliminate the need for these - Ben */
2638     ap_hook_type_checker(do_nothing,NULL,NULL,HOOK_REALLY_LAST);
2639     ap_hook_access_checker(do_nothing,NULL,NULL,HOOK_REALLY_LAST);
2640 }
2641
2642 API_VAR_EXPORT module core_module = {
2643     STANDARD20_MODULE_STUFF,
2644     create_core_dir_config,     /* create per-directory config structure */
2645     merge_core_dir_configs,     /* merge per-directory config structures */
2646     create_core_server_config,  /* create per-server config structure */
2647     merge_core_server_configs,  /* merge per-server config structures */
2648     core_cmds,                  /* command ap_table_t */
2649     core_handlers,              /* handlers */
2650     register_hooks              /* register hooks */
2651 };