]> granicus.if.org Git - apache/blob - server/config.c
Performance: Add quick_handler hook. This hook is called at the
[apache] / server / config.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  *    if any, must include the following acknowledgment:
21  *       "This product includes software developed by the
22  *        Apache Software Foundation (http://www.apache.org/)."
23  *    Alternately, this acknowledgment may appear in the software itself,
24  *    if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Apache" and "Apache Software Foundation" must
27  *    not be used to endorse or promote products derived from this
28  *    software without prior written permission. For written
29  *    permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache",
32  *    nor may "Apache" appear in their name, without prior written
33  *    permission of the Apache Software Foundation.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation.  For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  *
54  * Portions of this software are based upon public domain software
55  * originally written at the National Center for Supercomputing Applications,
56  * University of Illinois, Urbana-Champaign.
57  */
58
59 /*
60  * http_config.c: once was auxillary functions for reading httpd's config
61  * file and converting filenames into a namespace
62  *
63  * Rob McCool 
64  * 
65  * Wall-to-wall rewrite for Apache... commands which are part of the
66  * server core can now be found next door in "http_core.c".  Now contains
67  * general command loop, and functions which do bookkeeping for the new
68  * Apache config stuff (modules and configuration vectors).
69  *
70  * rst
71  *
72  */
73
74 #include "apr.h"
75 #include "apr_strings.h"
76 #include "apr_portable.h"
77 #include "apr_file_io.h"
78
79 #define APR_WANT_STDIO
80 #define APR_WANT_STRFUNC
81 #include "apr_want.h"
82
83 #define CORE_PRIVATE
84
85 #include "ap_config.h"
86 #include "httpd.h"
87 #include "http_config.h"
88 #include "http_protocol.h"
89 #include "http_core.h"
90 #include "http_log.h"           /* for errors in parse_htaccess */
91 #include "http_request.h"       /* for default_handler (see invoke_handler) */
92 #include "http_main.h"
93 #include "http_vhost.h"
94 #include "util_cfgtree.h"
95
96
97 AP_DECLARE_DATA const char *ap_server_argv0;
98
99 AP_DECLARE_DATA const char *ap_server_root;
100
101 AP_DECLARE_DATA apr_array_header_t *ap_server_pre_read_config;
102 AP_DECLARE_DATA apr_array_header_t *ap_server_post_read_config;
103 AP_DECLARE_DATA apr_array_header_t *ap_server_config_defines;
104
105 AP_DECLARE_DATA ap_directive_t *ap_conftree;
106
107 APR_HOOK_STRUCT(
108                APR_HOOK_LINK(header_parser)
109                APR_HOOK_LINK(pre_config)
110                APR_HOOK_LINK(post_config)
111                APR_HOOK_LINK(open_logs)
112                APR_HOOK_LINK(child_init)
113                APR_HOOK_LINK(handler)
114                APR_HOOK_LINK(quick_handler)
115                APR_HOOK_LINK(optional_fn_retrieve)
116 )
117
118 AP_IMPLEMENT_HOOK_RUN_ALL(int,header_parser,
119                           (request_rec *r),(r),OK,DECLINED)
120 AP_IMPLEMENT_HOOK_VOID(pre_config,
121                        (apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp),
122                        (pconf,plog,ptemp))
123 AP_IMPLEMENT_HOOK_VOID(post_config,
124                        (apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp,
125                         server_rec *s),(pconf,plog,ptemp,s))
126 AP_IMPLEMENT_HOOK_VOID(open_logs,
127                        (apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, 
128                         server_rec *s),(pconf,plog,ptemp,s))
129 AP_IMPLEMENT_HOOK_VOID(child_init,
130                        (apr_pool_t *pchild, server_rec *s),(pchild,s))
131
132 AP_IMPLEMENT_HOOK_RUN_FIRST(int,handler,(request_rec *r),
133                             (r),DECLINED)
134 AP_IMPLEMENT_HOOK_RUN_FIRST(int,quick_handler,(request_rec *r),
135                             (r),DECLINED)
136
137 AP_IMPLEMENT_HOOK_VOID(optional_fn_retrieve,(void),())
138
139 /****************************************************************
140  *
141  * We begin with the functions which deal with the linked list
142  * of modules which control just about all of the server operation.
143  */
144
145 /* total_modules is the number of modules that have been linked
146  * into the server.
147  */
148 static int total_modules = 0;
149 /* dynamic_modules is the number of modules that have been added
150  * after the pre-loaded ones have been set up. It shouldn't be larger
151  * than DYNAMIC_MODULE_LIMIT.
152  */
153 static int dynamic_modules = 0;
154 AP_DECLARE_DATA module *ap_top_module = NULL;
155 AP_DECLARE_DATA module **ap_loaded_modules=NULL;
156
157 typedef int (*handler_func) (request_rec *);
158 typedef void *(*dir_maker_func) (apr_pool_t *, char *);
159 typedef void *(*merger_func) (apr_pool_t *, void *, void *);
160
161 /* Dealing with config vectors.  These are associated with per-directory,
162  * per-server, and per-request configuration, and have a void* pointer for
163  * each modules.  The nature of the structure pointed to is private to the
164  * module in question... the core doesn't (and can't) know.  However, there
165  * are defined interfaces which allow it to create instances of its private
166  * per-directory and per-server structures, and to merge the per-directory
167  * structures of a directory and its subdirectory (producing a new one in
168  * which the defaults applying to the base directory have been properly
169  * overridden).
170  */
171
172 static ap_conf_vector_t *create_empty_config(apr_pool_t *p)
173 {
174     void *conf_vector = apr_pcalloc(p, sizeof(void *) *
175                                     (total_modules + DYNAMIC_MODULE_LIMIT));
176     return conf_vector;
177 }
178
179 static ap_conf_vector_t *create_default_per_dir_config(apr_pool_t *p)
180 {
181     void **conf_vector = apr_pcalloc(p, sizeof(void *) *
182                                      (total_modules + DYNAMIC_MODULE_LIMIT));
183     module *modp;
184
185     for (modp = ap_top_module; modp; modp = modp->next) {
186         dir_maker_func df = modp->create_dir_config;
187
188         if (df)
189             conf_vector[modp->module_index] = (*df) (p, NULL);
190     }
191
192     return (ap_conf_vector_t *) conf_vector;
193 }
194
195 ap_conf_vector_t *ap_merge_per_dir_configs(apr_pool_t *p,
196                                            ap_conf_vector_t *base,
197                                            ap_conf_vector_t *new_conf)
198 {
199     void **conf_vector = apr_palloc(p, sizeof(void *) * total_modules);
200     void **base_vector = (void **) base;
201     void **new_vector = (void **) new_conf;
202     module *modp;
203
204     for (modp = ap_top_module; modp; modp = modp->next) {
205         merger_func df = modp->merge_dir_config;
206         int i = modp->module_index;
207
208         if (df && new_vector[i])
209             conf_vector[i] = (*df) (p, base_vector[i], new_vector[i]);
210         else
211             conf_vector[i] = new_vector[i] ? new_vector[i] : base_vector[i];
212     }
213
214     return (ap_conf_vector_t *) conf_vector;
215 }
216
217 static ap_conf_vector_t *create_server_config(apr_pool_t *p, server_rec *s)
218 {
219     void **conf_vector = apr_pcalloc(p, sizeof(void *) *
220                                      (total_modules + DYNAMIC_MODULE_LIMIT));
221     module *modp;
222
223     for (modp = ap_top_module; modp; modp = modp->next) {
224         if (modp->create_server_config)
225             conf_vector[modp->module_index] = (*modp->create_server_config) (p, s);
226     }
227
228     return (ap_conf_vector_t *) conf_vector;
229 }
230
231 static void merge_server_configs(apr_pool_t *p, ap_conf_vector_t *base,
232                                  ap_conf_vector_t *virt)
233 {
234     /* Can reuse the 'virt' vector for the spine of it, since we don't
235      * have to deal with the moral equivalent of .htaccess files here...
236      */
237
238     void **base_vector = (void **) base;
239     void **virt_vector = (void **) virt;
240     module *modp;
241
242     for (modp = ap_top_module; modp; modp = modp->next) {
243         merger_func df = modp->merge_server_config;
244         int i = modp->module_index;
245
246         if (!virt_vector[i])
247             virt_vector[i] = base_vector[i];
248         else if (df)
249             virt_vector[i] = (*df) (p, base_vector[i], virt_vector[i]);
250     }
251 }
252
253 ap_conf_vector_t *ap_create_request_config(apr_pool_t *p)
254 {
255     return create_empty_config(p);
256 }
257
258 ap_conf_vector_t *ap_create_conn_config(apr_pool_t *p)
259 {
260     return create_empty_config(p);
261 }
262
263 AP_CORE_DECLARE(ap_conf_vector_t *) ap_create_per_dir_config(apr_pool_t *p)
264 {
265     return create_empty_config(p);
266 }
267
268 int ap_invoke_handler(request_rec *r)
269 {
270     const char *handler;
271     const char *p;
272     char *p2;
273     int result;
274     char hbuf[MAX_STRING_LEN];
275     const char *old_handler = r->handler;
276
277     if (!r->handler) {
278         handler = r->content_type ? r->content_type : ap_default_type(r);
279         if ((p=ap_strchr_c(handler, ';')) != NULL) {
280             apr_cpystrn(hbuf, handler, sizeof hbuf);
281             p2 = hbuf+(handler-p);
282             handler = hbuf;
283             /* MIME type arguments */
284             while (p2 > handler && p2[-1] == ' ')
285                 --p2;           /* strip trailing spaces */
286             *p2='\0';
287         }
288         r->handler = handler;
289     }
290
291     result = ap_run_handler(r);
292
293     r->handler = old_handler;
294
295     if (result == DECLINED && r->handler && r->filename) {
296         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r,
297             "handler \"%s\" not found for: %s", r->handler, r->filename);
298     }
299     return result == DECLINED ? HTTP_INTERNAL_SERVER_ERROR : result;
300 }
301
302 AP_DECLARE(int) ap_method_is_limited(cmd_parms *cmd, const char *method) {
303     int methnum;
304     int i;
305     char **xmethod;
306
307     methnum = ap_method_number_of(method);
308     /*
309      * The simple case: a method hard-coded into Apache.
310      */
311     if (methnum != M_INVALID) {
312         return (methnum & cmd->limited);
313     }
314     /*
315      * Some extension method we don't know implicitly.
316      */
317     if ((cmd->limited_xmethods == NULL)
318         || (cmd->limited_xmethods->nelts == 0)) {
319         return 0;
320     }
321     xmethod = (char **) cmd->limited_xmethods->elts;
322     for (i = 0; i < cmd->limited_xmethods->nelts; ++i) {
323         if (strcmp(method, xmethod[i]) == 0) {
324             return 1;
325         }
326     }
327     return 0;
328 }
329
330 AP_DECLARE(void) ap_register_hooks(module *m, apr_pool_t *p)
331 {
332     if(m->register_hooks)
333     {
334         if(getenv("SHOW_HOOKS"))
335         {
336             printf("Registering hooks for %s\n",m->name);
337             apr_debug_module_hooks=1;
338         }
339         apr_current_hooking_module=m->name;
340         m->register_hooks(p);
341     }
342 }
343
344 /* One-time setup for precompiled modules --- NOT to be done on restart */
345
346 AP_DECLARE(void) ap_add_module(module *m, apr_pool_t *p)
347 {
348     /* This could be called from an AddModule httpd.conf command,
349      * after the file has been linked and the module structure within it
350      * teased out...
351      */
352
353     if (m->version != MODULE_MAGIC_NUMBER_MAJOR) {
354         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
355                      "%s: module \"%s\" is not compatible with this "
356                      "version of Apache.", ap_server_argv0, m->name);
357         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Please contact the vendor for the correct version.");
358         exit(1);
359     }
360
361     if (m->next == NULL) {
362         m->next = ap_top_module;
363         ap_top_module = m;
364     }
365     if (m->module_index == -1) {
366         m->module_index = total_modules++;
367         dynamic_modules++;
368
369         if (dynamic_modules > DYNAMIC_MODULE_LIMIT) {
370             ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
371                          "%s: module \"%s\" could not be loaded, because"
372                          " the dynamic", ap_server_argv0, m->name);
373             ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
374                          "module limit was reached. Please increase "
375                          "DYNAMIC_MODULE_LIMIT and recompile.");
376             exit(1);
377         }
378     }
379
380     /* Some C compilers put a complete path into __FILE__, but we want
381      * only the filename (e.g. mod_includes.c). So check for path
382      * components (Unix and DOS), and remove them.
383      */
384
385     if (ap_strrchr_c(m->name, '/'))
386         m->name = 1 + ap_strrchr_c(m->name, '/');
387     if (ap_strrchr_c(m->name, '\\'))
388         m->name = 1 + ap_strrchr_c(m->name, '\\');
389
390 #ifdef _OSD_POSIX /* __FILE__="*POSIX(/home/martin/apache/src/modules/standard/mod_info.c)" */
391     /* We cannot fix the string in-place, because it's const */
392     if (m->name[strlen(m->name)-1]==')') {
393         char *tmp = strdup(m->name);    /* FIXME:memory leak, albeit a small one */
394         tmp[strlen(tmp)-1] = '\0';
395         m->name = tmp;
396     }
397 #endif /*_OSD_POSIX*/
398
399     /*  FIXME: is this the right place to call this?
400      *  It doesn't appear to be
401      */
402     ap_register_hooks(m, p);
403 }
404
405 /* 
406  * remove_module undoes what add_module did. There are some caveats:
407  * when the module is removed, its slot is lost so all the current
408  * per-dir and per-server configurations are invalid. So we should
409  * only ever call this function when you are invalidating almost
410  * all our current data. I.e. when doing a restart.
411  */
412
413 AP_DECLARE(void) ap_remove_module(module *m)
414 {
415     module *modp;
416
417     modp = ap_top_module;
418     if (modp == m) {
419         /* We are the top module, special case */
420         ap_top_module = modp->next;
421         m->next = NULL;
422     }
423     else {
424         /* Not the top module, find use. When found modp will
425          * point to the module _before_ us in the list
426          */
427
428         while (modp && modp->next != m) {
429             modp = modp->next;
430         }
431         if (!modp) {
432             /* Uh-oh, this module doesn't exist */
433             ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, NULL,
434                 "Cannot remove module %s: not found in module list",
435                 m->name);
436             return;
437         }
438         /* Eliminate us from the module list */
439         modp->next = modp->next->next;
440     }
441
442     m->module_index = -1;       /* simulate being unloaded, should
443                                  * be unnecessary */
444     dynamic_modules--;
445     total_modules--;
446 }
447
448 AP_DECLARE(void) ap_add_loaded_module(module *mod, apr_pool_t *p)
449 {
450     module **m;
451
452     /* 
453      *  Add module pointer to top of chained module list 
454      */
455     ap_add_module(mod, p);
456
457     /* 
458      *  And module pointer to list of loaded modules 
459      *
460      *  Notes: 1. ap_add_module() would already complain if no more space
461      *            exists for adding a dynamically loaded module
462      *         2. ap_add_module() accepts double inclusion, so we have
463      *            to accept this, too.
464      */
465     for (m = ap_loaded_modules; *m != NULL; m++)
466         ;
467     *m++ = mod;
468     *m = NULL;
469 }
470
471 AP_DECLARE(void) ap_remove_loaded_module(module *mod)
472 {
473     module **m;
474     module **m2;
475     int done;
476
477     /* 
478      *  Remove module pointer from chained module list 
479      */
480     ap_remove_module(mod);
481
482     /* 
483      *  Remove module pointer from list of loaded modules
484      *
485      *  Note: 1. We cannot determine if the module was successfully
486      *           removed by ap_remove_module().
487      *        2. We have not to complain explicity when the module
488      *           is not found because ap_remove_module() did it
489      *           for us already.
490      */
491     for (m = m2 = ap_loaded_modules, done = 0; *m2 != NULL; m2++) {
492         if (*m2 == mod && done == 0)
493             done = 1;
494         else
495             *m++ = *m2;
496     }
497     *m = NULL;
498 }
499
500 AP_DECLARE(void) ap_setup_prelinked_modules(process_rec *process)
501 {
502     module **m;
503     module **m2;
504
505     apr_global_hook_pool=process->pconf;
506
507     /*
508      *  Initialise total_modules variable and module indices
509      */
510     total_modules = 0;
511     for (m = ap_preloaded_modules; *m != NULL; m++)
512         (*m)->module_index = total_modules++;
513
514     /* 
515      *  Initialise list of loaded modules
516      */
517     ap_loaded_modules = (module **)apr_palloc(process->pool,
518         sizeof(module *)*(total_modules+DYNAMIC_MODULE_LIMIT+1));
519     if (ap_loaded_modules == NULL) {
520         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
521                      "Ouch!  Out of memory in ap_setup_prelinked_modules()!");
522     }
523     for (m = ap_preloaded_modules, m2 = ap_loaded_modules; *m != NULL; )
524         *m2++ = *m++;
525     *m2 = NULL;
526
527     /*
528      *   Initialize chain of linked (=activate) modules
529      */
530     for (m = ap_prelinked_modules; *m != NULL; m++)
531         ap_add_module(*m, process->pconf);
532
533     apr_sort_hooks();
534 }
535
536 AP_DECLARE(const char *) ap_find_module_name(module *m)
537 {
538     return m->name;
539 }
540
541 AP_DECLARE(module *) ap_find_linked_module(const char *name)
542 {
543     module *modp;
544
545     for (modp = ap_top_module; modp; modp = modp->next) {
546         if (strcmp(modp->name, name) == 0)
547             return modp;
548     }
549     return NULL;
550 }
551
552 /* Add a named module.  Returns 1 if module found, 0 otherwise.  */
553 AP_DECLARE(int) ap_add_named_module(const char *name, apr_pool_t *p)
554 {
555     module *modp;
556     int i = 0;
557
558     for (modp = ap_loaded_modules[i]; modp; modp = ap_loaded_modules[++i]) {
559         if (strcmp(modp->name, name) == 0) {
560             /* Only add modules that are not already enabled.  */
561             if (modp->next == NULL) {
562                 ap_add_module(modp, p);
563             }
564             return 1;
565         }
566     }
567
568     return 0;
569 }
570
571 /*****************************************************************
572  *
573  * Resource, access, and .htaccess config files now parsed by a common
574  * command loop.
575  *
576  * Let's begin with the basics; parsing the line and
577  * invoking the function...
578  */
579
580 static const char *invoke_cmd(const command_rec *cmd, cmd_parms *parms,
581                               void *mconfig, const char *args)
582 {
583     char *w, *w2, *w3;
584     const char *errmsg;
585
586     if ((parms->override & cmd->req_override) == 0)
587         return apr_pstrcat(parms->pool, cmd->name, " not allowed here", NULL);
588
589     parms->info = cmd->cmd_data;
590     parms->cmd = cmd;
591
592     switch (cmd->args_how) {
593     case RAW_ARGS:
594 #ifdef RESOLVE_ENV_PER_TOKEN
595         args = ap_resolve_env(parms->pool,args);
596 #endif
597         return cmd->AP_RAW_ARGS(parms, mconfig, args);
598
599     case NO_ARGS:
600         if (*args != 0)
601             return apr_pstrcat(parms->pool, cmd->name, " takes no arguments",
602                            NULL);
603
604         return cmd->AP_NO_ARGS(parms, mconfig);
605
606     case TAKE1:
607         w = ap_getword_conf(parms->pool, &args);
608
609         if (*w == '\0' || *args != 0)
610             return apr_pstrcat(parms->pool, cmd->name, " takes one argument",
611                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
612
613         return cmd->AP_TAKE1(parms, mconfig, w);
614
615     case TAKE2:
616         w = ap_getword_conf(parms->pool, &args);
617         w2 = ap_getword_conf(parms->pool, &args);
618
619         if (*w == '\0' || *w2 == '\0' || *args != 0)
620             return apr_pstrcat(parms->pool, cmd->name, " takes two arguments",
621                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
622
623         return cmd->AP_TAKE2(parms, mconfig, w, w2);
624
625     case TAKE12:
626
627         w = ap_getword_conf(parms->pool, &args);
628         w2 = ap_getword_conf(parms->pool, &args);
629
630         if (*w == '\0' || *args != 0)
631             return apr_pstrcat(parms->pool, cmd->name, " takes 1-2 arguments",
632                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
633
634         return cmd->AP_TAKE2(parms, mconfig, w, *w2 ? w2 : NULL);
635
636     case TAKE3:
637
638         w = ap_getword_conf(parms->pool, &args);
639         w2 = ap_getword_conf(parms->pool, &args);
640         w3 = ap_getword_conf(parms->pool, &args);
641
642         if (*w == '\0' || *w2 == '\0' || *w3 == '\0' || *args != 0)
643             return apr_pstrcat(parms->pool, cmd->name, " takes three arguments",
644                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
645
646         return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
647
648     case TAKE23:
649
650         w = ap_getword_conf(parms->pool, &args);
651         w2 = ap_getword_conf(parms->pool, &args);
652         w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
653
654         if (*w == '\0' || *w2 == '\0' || *args != 0)
655             return apr_pstrcat(parms->pool, cmd->name,
656                             " takes two or three arguments",
657                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
658
659         return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
660
661     case TAKE123:
662
663         w = ap_getword_conf(parms->pool, &args);
664         w2 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
665         w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
666
667         if (*w == '\0' || *args != 0)
668             return apr_pstrcat(parms->pool, cmd->name,
669                             " takes one, two or three arguments",
670                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
671
672         return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
673
674     case TAKE13:
675
676         w = ap_getword_conf(parms->pool, &args);
677         w2 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
678         w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
679
680         if (*w == '\0' || (w2 && *w2 && !w3) || *args != 0)
681             return apr_pstrcat(parms->pool, cmd->name,
682                             " takes one or three arguments",
683                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
684
685         return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
686
687     case ITERATE:
688
689         while (*(w = ap_getword_conf(parms->pool, &args)) != '\0')
690             {
691             if ((errmsg = cmd->AP_TAKE1(parms, mconfig, w)))
692                 return errmsg;
693             }
694
695         return NULL;
696
697     case ITERATE2:
698
699         w = ap_getword_conf(parms->pool, &args);
700
701         if (*w == '\0' || *args == 0)
702             return apr_pstrcat(parms->pool, cmd->name,
703                             " requires at least two arguments",
704                             cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
705
706         while (*(w2 = ap_getword_conf(parms->pool, &args)) != '\0')
707             {
708             if ((errmsg = cmd->AP_TAKE2(parms, mconfig, w, w2)))
709                 return errmsg;
710             }
711
712         return NULL;
713
714     case FLAG:
715
716         w = ap_getword_conf(parms->pool, &args);
717
718         if (*w == '\0' || (strcasecmp(w, "on") && strcasecmp(w, "off")))
719             return apr_pstrcat(parms->pool, cmd->name, " must be On or Off",
720                             NULL);
721
722         return cmd->AP_FLAG(parms, mconfig, strcasecmp(w, "off") != 0);
723
724     default:
725
726         return apr_pstrcat(parms->pool, cmd->name,
727                     " is improperly configured internally (server bug)",
728                         NULL);
729     }
730 }
731
732 AP_CORE_DECLARE(const command_rec *) ap_find_command(const char *name, const command_rec *cmds)
733 {
734     while (cmds->name)
735         if (!strcasecmp(name, cmds->name))
736             return cmds;
737         else
738             ++cmds;
739
740     return NULL;
741 }
742
743 AP_CORE_DECLARE(const command_rec *) ap_find_command_in_modules(const char *cmd_name, module **mod)
744 {
745     const command_rec *cmdp;
746     module *modp;
747
748     for (modp = *mod; modp; modp = modp->next)
749         if (modp->cmds && (cmdp = ap_find_command(cmd_name, modp->cmds))) {
750             *mod = modp;
751             return cmdp;
752         }
753
754     return NULL;
755 }
756
757 AP_CORE_DECLARE(void *) ap_set_config_vectors(server_rec *server,
758                                               ap_conf_vector_t *section_vector,
759                                               const char *section,
760                                               module *mod, apr_pool_t *pconf)
761 {
762     void *section_config = ap_get_module_config(section_vector, mod);
763     void *server_config = ap_get_module_config(server->module_config, mod);
764
765     if (!section_config && mod->create_dir_config) {
766         /* ### need to fix the create_dir_config functions' prototype... */
767         section_config = (*mod->create_dir_config) (pconf, (char *)section);
768         ap_set_module_config(section_vector, mod, section_config);
769     }
770
771     if (!server_config && mod->create_server_config) {
772         server_config = (*mod->create_server_config) (pconf, server);
773         ap_set_module_config(server->module_config, mod, server_config);
774     }
775
776     return section_config;
777 }
778
779 static const char *execute_now(char *cmd_line, const char *args, cmd_parms *parms, 
780                          apr_pool_t *p, apr_pool_t *ptemp,
781                          ap_directive_t **sub_tree, ap_directive_t *parent);
782
783 static const char * ap_build_config_sub(apr_pool_t *p, apr_pool_t *temp_pool,
784                                         const char *l, cmd_parms *parms,
785                                         ap_directive_t **current,
786                                         ap_directive_t **curr_parent,
787                                         ap_directive_t **conftree)
788 {
789     const char *args;
790     char *cmd_name;
791     ap_directive_t *newdir;
792     module *mod = ap_top_module;
793     const command_rec *cmd;
794
795     if (*l == '#' || *l == '\0')
796         return NULL;
797
798 #if RESOLVE_ENV_PER_TOKEN
799     args = l;
800 #else
801     args = ap_resolve_env(temp_pool, l); 
802 #endif
803     cmd_name = ap_getword_conf(p, &args);
804     if (*cmd_name == '\0') {
805         /* Note: this branch should not occur. An empty line should have
806          * triggered the exit further above.
807          */
808         return NULL;
809     }
810
811     newdir = apr_pcalloc(p, sizeof(ap_directive_t));
812     newdir->filename = parms->config_file->name;
813     newdir->line_num = parms->config_file->line_number;
814     newdir->directive = cmd_name;
815     newdir->args = apr_pstrdup(p, args);
816
817     if ((cmd = ap_find_command_in_modules(cmd_name, &mod)) != NULL) {
818         if (cmd->req_override & EXEC_ON_READ) {
819             const char *retval;
820             ap_directive_t *sub_tree = NULL;
821
822             parms->err_directive = newdir;
823             retval = execute_now(cmd_name, args, parms, p, temp_pool, 
824                                  &sub_tree, *curr_parent);
825             if (*current) {
826                 (*current)->next = sub_tree;
827             }
828             else {
829                 (*current) = sub_tree;
830                 if (*curr_parent) {
831                     (*curr_parent)->first_child = (*current);
832                 }
833                 if (*current) {
834                     (*current)->parent = (*curr_parent);
835                 }
836             }
837             if (*current) {
838                 if (!*conftree) {
839                     /* Before walking *current to the end of the list,
840                      * set the head to *current.
841                      */
842                     *conftree = *current;
843                 }
844                 while ((*current)->next != NULL) {
845                     (*current) = (*current)->next;
846                     (*current)->parent = (*curr_parent);
847                 }
848             }
849             return retval;
850         }
851     }
852
853     if (cmd_name[0] == '<') {
854         if (cmd_name[1] != '/') {
855             (*current) = ap_add_node(curr_parent, *current, newdir, 1);
856         }
857         else if (*curr_parent == NULL) {
858             parms->err_directive = newdir;
859             return apr_pstrcat(p, cmd_name,
860                               " without matching <", cmd_name + 2,
861                               " section", NULL);
862         }
863         else {
864             char *bracket = cmd_name + strlen(cmd_name) - 1;
865
866             if (*bracket != '>') {
867                 return apr_pstrcat(p, cmd_name,
868                                   "> directive missing closing '>'", NULL);
869             }
870             *bracket = '\0';
871             if (strcasecmp(cmd_name + 2,
872                             (*curr_parent)->directive + 1) != 0) {
873                 return apr_pstrcat(p, "Expected </",
874                                   (*curr_parent)->directive + 1, "> but saw ",
875                                   cmd_name, ">", NULL);
876             }
877             *bracket = '>';
878
879             /* done with this section; move up a level */
880             *current = *curr_parent;
881             *curr_parent = (*current)->parent;
882         }
883     }
884     else {
885         *current = ap_add_node(curr_parent, *current, newdir, 0);
886     }
887
888     return NULL;
889 }
890
891 const char *ap_build_cont_config(apr_pool_t *p, apr_pool_t *temp_pool,
892                                  cmd_parms *parms,
893                                  ap_directive_t **current,
894                                  ap_directive_t **curr_parent,
895                                  char *orig_directive)
896 {
897     char l[MAX_STRING_LEN];
898     char *bracket;
899     const char *retval;
900     ap_directive_t *sub_tree = NULL;
901
902     bracket = apr_pstrcat(p, orig_directive + 1, ">", NULL);
903     while (!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) {
904         if (!memcmp(l, "</", 2) &&
905             (strcasecmp(l + 2, bracket) == 0) &&
906             (*curr_parent == NULL)) {
907             break;
908         } 
909         retval = ap_build_config_sub(p, temp_pool, l, parms, current, 
910                                      curr_parent, &sub_tree);
911         if (retval != NULL)
912             return retval;
913         if (sub_tree == NULL && curr_parent != NULL) { 
914             sub_tree = *curr_parent;
915         }
916         if (sub_tree == NULL && current != NULL) {
917             sub_tree = *current;
918         }
919     }
920     *current = sub_tree;
921     return NULL;
922 }
923
924 static const char *ap_walk_config_sub(const ap_directive_t *current,
925                                       cmd_parms *parms,
926                                       ap_conf_vector_t *section_vector)
927 {
928     module *mod = ap_top_module;
929
930     while (1) {
931         const command_rec *cmd;
932
933         if (!(cmd = ap_find_command_in_modules(current->directive, &mod))) {
934             parms->err_directive = current;
935             return apr_pstrcat(parms->pool, "Invalid command '", 
936                               current->directive,
937                               "', perhaps mis-spelled or defined by a module "
938                               "not included in the server configuration",
939                               NULL);
940         }
941         else {
942             void *dir_config = ap_set_config_vectors(parms->server,
943                                                      section_vector,
944                                                      parms->path,
945                                                      mod,
946                                                      parms->pool);
947             const char *retval;
948
949             retval = invoke_cmd(cmd, parms, dir_config, current->args);
950             if (retval == NULL) {
951                 return NULL;
952             }
953             if (strcmp(retval, DECLINE_CMD) != 0) {
954                 /* If the directive in error has already been set, don't
955                  * replace it.  Otherwise, an error inside a container 
956                  * will be reported as occuring on the first line of the
957                  * container.
958                  */
959                 if (!parms->err_directive) {
960                     parms->err_directive = current;
961                 }
962                 return retval;
963             }
964
965             mod = mod->next;    /* Next time around, skip this one */
966         }
967     }
968     /* NOTREACHED */
969 }
970
971 AP_DECLARE(const char *) ap_walk_config(ap_directive_t *current,
972                                         cmd_parms *parms,
973                                         ap_conf_vector_t *section_vector)
974 {
975     ap_conf_vector_t *oldconfig = parms->context;
976
977     parms->context = section_vector;
978
979     /* scan through all directives, executing each one */
980     for (; current != NULL; current = current->next) {
981         const char *errmsg;
982
983         parms->directive = current;
984
985         /* actually parse the command and execute the correct function */
986         errmsg = ap_walk_config_sub(current, parms, section_vector);
987         if (errmsg != NULL) {
988             /* restore the context (just in case) */
989             parms->context = oldconfig;
990             return errmsg;
991         }
992     }
993
994     parms->context = oldconfig;
995     return NULL;
996 }
997
998
999 AP_DECLARE(const char *) ap_build_config(cmd_parms *parms,
1000                                          apr_pool_t *p, apr_pool_t *temp_pool,
1001                                          ap_directive_t **conftree)
1002 {
1003     ap_directive_t *current = *conftree;
1004     ap_directive_t *curr_parent = NULL;
1005     char l[MAX_STRING_LEN];
1006     const char *errmsg;
1007
1008     if (current != NULL) {
1009         while (current->next) {
1010             current = current->next;
1011         }
1012     }
1013
1014     while (!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) {
1015
1016         errmsg = ap_build_config_sub(p, temp_pool, l, parms,
1017                                      &current, &curr_parent, conftree);
1018         if (errmsg != NULL)
1019             return errmsg;
1020
1021         if (*conftree == NULL && curr_parent != NULL) { 
1022             *conftree = curr_parent;
1023         }
1024         if (*conftree == NULL && current != NULL) {
1025             *conftree = current;
1026         }
1027     }
1028
1029     if (curr_parent != NULL) {
1030         errmsg = "";
1031         while (curr_parent != NULL) {
1032             errmsg = apr_psprintf(p, "%s%s%s:%u: %s> was not closed.",
1033                                  errmsg,
1034                                  *errmsg == '\0' ? "" : APR_EOL_STR,
1035                                  curr_parent->filename,
1036                                  curr_parent->line_num,
1037                                  curr_parent->directive);
1038             curr_parent = curr_parent->parent;
1039         }
1040         return errmsg;
1041     }
1042
1043     return NULL;
1044 }
1045
1046 /*
1047  * Generic command functions...
1048  */
1049
1050 AP_DECLARE_NONSTD(const char *) ap_set_string_slot(cmd_parms *cmd,
1051                                                    void *struct_ptr,
1052                                                    const char *arg)
1053 {
1054     /* This one's pretty generic... */
1055
1056     int offset = (int) (long) cmd->info;
1057     *(const char **) ((char *)struct_ptr + offset) = arg;
1058     return NULL;
1059 }
1060
1061 AP_DECLARE_NONSTD(const char *) ap_set_string_slot_lower(cmd_parms *cmd,
1062                                                          void *struct_ptr,
1063                                                          const char *arg_)
1064 {
1065     /* This one's pretty generic... */
1066     char *arg=apr_pstrdup(cmd->pool,arg_);
1067
1068     int offset = (int) (long) cmd->info;
1069     ap_str_tolower(arg);
1070     *(char **) ((char *)struct_ptr + offset) = arg;
1071     return NULL;
1072 }
1073
1074 AP_DECLARE_NONSTD(const char *) ap_set_flag_slot(cmd_parms *cmd,
1075                                                  void *struct_ptr_v, int arg)
1076 {
1077     /* This one's pretty generic too... */
1078
1079     int offset = (int) (long) cmd->info;
1080     char *struct_ptr = (char *)struct_ptr_v;
1081     *(int *) (struct_ptr + offset) = arg ? 1 : 0;
1082     return NULL;
1083 }
1084
1085 AP_DECLARE_NONSTD(const char *) ap_set_file_slot(cmd_parms *cmd, void *struct_ptr, 
1086                                                  const char *arg)
1087 {
1088     /* Prepend server_root to relative arg.
1089        This allows .htaccess to be independent of server_root,
1090        so the server can be moved or mirrored with less pain.  */
1091     char *p;
1092     int offset = (int) (long) cmd->info;
1093 #ifndef OS2
1094     arg = ap_os_canonical_filename(cmd->pool, arg);
1095 #endif
1096     if (ap_os_is_path_absolute(arg))
1097         p = apr_pstrdup(cmd->pool, arg);
1098     else
1099         p = ap_make_full_path(cmd->pool, ap_server_root, arg);
1100     *(char **) ((char*)struct_ptr + offset) = p;
1101     return NULL;
1102 }
1103
1104 /*****************************************************************
1105  *
1106  * Reading whole config files...
1107  */
1108
1109 static cmd_parms default_parms =
1110 {NULL, 0, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
1111
1112 AP_DECLARE(const char *) ap_server_root_relative(apr_pool_t *p, const char *file)
1113 {
1114 #ifndef OS2
1115     file = ap_os_canonical_filename(p, file);
1116 #endif
1117     if(ap_os_is_path_absolute(file))
1118         return file;
1119     return ap_make_full_path(p, ap_server_root, file);
1120 }
1121
1122 AP_DECLARE(const char *) ap_soak_end_container(cmd_parms *cmd, char *directive)
1123 {
1124     char l[MAX_STRING_LEN];
1125     const char *args;
1126     char *cmd_name;
1127
1128     while(!(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) {
1129 #if RESOLVE_ENV_PER_TOKEN
1130         args = l;
1131 #else
1132         args = ap_resolve_env(cmd->temp_pool, l);
1133 #endif
1134         cmd_name = ap_getword_conf(cmd->pool, &args);
1135         if (cmd_name[0] == '<') {
1136             if (cmd_name[1] == '/') {
1137                 cmd_name[strlen(cmd_name) - 1] = '\0';
1138                 if (strcasecmp(cmd_name + 2, directive + 1) != 0) {
1139                     return apr_pstrcat(cmd->pool, "Expected </",
1140                                       directive + 1, "> but saw ",
1141                                       cmd_name, ">", NULL);
1142                 }
1143                 return NULL; /* found end of container */
1144             }
1145             else {
1146                 const char *msg;
1147
1148                 if ((msg = ap_soak_end_container(cmd, cmd_name)) != NULL) {
1149                     return msg;
1150                 }
1151             }
1152         }
1153     }
1154     return apr_pstrcat(cmd->pool, "Expected </",
1155                        directive + 1, "> before end of configuration",
1156                        NULL);
1157 }
1158
1159 static const char *execute_now(char *cmd_line, const char *args, cmd_parms *parms, 
1160                          apr_pool_t *p, apr_pool_t *ptemp, 
1161                          ap_directive_t **sub_tree, ap_directive_t *parent)
1162 {
1163     module *mod = ap_top_module;
1164     const command_rec *cmd;
1165
1166     if (!(cmd = ap_find_command_in_modules(cmd_line, &mod))) {
1167         return apr_pstrcat(parms->pool, "Invalid command '", 
1168                           cmd_line,
1169                           "', perhaps mis-spelled or defined by a module "
1170                           "not included in the server configuration",
1171                           NULL);
1172     }
1173     else {
1174         return invoke_cmd(cmd, parms, sub_tree, args);
1175     }
1176 }
1177
1178 /* This structure and the following functions are needed for the
1179  * table-based config file reading. They are passed to the
1180  * cfg_open_custom() routine.
1181  */
1182
1183 /* Structure to be passed to cfg_open_custom(): it contains an
1184  * index which is incremented from 0 to nelts on each call to
1185  * cfg_getline() (which in turn calls arr_elts_getstr())
1186  * and an apr_array_header_t pointer for the string array.
1187  */
1188 typedef struct {
1189     apr_array_header_t *array;
1190     int curr_idx;
1191 } arr_elts_param_t;
1192
1193
1194 /* arr_elts_getstr() returns the next line from the string array. */
1195 static void *arr_elts_getstr(void *buf, size_t bufsiz, void *param)
1196 {
1197     arr_elts_param_t *arr_param = (arr_elts_param_t *) param;
1198
1199     /* End of array reached? */
1200     if (++arr_param->curr_idx > arr_param->array->nelts)
1201         return NULL;
1202
1203     /* return the line */
1204     apr_cpystrn(buf, ((char **) arr_param->array->elts)[arr_param->curr_idx - 1], bufsiz);
1205
1206     return buf;
1207 }
1208
1209
1210 /* arr_elts_close(): dummy close routine (makes sure no more lines can be read) */
1211 static int arr_elts_close(void *param)
1212 {
1213     arr_elts_param_t *arr_param = (arr_elts_param_t *) param;
1214     arr_param->curr_idx = arr_param->array->nelts;
1215     return 0;
1216 }
1217
1218 static void process_command_config(server_rec *s, apr_array_header_t *arr, 
1219                               ap_directive_t **conftree, apr_pool_t *p,
1220                               apr_pool_t *ptemp)
1221 {
1222     const char *errmsg;
1223     cmd_parms parms;
1224     arr_elts_param_t arr_parms;
1225
1226     arr_parms.curr_idx = 0;
1227     arr_parms.array = arr;
1228
1229     parms = default_parms;
1230     parms.pool = p;
1231     parms.temp_pool = ptemp;
1232     parms.server = s;
1233     parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT);
1234
1235     parms.config_file = ap_pcfg_open_custom(p, "-c/-C directives",
1236                               &arr_parms, NULL,
1237                               arr_elts_getstr, arr_elts_close);
1238
1239     errmsg = ap_build_config(&parms, p, ptemp, conftree);
1240     if (errmsg) {
1241         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
1242                      "Syntax error in -C/-c directive:" APR_EOL_STR "%s", 
1243                      errmsg);
1244         exit(1);
1245     }
1246
1247     ap_cfg_closefile(parms.config_file);
1248 }
1249
1250 typedef struct {
1251     char *fname;
1252 } fnames;
1253
1254 static int fname_alphasort(const void *fn1, const void *fn2)
1255 {
1256     const fnames *f1 = fn1;
1257     const fnames *f2 = fn2;
1258
1259     return strcmp(f1->fname,f2->fname);
1260 }
1261
1262 void ap_process_resource_config(server_rec *s, const char *fname, 
1263                                 ap_directive_t **conftree, apr_pool_t *p, 
1264                                 apr_pool_t *ptemp)
1265 {
1266     cmd_parms parms;
1267     apr_finfo_t finfo;
1268     const char *errmsg;
1269     ap_configfile_t *cfp;
1270
1271     fname = ap_server_root_relative(p, fname);
1272
1273     /* don't require conf/httpd.conf if we have a -C or -c switch */
1274     if ((ap_server_pre_read_config->nelts
1275          || ap_server_post_read_config->nelts)
1276         && !(strcmp(fname, ap_server_root_relative(p, SERVER_CONFIG_FILE)))) {
1277         if (apr_lstat(&finfo, fname, APR_FINFO_TYPE, p) != APR_SUCCESS)
1278             return;
1279     }
1280
1281     /* 
1282      * here we want to check if the candidate file is really a
1283      * directory, and most definitely NOT a symlink (to prevent
1284      * horrible loops).  If so, let's recurse and toss it back 
1285      * into the function.
1286      */
1287     if (ap_is_rdirectory(ptemp, fname)) {
1288         apr_dir_t *dirp;
1289         apr_finfo_t dirent;
1290         int current;
1291         apr_array_header_t *candidates = NULL;
1292         fnames *fnew;
1293         apr_status_t rv;
1294         char errmsg[120];
1295
1296         /*
1297          * first course of business is to grok all the directory
1298          * entries here and store 'em away. Recall we need full pathnames
1299          * for this.
1300          */
1301         fprintf(stderr, "Processing config directory: %s\n", fname);
1302         rv = apr_dir_open(&dirp, fname, p);
1303         if (rv != APR_SUCCESS) {
1304             fprintf(stderr, "%s: could not open config directory %s: %s\n",
1305                     ap_server_argv0, fname,
1306                     apr_strerror(rv, errmsg, sizeof errmsg));
1307             exit(1);
1308         }
1309         candidates = apr_array_make(p, 1, sizeof(fnames));
1310         while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp) == APR_SUCCESS) {
1311             /* strip out '.' and '..' */
1312             if (strcmp(dirent.name, ".") &&
1313                 strcmp(dirent.name, "..")) {
1314                 fnew = (fnames *) apr_array_push(candidates);
1315                 fnew->fname = ap_make_full_path(p, fname, dirent.name);
1316             }
1317         }
1318         apr_dir_close(dirp);
1319         if (candidates->nelts != 0) {
1320             qsort((void *) candidates->elts, candidates->nelts,
1321               sizeof(fnames), fname_alphasort);
1322             /*
1323              * Now recurse these... we handle errors and subdirectories
1324              * via the recursion, which is nice
1325              */
1326             for (current = 0; current < candidates->nelts; ++current) {
1327                 fnew = &((fnames *) candidates->elts)[current];
1328                 fprintf(stderr, " Processing config file: %s\n", fnew->fname);
1329                 ap_process_resource_config(s, fnew->fname, conftree, p, ptemp);
1330             }
1331         }
1332         return;
1333     }
1334     
1335     /* GCC's initialization extensions are soooo nice here... */
1336
1337     parms = default_parms;
1338     parms.pool = p;
1339     parms.temp_pool = ptemp;
1340     parms.server = s;
1341     parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT);
1342
1343     if (ap_pcfg_openfile(&cfp, p, fname) != APR_SUCCESS) {
1344         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
1345                      "%s: could not open document config file %s",
1346                      ap_server_argv0, fname);
1347         exit(1);
1348     }
1349
1350     parms.config_file = cfp;
1351
1352     errmsg = ap_build_config(&parms, p, ptemp, conftree);
1353
1354     if (errmsg != NULL) {
1355         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
1356                      "Syntax error on line %d of %s:",
1357                      parms.err_directive->line_num, 
1358                      parms.err_directive->filename);
1359         ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
1360                      "%s", errmsg);
1361         exit(1);
1362     }
1363
1364     ap_cfg_closefile(cfp);
1365 }
1366
1367 AP_DECLARE(void) ap_process_config_tree(server_rec *s,
1368                                         ap_directive_t *conftree,
1369                                         apr_pool_t *p, apr_pool_t *ptemp)
1370 {
1371     const char *errmsg;
1372     cmd_parms parms;
1373
1374     parms = default_parms;
1375     parms.pool = p;
1376     parms.temp_pool = ptemp;
1377     parms.server = s;
1378     parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT);
1379     parms.limited = -1;
1380
1381     errmsg = ap_walk_config(conftree, &parms, s->lookup_defaults);
1382     if (errmsg) {
1383         ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, p,
1384                      "Syntax error on line %d of %s:",
1385                      parms.err_directive->line_num,
1386                      parms.err_directive->filename);
1387         ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, p, 
1388                      "%s", errmsg);
1389         exit(1);
1390     }
1391 }
1392
1393 int ap_parse_htaccess(ap_conf_vector_t **result, request_rec *r, int override,
1394                       const char *d, const char *access_name)
1395 {
1396     ap_configfile_t *f = NULL;
1397     cmd_parms parms;
1398     char *filename = NULL;
1399     const struct htaccess_result *cache;
1400     struct htaccess_result *new;
1401     ap_conf_vector_t *dc = NULL;
1402     apr_status_t status;
1403
1404     /* firstly, search cache */
1405     for (cache = r->htaccess; cache != NULL; cache = cache->next)
1406         if (cache->override == override && strcmp(cache->dir, d) == 0) {
1407             if (cache->htaccess != NULL)
1408                 *result = cache->htaccess;
1409             return OK;
1410         }
1411
1412     parms = default_parms;
1413     parms.override = override;
1414     parms.pool = r->pool;
1415     parms.temp_pool = r->pool;
1416     parms.server = r->server;
1417     parms.path = apr_pstrdup(r->pool, d);
1418
1419     /* loop through the access names and find the first one */
1420
1421     while (access_name[0]) {
1422         filename = ap_make_full_path(r->pool, d,
1423                                      ap_getword_conf(r->pool, &access_name));
1424         status = ap_pcfg_openfile(&f, r->pool, filename);
1425
1426         if (status == APR_SUCCESS) {
1427             const char *errmsg;
1428             ap_directive_t *temptree = NULL;
1429
1430             dc = ap_create_per_dir_config(r->pool);
1431
1432             parms.config_file = f;
1433             errmsg = ap_build_config(&parms, r->pool, r->pool, &temptree);
1434             if (errmsg == NULL)
1435                 errmsg = ap_walk_config(temptree, &parms, dc);
1436
1437             ap_cfg_closefile(f);
1438
1439             if (errmsg) {
1440                 ap_log_rerror(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, 0, r,
1441                               "%s: %s", filename, errmsg);
1442                 return HTTP_INTERNAL_SERVER_ERROR;
1443             }
1444             *result = dc;
1445             break;
1446         } else {
1447             if (!APR_STATUS_IS_ENOENT(status)
1448                 && !APR_STATUS_IS_ENOTDIR(status)) {
1449                 ap_log_rerror(APLOG_MARK, APLOG_CRIT, status, r,
1450                               "%s pcfg_openfile: unable to check htaccess file, "
1451                               "ensure it is readable",
1452                               filename);
1453                 apr_table_setn(r->notes, "error-notes",
1454                               "Server unable to read htaccess file, denying "
1455                               "access to be safe");
1456                 return HTTP_FORBIDDEN;
1457             }
1458         }
1459     }
1460
1461     /* cache it */
1462     new = apr_palloc(r->pool, sizeof(struct htaccess_result));
1463     new->dir = parms.path;
1464     new->override = override;
1465     new->htaccess = dc;
1466
1467     /* add to head of list */
1468     new->next = r->htaccess;
1469     r->htaccess = new;
1470
1471     return OK;
1472 }
1473
1474 AP_CORE_DECLARE(const char *) ap_init_virtual_host(apr_pool_t *p,
1475                                                    const char *hostname,
1476                                                    server_rec *main_server,
1477                                                    server_rec **ps)
1478 {
1479     server_rec *s = (server_rec *) apr_pcalloc(p, sizeof(server_rec));
1480
1481     /* TODO: this crap belongs in http_core */
1482     s->process = main_server->process;
1483     s->server_admin = NULL;
1484     s->server_hostname = NULL;
1485     s->error_fname = NULL;
1486     s->timeout = 0;
1487     s->keep_alive_timeout = 0;
1488     s->keep_alive = -1;
1489     s->keep_alive_max = -1;
1490     s->error_log = main_server->error_log;
1491     s->loglevel = main_server->loglevel;
1492     /* useful default, otherwise we get a port of 0 on redirects */
1493     s->port = main_server->port;
1494     s->next = NULL;
1495
1496     s->is_virtual = 1;
1497     s->names = apr_array_make(p, 4, sizeof(char **));
1498     s->wild_names = apr_array_make(p, 4, sizeof(char **));
1499
1500     s->module_config = create_empty_config(p);
1501     s->lookup_defaults = ap_create_per_dir_config(p);
1502
1503     s->limit_req_line = main_server->limit_req_line;
1504     s->limit_req_fieldsize = main_server->limit_req_fieldsize;
1505     s->limit_req_fields = main_server->limit_req_fields;
1506
1507     *ps = s;
1508
1509     return ap_parse_vhost_addrs(p, hostname, s);
1510 }
1511
1512
1513 AP_DECLARE(void) ap_fixup_virtual_hosts(apr_pool_t *p, server_rec *main_server)
1514 {
1515     server_rec *virt;
1516
1517     for (virt = main_server->next; virt; virt = virt->next) {
1518         merge_server_configs(p, main_server->module_config,
1519                              virt->module_config);
1520
1521         virt->lookup_defaults =
1522             ap_merge_per_dir_configs(p, main_server->lookup_defaults,
1523                                   virt->lookup_defaults);
1524
1525         if (virt->server_admin == NULL)
1526             virt->server_admin = main_server->server_admin;
1527
1528         if (virt->timeout == 0)
1529             virt->timeout = main_server->timeout;
1530
1531         if (virt->keep_alive_timeout == 0)
1532             virt->keep_alive_timeout = main_server->keep_alive_timeout;
1533
1534         if (virt->keep_alive == -1)
1535             virt->keep_alive = main_server->keep_alive;
1536
1537         if (virt->keep_alive_max == -1)
1538             virt->keep_alive_max = main_server->keep_alive_max;
1539
1540         /* XXX: this is really something that should be dealt with by a
1541          * post-config api phase */
1542         ap_core_reorder_directories(p, virt);
1543     }
1544     ap_core_reorder_directories(p, main_server);
1545 }
1546
1547 /*****************************************************************
1548  *
1549  * Getting *everything* configured... 
1550  */
1551
1552 static void init_config_globals(apr_pool_t *p)
1553 {
1554     /* Global virtual host hash bucket pointers.  Init to null. */
1555     ap_init_vhost_config(p);
1556 }
1557
1558 static server_rec *init_server_config(process_rec *process, apr_pool_t *p)
1559 {
1560     apr_status_t rv;
1561     server_rec *s = (server_rec *) apr_pcalloc(p, sizeof(server_rec));
1562
1563     apr_file_open_stderr(&s->error_log, p);
1564     s->process = process;
1565     s->port = 0;
1566     s->server_admin = DEFAULT_ADMIN;
1567     s->server_hostname = NULL;
1568     s->error_fname = DEFAULT_ERRORLOG;
1569     s->loglevel = DEFAULT_LOGLEVEL;
1570     s->limit_req_line = DEFAULT_LIMIT_REQUEST_LINE;
1571     s->limit_req_fieldsize = DEFAULT_LIMIT_REQUEST_FIELDSIZE;
1572     s->limit_req_fields = DEFAULT_LIMIT_REQUEST_FIELDS;
1573     s->timeout = DEFAULT_TIMEOUT;     
1574     s->keep_alive_timeout = DEFAULT_KEEPALIVE_TIMEOUT;
1575     s->keep_alive_max = DEFAULT_KEEPALIVE;
1576     s->keep_alive = 1;
1577     s->next = NULL;
1578     s->addrs = apr_pcalloc(p, sizeof(server_addr_rec));
1579     /* NOT virtual host; don't match any real network interface */
1580     rv = apr_sockaddr_info_get(&s->addrs->host_addr,
1581                          NULL, APR_INET, 0, 0, p);
1582     ap_assert(rv == APR_SUCCESS); /* otherwise: bug or no storage */
1583     s->addrs->host_port = 0;    /* matches any port */
1584     s->addrs->virthost = "";    /* must be non-NULL */
1585     s->names = s->wild_names = NULL;
1586
1587     s->module_config = create_server_config(p, s);
1588     s->lookup_defaults = create_default_per_dir_config(p);
1589
1590     return s;
1591 }
1592
1593
1594 AP_DECLARE(server_rec*) ap_read_config(process_rec *process, apr_pool_t *ptemp,
1595                                        const char *confname, 
1596                                        ap_directive_t **conftree)
1597 {
1598     apr_pool_t *p = process->pconf;
1599     server_rec *s = init_server_config(process, p);
1600
1601     init_config_globals(p);
1602
1603     /* All server-wide config files now have the SAME syntax... */
1604
1605     process_command_config(s, ap_server_pre_read_config, conftree,
1606                                       p, ptemp);
1607
1608     ap_process_resource_config(s, confname, conftree, p, ptemp);
1609
1610     process_command_config(s, ap_server_post_read_config, conftree,
1611                                       p, ptemp);
1612
1613     return s;
1614 }
1615
1616 AP_DECLARE(void) ap_single_module_configure(apr_pool_t *p, server_rec *s, 
1617                                             module *m)
1618 {
1619     if (m->create_server_config)
1620         ap_set_module_config(s->module_config, m,
1621                              (*m->create_server_config)(p, s));
1622     if (m->create_dir_config)
1623         ap_set_module_config(s->lookup_defaults, m,
1624                              (*m->create_dir_config)(p, NULL));
1625 }
1626
1627 AP_DECLARE(void) ap_run_rewrite_args(process_rec *process)
1628 {
1629     module *m;
1630
1631     for (m = ap_top_module; m; m = m->next)
1632         if (m->rewrite_args)
1633             (*m->rewrite_args) (process);
1634 }
1635
1636 /********************************************************************
1637  * Configuration directives are restricted in terms of where they may
1638  * appear in the main configuration files and/or .htaccess files according
1639  * to the bitmask req_override in the command_rec structure.
1640  * If any of the overrides set in req_override are also allowed in the
1641  * context in which the command is read, then the command is allowed.
1642  * The context is determined as follows:
1643  *
1644  *    inside *.conf --> override = (RSRC_CONF|OR_ALL)&~(OR_AUTHCFG|OR_LIMIT);
1645  *    within <Directory> or <Location> --> override = OR_ALL|ACCESS_CONF;
1646  *    within .htaccess --> override = AllowOverride for current directory;
1647  *
1648  * the result is, well, a rather confusing set of possibilities for when
1649  * a particular directive is allowed to be used.  This procedure prints
1650  * in English where the given (pc) directive can be used.
1651  */
1652 static void show_overrides(const command_rec *pc, module *pm)
1653 {
1654     int n = 0;
1655
1656     printf("\tAllowed in *.conf ");
1657     if ((pc->req_override & (OR_OPTIONS | OR_FILEINFO | OR_INDEXES)) ||
1658         ((pc->req_override & RSRC_CONF) &&
1659          ((pc->req_override & (ACCESS_CONF | OR_AUTHCFG | OR_LIMIT)))))
1660         printf("anywhere");
1661     else if (pc->req_override & RSRC_CONF)
1662         printf("only outside <Directory>, <Files> or <Location>");
1663     else
1664         printf("only inside <Directory>, <Files> or <Location>");
1665
1666     /* Warn if the directive is allowed inside <Directory> or .htaccess
1667      * but module doesn't support per-dir configuration */
1668
1669     if ((pc->req_override & (OR_ALL | ACCESS_CONF)) && !pm->create_dir_config)
1670         printf(" [no per-dir config]");
1671
1672     if (pc->req_override & OR_ALL) {
1673         printf(" and in .htaccess\n\twhen AllowOverride");
1674
1675         if ((pc->req_override & OR_ALL) == OR_ALL)
1676             printf(" isn't None");
1677         else {
1678             printf(" includes ");
1679
1680             if (pc->req_override & OR_AUTHCFG) {
1681                 if (n++)
1682                     printf(" or ");
1683                 printf("AuthConfig");
1684             }
1685             if (pc->req_override & OR_LIMIT) {
1686                 if (n++)
1687                     printf(" or ");
1688                 printf("Limit");
1689             }
1690             if (pc->req_override & OR_OPTIONS) {
1691                 if (n++)
1692                     printf(" or ");
1693                 printf("Options");
1694             }
1695             if (pc->req_override & OR_FILEINFO) {
1696                 if (n++)
1697                     printf(" or ");
1698                 printf("FileInfo");
1699             }
1700             if (pc->req_override & OR_INDEXES) {
1701                 if (n++)
1702                     printf(" or ");
1703                 printf("Indexes");
1704             }
1705         }
1706     }
1707     printf("\n");
1708 }
1709
1710 /* Show the preloaded configuration directives, the help string explaining
1711  * the directive arguments, in what module they are handled, and in
1712  * what parts of the configuration they are allowed.  Used for httpd -h.
1713  */
1714 AP_DECLARE(void) ap_show_directives(void)
1715 {
1716     const command_rec *pc;
1717     int n;
1718
1719     for (n = 0; ap_loaded_modules[n]; ++n)
1720         for (pc = ap_loaded_modules[n]->cmds; pc && pc->name; ++pc) {
1721             printf("%s (%s)\n", pc->name, ap_loaded_modules[n]->name);
1722             if (pc->errmsg)
1723                 printf("\t%s\n", pc->errmsg);
1724             show_overrides(pc, ap_loaded_modules[n]);
1725         }
1726 }
1727
1728 /* Show the preloaded module names.  Used for httpd -l. */
1729 AP_DECLARE(void) ap_show_modules(void)
1730 {
1731     int n;
1732
1733     printf("Compiled in modules:\n");
1734     for (n = 0; ap_loaded_modules[n]; ++n)
1735         printf("  %s\n", ap_loaded_modules[n]->name);
1736 }
1737