]> granicus.if.org Git - apache/blob - server/core.c
mod_session_cookie: Add a session implementation capable of storing
[apache] / server / core.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr.h"
18 #include "apr_strings.h"
19 #include "apr_lib.h"
20 #include "apr_fnmatch.h"
21 #include "apr_hash.h"
22 #include "apr_thread_proc.h"    /* for RLIMIT stuff */
23 #include "apr_hooks.h"
24
25 #define APR_WANT_IOVEC
26 #define APR_WANT_STRFUNC
27 #define APR_WANT_MEMFUNC
28 #include "apr_want.h"
29
30 #define CORE_PRIVATE
31 #include "ap_config.h"
32 #include "httpd.h"
33 #include "http_config.h"
34 #include "http_core.h"
35 #include "http_protocol.h" /* For index_of_response().  Grump. */
36 #include "http_request.h"
37 #include "http_vhost.h"
38 #include "http_main.h"     /* For the default_handler below... */
39 #include "http_log.h"
40 #include "util_md5.h"
41 #include "http_connection.h"
42 #include "apr_buckets.h"
43 #include "util_filter.h"
44 #include "util_ebcdic.h"
45 #include "util_mutex.h"
46 #include "mpm.h"
47 #include "mpm_common.h"
48 #include "scoreboard.h"
49 #include "mod_core.h"
50 #include "mod_proxy.h"
51 #include "ap_listen.h"
52
53 #include "mod_so.h" /* for ap_find_loaded_module_symbol */
54
55 /* LimitRequestBody handling */
56 #define AP_LIMIT_REQ_BODY_UNSET         ((apr_off_t) -1)
57 #define AP_DEFAULT_LIMIT_REQ_BODY       ((apr_off_t) 0)
58
59 /* LimitXMLRequestBody handling */
60 #define AP_LIMIT_UNSET                  ((long) -1)
61 #define AP_DEFAULT_LIMIT_XML_BODY       ((size_t)1000000)
62
63 #define AP_MIN_SENDFILE_BYTES           (256)
64
65 /* maximum include nesting level */
66 #ifndef AP_MAX_INCLUDE_DEPTH
67 #define AP_MAX_INCLUDE_DEPTH            (128)
68 #endif
69
70 APR_HOOK_STRUCT(
71     APR_HOOK_LINK(get_mgmt_items)
72 )
73
74 AP_IMPLEMENT_HOOK_RUN_ALL(int, get_mgmt_items,
75                           (apr_pool_t *p, const char *val, apr_hash_t *ht),
76                           (p, val, ht), OK, DECLINED)
77
78 /* Server core module... This module provides support for really basic
79  * server operations, including options and commands which control the
80  * operation of other modules.  Consider this the bureaucracy module.
81  *
82  * The core module also defines handlers, etc., do handle just enough
83  * to allow a server with the core module ONLY to actually serve documents
84  * (though it slaps DefaultType on all of 'em); this was useful in testing,
85  * but may not be worth preserving.
86  *
87  * This file could almost be mod_core.c, except for the stuff which affects
88  * the http_conf_globals.
89  */
90
91 /* Handles for core filters */
92 AP_DECLARE_DATA ap_filter_rec_t *ap_subreq_core_filter_handle;
93 AP_DECLARE_DATA ap_filter_rec_t *ap_core_output_filter_handle;
94 AP_DECLARE_DATA ap_filter_rec_t *ap_content_length_filter_handle;
95 AP_DECLARE_DATA ap_filter_rec_t *ap_core_input_filter_handle;
96
97 /* magic pointer for ErrorDocument xxx "default" */
98 static char errordocument_default;
99
100 static void *create_core_dir_config(apr_pool_t *a, char *dir)
101 {
102     core_dir_config *conf;
103
104     conf = (core_dir_config *)apr_pcalloc(a, sizeof(core_dir_config));
105
106     /* conf->r and conf->d[_*] are initialized by dirsection() or left NULL */
107
108     conf->opts = dir ? OPT_UNSET : OPT_UNSET|OPT_ALL;
109     conf->opts_add = conf->opts_remove = OPT_NONE;
110     conf->override = dir ? OR_UNSET : OR_UNSET|OR_ALL;
111     conf->override_opts = OPT_UNSET | OPT_ALL | OPT_INCNOEXEC | OPT_SYM_OWNER
112                           | OPT_MULTI;
113
114     conf->content_md5 = 2;
115     conf->accept_path_info = 3;
116
117     conf->use_canonical_name = USE_CANONICAL_NAME_UNSET;
118     conf->use_canonical_phys_port = USE_CANONICAL_PHYS_PORT_UNSET;
119
120     conf->hostname_lookups = HOSTNAME_LOOKUP_UNSET;
121
122 #ifdef RLIMIT_CPU
123     conf->limit_cpu = NULL;
124 #endif
125 #if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
126     conf->limit_mem = NULL;
127 #endif
128 #ifdef RLIMIT_NPROC
129     conf->limit_nproc = NULL;
130 #endif
131
132     conf->limit_req_body = AP_LIMIT_REQ_BODY_UNSET;
133     conf->limit_xml_body = AP_LIMIT_UNSET;
134     conf->sec_file = apr_array_make(a, 2, sizeof(ap_conf_vector_t *));
135
136     conf->server_signature = srv_sig_unset;
137
138     conf->add_default_charset = ADD_DEFAULT_CHARSET_UNSET;
139     conf->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
140
141     /* Overriding all negotiation
142      */
143     conf->mime_type = NULL;
144     conf->handler = NULL;
145     conf->output_filters = NULL;
146     conf->input_filters = NULL;
147
148     /*
149      * Flag for use of inodes in ETags.
150      */
151     conf->etag_bits = ETAG_UNSET;
152     conf->etag_add = ETAG_UNSET;
153     conf->etag_remove = ETAG_UNSET;
154
155     conf->enable_mmap = ENABLE_MMAP_UNSET;
156     conf->enable_sendfile = ENABLE_SENDFILE_UNSET;
157     conf->allow_encoded_slashes = 0;
158
159     return (void *)conf;
160 }
161
162 /*
163  * Overlay one hash table of ct_output_filters onto another
164  */
165 static void *merge_ct_filters(apr_pool_t *p,
166                               const void *key,
167                               apr_ssize_t klen,
168                               const void *overlay_val,
169                               const void *base_val,
170                               const void *data)
171 {
172     ap_filter_rec_t *cur;
173     const ap_filter_rec_t *overlay_info = (const ap_filter_rec_t *)overlay_val;
174     const ap_filter_rec_t *base_info = (const ap_filter_rec_t *)base_val;
175
176     cur = NULL;
177
178     while (overlay_info) {
179         ap_filter_rec_t *new;
180
181         new = apr_pcalloc(p, sizeof(ap_filter_rec_t));
182         new->name = apr_pstrdup(p, overlay_info->name);
183         new->next = cur;
184         cur = new;
185         overlay_info = overlay_info->next;
186     }
187
188     while (base_info) {
189         ap_filter_rec_t *f;
190         int found = 0;
191
192         /* We can't have dups. */
193         f = cur;
194         while (f) {
195             if (!strcasecmp(base_info->name, f->name)) {
196                 found = 1;
197                 break;
198             }
199
200             f = f->next;
201         }
202
203         if (!found) {
204             f = apr_pcalloc(p, sizeof(ap_filter_rec_t));
205             f->name = apr_pstrdup(p, base_info->name);
206             f->next = cur;
207             cur = f;
208         }
209
210         base_info = base_info->next;
211     }
212
213     return cur;
214 }
215
216 static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv)
217 {
218     core_dir_config *base = (core_dir_config *)basev;
219     core_dir_config *new = (core_dir_config *)newv;
220     core_dir_config *conf;
221     int i;
222
223     /* Create this conf by duplicating the base, replacing elements
224      * (or creating copies for merging) where new-> values exist.
225      */
226     conf = (core_dir_config *)apr_pmemdup(a, base, sizeof(core_dir_config));
227
228     conf->d = new->d;
229     conf->d_is_fnmatch = new->d_is_fnmatch;
230     conf->d_components = new->d_components;
231     conf->r = new->r;
232     conf->condition = new->condition;
233
234     if (new->opts & OPT_UNSET) {
235         /* there was no explicit setting of new->opts, so we merge
236          * preserve the invariant (opts_add & opts_remove) == 0
237          */
238         conf->opts_add = (conf->opts_add & ~new->opts_remove) | new->opts_add;
239         conf->opts_remove = (conf->opts_remove & ~new->opts_add)
240                             | new->opts_remove;
241         conf->opts = (conf->opts & ~conf->opts_remove) | conf->opts_add;
242         if ((base->opts & OPT_INCNOEXEC) && (new->opts & OPT_INCLUDES)) {
243             conf->opts = (conf->opts & ~OPT_INCNOEXEC) | OPT_INCLUDES;
244         }
245     }
246     else {
247         /* otherwise we just copy, because an explicit opts setting
248          * overrides all earlier +/- modifiers
249          */
250         conf->opts = new->opts;
251         conf->opts_add = new->opts_add;
252         conf->opts_remove = new->opts_remove;
253     }
254
255     if (!(new->override & OR_UNSET)) {
256         conf->override = new->override;
257     }
258
259     if (!(new->override_opts & OPT_UNSET)) {
260         conf->override_opts = new->override_opts;
261     }
262
263     if (new->ap_default_type) {
264         conf->ap_default_type = new->ap_default_type;
265     }
266
267     if (conf->response_code_strings == NULL) {
268         conf->response_code_strings = new->response_code_strings;
269     }
270     else if (new->response_code_strings != NULL) {
271         /* If we merge, the merge-result must have it's own array
272          */
273         conf->response_code_strings = apr_pmemdup(a,
274             base->response_code_strings,
275             sizeof(*conf->response_code_strings) * RESPONSE_CODES);
276
277         for (i = 0; i < RESPONSE_CODES; ++i) {
278             if (new->response_code_strings[i] != NULL) {
279                 conf->response_code_strings[i] = new->response_code_strings[i];
280             }
281         }
282     }
283     /* Otherwise we simply use the base->response_code_strings array
284      */
285
286     if (new->hostname_lookups != HOSTNAME_LOOKUP_UNSET) {
287         conf->hostname_lookups = new->hostname_lookups;
288     }
289
290     if ((new->content_md5 & 2) == 0) {
291         conf->content_md5 = new->content_md5;
292     }
293
294     if (new->accept_path_info != 3) {
295         conf->accept_path_info = new->accept_path_info;
296     }
297
298     if (new->use_canonical_name != USE_CANONICAL_NAME_UNSET) {
299         conf->use_canonical_name = new->use_canonical_name;
300     }
301
302     if (new->use_canonical_phys_port != USE_CANONICAL_PHYS_PORT_UNSET) {
303         conf->use_canonical_phys_port = new->use_canonical_phys_port;
304     }
305
306 #ifdef RLIMIT_CPU
307     if (new->limit_cpu) {
308         conf->limit_cpu = new->limit_cpu;
309     }
310 #endif
311
312 #if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
313     if (new->limit_mem) {
314         conf->limit_mem = new->limit_mem;
315     }
316 #endif
317
318 #ifdef RLIMIT_NPROC
319     if (new->limit_nproc) {
320         conf->limit_nproc = new->limit_nproc;
321     }
322 #endif
323
324     if (new->limit_req_body != AP_LIMIT_REQ_BODY_UNSET) {
325         conf->limit_req_body = new->limit_req_body;
326     }
327
328     if (new->limit_xml_body != AP_LIMIT_UNSET)
329         conf->limit_xml_body = new->limit_xml_body;
330     else
331         conf->limit_xml_body = base->limit_xml_body;
332
333     if (!conf->sec_file) {
334         conf->sec_file = new->sec_file;
335     }
336     else if (new->sec_file) {
337         /* If we merge, the merge-result must have it's own array
338          */
339         conf->sec_file = apr_array_append(a, base->sec_file, new->sec_file);
340     }
341     /* Otherwise we simply use the base->sec_file array
342      */
343
344     if (new->server_signature != srv_sig_unset) {
345         conf->server_signature = new->server_signature;
346     }
347
348     if (new->add_default_charset != ADD_DEFAULT_CHARSET_UNSET) {
349         conf->add_default_charset = new->add_default_charset;
350         conf->add_default_charset_name = new->add_default_charset_name;
351     }
352
353     /* Overriding all negotiation
354      */
355     if (new->mime_type) {
356         conf->mime_type = new->mime_type;
357     }
358
359     if (new->handler) {
360         conf->handler = new->handler;
361     }
362
363     if (new->output_filters) {
364         conf->output_filters = new->output_filters;
365     }
366
367     if (new->input_filters) {
368         conf->input_filters = new->input_filters;
369     }
370
371     if (conf->ct_output_filters && new->ct_output_filters) {
372         conf->ct_output_filters = apr_hash_merge(a,
373                                                  new->ct_output_filters,
374                                                  conf->ct_output_filters,
375                                                  merge_ct_filters,
376                                                  NULL);
377     }
378     else if (new->ct_output_filters) {
379         conf->ct_output_filters = apr_hash_copy(a, new->ct_output_filters);
380     }
381     else if (conf->ct_output_filters) {
382         /* That memcpy above isn't enough. */
383         conf->ct_output_filters = apr_hash_copy(a, base->ct_output_filters);
384     }
385
386     /*
387      * Now merge the setting of the FileETag directive.
388      */
389     if (new->etag_bits == ETAG_UNSET) {
390         conf->etag_add =
391             (conf->etag_add & (~ new->etag_remove)) | new->etag_add;
392         conf->etag_remove =
393             (conf->etag_remove & (~ new->etag_add)) | new->etag_remove;
394         conf->etag_bits =
395             (conf->etag_bits & (~ conf->etag_remove)) | conf->etag_add;
396     }
397     else {
398         conf->etag_bits = new->etag_bits;
399         conf->etag_add = new->etag_add;
400         conf->etag_remove = new->etag_remove;
401     }
402
403     if (conf->etag_bits != ETAG_NONE) {
404         conf->etag_bits &= (~ ETAG_NONE);
405     }
406
407     if (new->enable_mmap != ENABLE_MMAP_UNSET) {
408         conf->enable_mmap = new->enable_mmap;
409     }
410
411     if (new->enable_sendfile != ENABLE_SENDFILE_UNSET) {
412         conf->enable_sendfile = new->enable_sendfile;
413     }
414
415     conf->allow_encoded_slashes = new->allow_encoded_slashes;
416
417     return (void*)conf;
418 }
419
420 static void *create_core_server_config(apr_pool_t *a, server_rec *s)
421 {
422     core_server_config *conf;
423     int is_virtual = s->is_virtual;
424
425     conf = (core_server_config *)apr_pcalloc(a, sizeof(core_server_config));
426
427 #ifdef GPROF
428     conf->gprof_dir = NULL;
429 #endif
430
431     conf->access_name = is_virtual ? NULL : DEFAULT_ACCESS_FNAME;
432     conf->ap_document_root = is_virtual ? NULL : DOCUMENT_LOCATION;
433     conf->sec_dir = apr_array_make(a, 40, sizeof(ap_conf_vector_t *));
434     conf->sec_url = apr_array_make(a, 40, sizeof(ap_conf_vector_t *));
435
436     /* recursion stopper */
437     conf->redirect_limit = 0; /* 0 == unset */
438     conf->subreq_limit = 0;
439
440     conf->protocol = NULL;
441     conf->accf_map = apr_table_make(a, 5);
442
443 #ifdef APR_TCP_DEFER_ACCEPT
444     apr_table_set(conf->accf_map, "http", "data");
445     apr_table_set(conf->accf_map, "https", "data");
446 #endif
447
448 #if APR_HAS_SO_ACCEPTFILTER
449 #ifndef ACCEPT_FILTER_NAME
450 #define ACCEPT_FILTER_NAME "httpready"
451 #ifdef __FreeBSD_version
452 #if __FreeBSD_version < 411000 /* httpready broken before 4.1.1 */
453 #undef ACCEPT_FILTER_NAME
454 #define ACCEPT_FILTER_NAME "dataready"
455 #endif
456 #endif
457 #endif
458     apr_table_set(conf->accf_map, "http", ACCEPT_FILTER_NAME);
459     apr_table_set(conf->accf_map, "https", "dataready");
460 #endif
461
462     conf->trace_enable = AP_TRACE_UNSET;
463
464     return (void *)conf;
465 }
466
467 static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
468 {
469     core_server_config *base = (core_server_config *)basev;
470     core_server_config *virt = (core_server_config *)virtv;
471     core_server_config *conf;
472
473     conf = (core_server_config *)apr_pmemdup(p, virt, sizeof(core_server_config));
474
475     if (!conf->access_name) {
476         conf->access_name = base->access_name;
477     }
478
479     if (!conf->ap_document_root) {
480         conf->ap_document_root = base->ap_document_root;
481     }
482
483     if (!conf->protocol) {
484         conf->protocol = base->protocol;
485     }
486
487     conf->sec_dir = apr_array_append(p, base->sec_dir, virt->sec_dir);
488     conf->sec_url = apr_array_append(p, base->sec_url, virt->sec_url);
489
490     conf->redirect_limit = virt->redirect_limit
491                            ? virt->redirect_limit
492                            : base->redirect_limit;
493
494     conf->subreq_limit = virt->subreq_limit
495                          ? virt->subreq_limit
496                          : base->subreq_limit;
497
498     conf->trace_enable = (virt->trace_enable != AP_TRACE_UNSET)
499                          ? virt->trace_enable
500                          : base->trace_enable;
501
502     return conf;
503 }
504
505 /* Add per-directory configuration entry (for <directory> section);
506  * these are part of the core server config.
507  */
508
509 AP_CORE_DECLARE(void) ap_add_per_dir_conf(server_rec *s, void *dir_config)
510 {
511     core_server_config *sconf = ap_get_module_config(s->module_config,
512                                                      &core_module);
513     void **new_space = (void **)apr_array_push(sconf->sec_dir);
514
515     *new_space = dir_config;
516 }
517
518 AP_CORE_DECLARE(void) ap_add_per_url_conf(server_rec *s, void *url_config)
519 {
520     core_server_config *sconf = ap_get_module_config(s->module_config,
521                                                      &core_module);
522     void **new_space = (void **)apr_array_push(sconf->sec_url);
523
524     *new_space = url_config;
525 }
526
527 AP_CORE_DECLARE(void) ap_add_file_conf(core_dir_config *conf, void *url_config)
528 {
529     void **new_space = (void **)apr_array_push(conf->sec_file);
530
531     *new_space = url_config;
532 }
533
534 /* We need to do a stable sort, qsort isn't stable.  So to make it stable
535  * we'll be maintaining the original index into the list, and using it
536  * as the minor key during sorting.  The major key is the number of
537  * components (where the root component is zero).
538  */
539 struct reorder_sort_rec {
540     ap_conf_vector_t *elt;
541     int orig_index;
542 };
543
544 static int reorder_sorter(const void *va, const void *vb)
545 {
546     const struct reorder_sort_rec *a = va;
547     const struct reorder_sort_rec *b = vb;
548     core_dir_config *core_a;
549     core_dir_config *core_b;
550
551     core_a = ap_get_module_config(a->elt, &core_module);
552     core_b = ap_get_module_config(b->elt, &core_module);
553
554     /* a regex always sorts after a non-regex
555      */
556     if (!core_a->r && core_b->r) {
557         return -1;
558     }
559     else if (core_a->r && !core_b->r) {
560         return 1;
561     }
562
563     /* we always sort next by the number of components
564      */
565     if (core_a->d_components < core_b->d_components) {
566         return -1;
567     }
568     else if (core_a->d_components > core_b->d_components) {
569         return 1;
570     }
571
572     /* They have the same number of components, we now have to compare
573      * the minor key to maintain the original order (from the config.)
574      */
575     return a->orig_index - b->orig_index;
576 }
577
578 void ap_core_reorder_directories(apr_pool_t *p, server_rec *s)
579 {
580     core_server_config *sconf;
581     apr_array_header_t *sec_dir;
582     struct reorder_sort_rec *sortbin;
583     int nelts;
584     ap_conf_vector_t **elts;
585     int i;
586     apr_pool_t *tmp;
587
588     sconf = ap_get_module_config(s->module_config, &core_module);
589     sec_dir = sconf->sec_dir;
590     nelts = sec_dir->nelts;
591     elts = (ap_conf_vector_t **)sec_dir->elts;
592
593     if (!nelts) {
594         /* simple case of already being sorted... */
595         /* We're not checking this condition to be fast... we're checking
596          * it to avoid trying to palloc zero bytes, which can trigger some
597          * memory debuggers to barf
598          */
599         return;
600     }
601
602     /* we have to allocate tmp space to do a stable sort */
603     apr_pool_create(&tmp, p);
604     sortbin = apr_palloc(tmp, sec_dir->nelts * sizeof(*sortbin));
605     for (i = 0; i < nelts; ++i) {
606         sortbin[i].orig_index = i;
607         sortbin[i].elt = elts[i];
608     }
609
610     qsort(sortbin, nelts, sizeof(*sortbin), reorder_sorter);
611
612     /* and now copy back to the original array */
613     for (i = 0; i < nelts; ++i) {
614         elts[i] = sortbin[i].elt;
615     }
616
617     apr_pool_destroy(tmp);
618 }
619
620 /*****************************************************************
621  *
622  * There are some elements of the core config structures in which
623  * other modules have a legitimate interest (this is ugly, but necessary
624  * to preserve NCSA back-compatibility).  So, we have a bunch of accessors
625  * here...
626  */
627
628 AP_DECLARE(int) ap_allow_options(request_rec *r)
629 {
630     core_dir_config *conf =
631       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
632
633     return conf->opts;
634 }
635
636 AP_DECLARE(int) ap_allow_overrides(request_rec *r)
637 {
638     core_dir_config *conf;
639     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
640                                                    &core_module);
641
642     return conf->override;
643 }
644
645 /*
646  * Optional function coming from mod_authn_core, used for 
647  * retrieving the type of autorization
648  */
649 static APR_OPTIONAL_FN_TYPE(authn_ap_auth_type) *authn_ap_auth_type;
650
651 AP_DECLARE(const char *) ap_auth_type(request_rec *r)
652 {
653     if (authn_ap_auth_type) {
654         return authn_ap_auth_type(r);
655     }
656     return NULL;
657 }
658
659 /*
660  * Optional function coming from mod_authn_core, used for 
661  * retrieving the authorization realm
662  */
663 static APR_OPTIONAL_FN_TYPE(authn_ap_auth_name) *authn_ap_auth_name;
664
665 AP_DECLARE(const char *) ap_auth_name(request_rec *r)
666 {
667     if (authn_ap_auth_name) {
668         return authn_ap_auth_name(r);
669     }
670     return NULL;
671 }
672
673 /*
674  * Optional function coming from mod_access_compat, used to determine how
675    access control interacts with authentication/authorization
676  */
677 static APR_OPTIONAL_FN_TYPE(access_compat_ap_satisfies) *access_compat_ap_satisfies;
678
679 AP_DECLARE(int) ap_satisfies(request_rec *r)
680 {
681     if (access_compat_ap_satisfies) {
682         return access_compat_ap_satisfies(r);
683     }
684     return SATISFY_NOSPEC;
685 }
686
687 AP_DECLARE(const char *) ap_default_type(request_rec *r)
688 {
689     core_dir_config *conf;
690
691     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
692                                                    &core_module);
693
694     return conf->ap_default_type
695                ? conf->ap_default_type
696                : DEFAULT_CONTENT_TYPE;
697 }
698
699 AP_DECLARE(const char *) ap_document_root(request_rec *r) /* Don't use this! */
700 {
701     core_server_config *conf;
702
703     conf = (core_server_config *)ap_get_module_config(r->server->module_config,
704                                                       &core_module);
705
706     return conf->ap_document_root;
707 }
708
709 /* Should probably just get rid of this... the only code that cares is
710  * part of the core anyway (and in fact, it isn't publicised to other
711  * modules).
712  */
713
714 char *ap_response_code_string(request_rec *r, int error_index)
715 {
716     core_dir_config *dirconf;
717     core_request_config *reqconf;
718
719     /* check for string registered via ap_custom_response() first */
720     reqconf = (core_request_config *)ap_get_module_config(r->request_config,
721                                                           &core_module);
722     if (reqconf->response_code_strings != NULL &&
723         reqconf->response_code_strings[error_index] != NULL) {
724         return reqconf->response_code_strings[error_index];
725     }
726
727     /* check for string specified via ErrorDocument */
728     dirconf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
729                                                       &core_module);
730
731     if (dirconf->response_code_strings == NULL) {
732         return NULL;
733     }
734
735     if (dirconf->response_code_strings[error_index] == &errordocument_default) {
736         return NULL;
737     }
738
739     return dirconf->response_code_strings[error_index];
740 }
741
742
743 /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
744 static APR_INLINE void do_double_reverse (conn_rec *conn)
745 {
746     apr_sockaddr_t *sa;
747     apr_status_t rv;
748
749     if (conn->double_reverse) {
750         /* already done */
751         return;
752     }
753
754     if (conn->remote_host == NULL || conn->remote_host[0] == '\0') {
755         /* single reverse failed, so don't bother */
756         conn->double_reverse = -1;
757         return;
758     }
759
760     rv = apr_sockaddr_info_get(&sa, conn->remote_host, APR_UNSPEC, 0, 0, conn->pool);
761     if (rv == APR_SUCCESS) {
762         while (sa) {
763             if (apr_sockaddr_equal(sa, conn->remote_addr)) {
764                 conn->double_reverse = 1;
765                 return;
766             }
767
768             sa = sa->next;
769         }
770     }
771
772     conn->double_reverse = -1;
773 }
774
775 AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config,
776                                             int type, int *str_is_ip)
777 {
778     int hostname_lookups;
779     int ignored_str_is_ip;
780
781     if (!str_is_ip) { /* caller doesn't want to know */
782         str_is_ip = &ignored_str_is_ip;
783     }
784     *str_is_ip = 0;
785
786     /* If we haven't checked the host name, and we want to */
787     if (dir_config) {
788         hostname_lookups =
789             ((core_dir_config *)ap_get_module_config(dir_config, &core_module))
790             ->hostname_lookups;
791
792         if (hostname_lookups == HOSTNAME_LOOKUP_UNSET) {
793             hostname_lookups = HOSTNAME_LOOKUP_OFF;
794         }
795     }
796     else {
797         /* the default */
798         hostname_lookups = HOSTNAME_LOOKUP_OFF;
799     }
800
801     if (type != REMOTE_NOLOOKUP
802         && conn->remote_host == NULL
803         && (type == REMOTE_DOUBLE_REV
804         || hostname_lookups != HOSTNAME_LOOKUP_OFF)) {
805
806         if (apr_getnameinfo(&conn->remote_host, conn->remote_addr, 0)
807             == APR_SUCCESS) {
808             ap_str_tolower(conn->remote_host);
809
810             if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) {
811                 do_double_reverse(conn);
812                 if (conn->double_reverse != 1) {
813                     conn->remote_host = NULL;
814                 }
815             }
816         }
817
818         /* if failed, set it to the NULL string to indicate error */
819         if (conn->remote_host == NULL) {
820             conn->remote_host = "";
821         }
822     }
823
824     if (type == REMOTE_DOUBLE_REV) {
825         do_double_reverse(conn);
826         if (conn->double_reverse == -1) {
827             return NULL;
828         }
829     }
830
831     /*
832      * Return the desired information; either the remote DNS name, if found,
833      * or either NULL (if the hostname was requested) or the IP address
834      * (if any identifier was requested).
835      */
836     if (conn->remote_host != NULL && conn->remote_host[0] != '\0') {
837         return conn->remote_host;
838     }
839     else {
840         if (type == REMOTE_HOST || type == REMOTE_DOUBLE_REV) {
841             return NULL;
842         }
843         else {
844             *str_is_ip = 1;
845             return conn->remote_ip;
846         }
847     }
848 }
849
850 /*
851  * Optional function coming from mod_ident, used for looking up ident user
852  */
853 static APR_OPTIONAL_FN_TYPE(ap_ident_lookup) *ident_lookup;
854
855 AP_DECLARE(const char *) ap_get_remote_logname(request_rec *r)
856 {
857     if (r->connection->remote_logname != NULL) {
858         return r->connection->remote_logname;
859     }
860
861     if (ident_lookup) {
862         return ident_lookup(r);
863     }
864
865     return NULL;
866 }
867
868 /* There are two options regarding what the "name" of a server is.  The
869  * "canonical" name as defined by ServerName and Port, or the "client's
870  * name" as supplied by a possible Host: header or full URI.
871  *
872  * The DNS option to UseCanonicalName causes this routine to do a
873  * reverse lookup on the local IP address of the connection and use
874  * that for the ServerName. This makes its value more reliable while
875  * at the same time allowing Demon's magic virtual hosting to work.
876  * The assumption is that DNS lookups are sufficiently quick...
877  * -- fanf 1998-10-03
878  */
879 AP_DECLARE(const char *) ap_get_server_name(request_rec *r)
880 {
881     conn_rec *conn = r->connection;
882     core_dir_config *d;
883     const char *retval;
884
885     d = (core_dir_config *)ap_get_module_config(r->per_dir_config,
886                                                 &core_module);
887
888     switch (d->use_canonical_name) {
889         case USE_CANONICAL_NAME_ON:
890             retval = r->server->server_hostname;
891             break;
892         case USE_CANONICAL_NAME_DNS:
893             if (conn->local_host == NULL) {
894                 if (apr_getnameinfo(&conn->local_host,
895                                 conn->local_addr, 0) != APR_SUCCESS)
896                     conn->local_host = apr_pstrdup(conn->pool,
897                                                r->server->server_hostname);
898                 else {
899                     ap_str_tolower(conn->local_host);
900                 }
901             }
902             retval = conn->local_host;
903             break;
904         case USE_CANONICAL_NAME_OFF:
905         case USE_CANONICAL_NAME_UNSET:
906             retval = r->hostname ? r->hostname : r->server->server_hostname;
907             break;
908         default:
909             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
910                          "ap_get_server_name: Invalid UCN Option somehow");
911             retval = "localhost";
912             break;
913     }
914     return retval;
915 }
916
917 /*
918  * Get the current server name from the request for the purposes
919  * of using in a URL.  If the server name is an IPv6 literal
920  * address, it will be returned in URL format (e.g., "[fe80::1]").
921  */
922 static const char *get_server_name_for_url(request_rec *r)
923 {
924     const char *plain_server_name = ap_get_server_name(r);
925
926 #if APR_HAVE_IPV6
927     if (ap_strchr_c(plain_server_name, ':')) { /* IPv6 literal? */
928         return apr_psprintf(r->pool, "[%s]", plain_server_name);
929     }
930 #endif
931     return plain_server_name;
932 }
933
934 AP_DECLARE(apr_port_t) ap_get_server_port(const request_rec *r)
935 {
936     apr_port_t port;
937     core_dir_config *d =
938       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
939
940     switch (d->use_canonical_name) {
941         case USE_CANONICAL_NAME_OFF:
942         case USE_CANONICAL_NAME_DNS:
943         case USE_CANONICAL_NAME_UNSET:
944             if (d->use_canonical_phys_port == USE_CANONICAL_PHYS_PORT_ON)
945                 port = r->parsed_uri.port_str ? r->parsed_uri.port :
946                        r->connection->local_addr->port ? r->connection->local_addr->port :
947                        r->server->port ? r->server->port :
948                        ap_default_port(r);
949             else /* USE_CANONICAL_PHYS_PORT_OFF or USE_CANONICAL_PHYS_PORT_UNSET */
950                 port = r->parsed_uri.port_str ? r->parsed_uri.port :
951                        r->server->port ? r->server->port :
952                        ap_default_port(r);
953             break;
954         case USE_CANONICAL_NAME_ON:
955             /* With UseCanonicalName on (and in all versions prior to 1.3)
956              * Apache will use the hostname and port specified in the
957              * ServerName directive to construct a canonical name for the
958              * server. (If no port was specified in the ServerName
959              * directive, Apache uses the port supplied by the client if
960              * any is supplied, and finally the default port for the protocol
961              * used.
962              */
963             if (d->use_canonical_phys_port == USE_CANONICAL_PHYS_PORT_ON)
964                 port = r->server->port ? r->server->port :
965                        r->connection->local_addr->port ? r->connection->local_addr->port :
966                        ap_default_port(r);
967             else /* USE_CANONICAL_PHYS_PORT_OFF or USE_CANONICAL_PHYS_PORT_UNSET */
968                 port = r->server->port ? r->server->port :
969                        ap_default_port(r);
970             break;
971         default:
972             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
973                          "ap_get_server_port: Invalid UCN Option somehow");
974             port = ap_default_port(r);
975             break;
976     }
977
978     return port;
979 }
980
981 AP_DECLARE(char *) ap_construct_url(apr_pool_t *p, const char *uri,
982                                     request_rec *r)
983 {
984     unsigned port = ap_get_server_port(r);
985     const char *host = get_server_name_for_url(r);
986
987     if (ap_is_default_port(port, r)) {
988         return apr_pstrcat(p, ap_http_scheme(r), "://", host, uri, NULL);
989     }
990
991     return apr_psprintf(p, "%s://%s:%u%s", ap_http_scheme(r), host, port, uri);
992 }
993
994 AP_DECLARE(apr_off_t) ap_get_limit_req_body(const request_rec *r)
995 {
996     core_dir_config *d =
997       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
998
999     if (d->limit_req_body == AP_LIMIT_REQ_BODY_UNSET) {
1000         return AP_DEFAULT_LIMIT_REQ_BODY;
1001     }
1002
1003     return d->limit_req_body;
1004 }
1005
1006
1007 /*****************************************************************
1008  *
1009  * Commands... this module handles almost all of the NCSA httpd.conf
1010  * commands, but most of the old srm.conf is in the the modules.
1011  */
1012
1013
1014 /* returns a parent if it matches the given directive */
1015 static const ap_directive_t * find_parent(const ap_directive_t *dirp,
1016                                           const char *what)
1017 {
1018     while (dirp->parent != NULL) {
1019         dirp = dirp->parent;
1020
1021         /* ### it would be nice to have atom-ized directives */
1022         if (strcasecmp(dirp->directive, what) == 0)
1023             return dirp;
1024     }
1025
1026     return NULL;
1027 }
1028
1029 AP_DECLARE(const char *) ap_check_cmd_context(cmd_parms *cmd,
1030                                               unsigned forbidden)
1031 {
1032     const char *gt = (cmd->cmd->name[0] == '<'
1033                       && cmd->cmd->name[strlen(cmd->cmd->name)-1] != '>')
1034                          ? ">" : "";
1035     const ap_directive_t *found;
1036
1037     if ((forbidden & NOT_IN_VIRTUALHOST) && cmd->server->is_virtual) {
1038         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1039                            " cannot occur within <VirtualHost> section", NULL);
1040     }
1041
1042     if ((forbidden & NOT_IN_LIMIT) && cmd->limited != -1) {
1043         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1044                            " cannot occur within <Limit> section", NULL);
1045     }
1046
1047     if ((forbidden & NOT_IN_DIR_LOC_FILE) == NOT_IN_DIR_LOC_FILE) {
1048         if (cmd->path != NULL) {
1049             return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1050                             " cannot occur within <Directory/Location/Files> "
1051                             "section", NULL);
1052         }
1053         if (cmd->cmd->req_override & EXEC_ON_READ) {
1054             /* EXEC_ON_READ must be NOT_IN_DIR_LOC_FILE, if not, it will
1055              * (deliberately) segfault below in the individual tests...
1056              */
1057             return NULL;
1058         }
1059     }
1060
1061     if (((forbidden & NOT_IN_DIRECTORY)
1062          && ((found = find_parent(cmd->directive, "<Directory"))
1063              || (found = find_parent(cmd->directive, "<DirectoryMatch"))))
1064         || ((forbidden & NOT_IN_LOCATION)
1065             && ((found = find_parent(cmd->directive, "<Location"))
1066                 || (found = find_parent(cmd->directive, "<LocationMatch"))))
1067         || ((forbidden & NOT_IN_FILES)
1068             && ((found = find_parent(cmd->directive, "<Files"))
1069                 || (found = find_parent(cmd->directive, "<FilesMatch"))))) {
1070         return apr_pstrcat(cmd->pool, cmd->cmd->name, gt,
1071                            " cannot occur within ", found->directive,
1072                            "> section", NULL);
1073     }
1074
1075     return NULL;
1076 }
1077
1078 static const char *set_access_name(cmd_parms *cmd, void *dummy,
1079                                    const char *arg)
1080 {
1081     void *sconf = cmd->server->module_config;
1082     core_server_config *conf = ap_get_module_config(sconf, &core_module);
1083
1084     const char *err = ap_check_cmd_context(cmd,
1085                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1086     if (err != NULL) {
1087         return err;
1088     }
1089
1090     conf->access_name = apr_pstrdup(cmd->pool, arg);
1091     return NULL;
1092 }
1093
1094
1095 static const char *set_define(cmd_parms *cmd, void *dummy,
1096                                    const char *optarg)
1097 {
1098     char **newv;
1099
1100     const char *err = ap_check_cmd_context(cmd,
1101                                            GLOBAL_ONLY);
1102     if (err != NULL) {
1103         return err;
1104     }
1105
1106     newv = (char **)apr_array_push(ap_server_config_defines);
1107     *newv = apr_pstrdup(cmd->pool, optarg);
1108
1109     return NULL;
1110 }
1111
1112 #ifdef GPROF
1113 static const char *set_gprof_dir(cmd_parms *cmd, void *dummy, const char *arg)
1114 {
1115     void *sconf = cmd->server->module_config;
1116     core_server_config *conf = ap_get_module_config(sconf, &core_module);
1117
1118     const char *err = ap_check_cmd_context(cmd,
1119                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1120     if (err != NULL) {
1121         return err;
1122     }
1123
1124     conf->gprof_dir = apr_pstrdup(cmd->pool, arg);
1125     return NULL;
1126 }
1127 #endif /*GPROF*/
1128
1129 static const char *set_add_default_charset(cmd_parms *cmd,
1130                                            void *d_, const char *arg)
1131 {
1132     core_dir_config *d = d_;
1133
1134     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1135     if (err != NULL) {
1136         return err;
1137     }
1138
1139     if (!strcasecmp(arg, "Off")) {
1140        d->add_default_charset = ADD_DEFAULT_CHARSET_OFF;
1141     }
1142     else if (!strcasecmp(arg, "On")) {
1143        d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
1144        d->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
1145     }
1146     else {
1147        d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
1148        d->add_default_charset_name = arg;
1149     }
1150
1151     return NULL;
1152 }
1153
1154 static const char *set_document_root(cmd_parms *cmd, void *dummy,
1155                                      const char *arg)
1156 {
1157     void *sconf = cmd->server->module_config;
1158     core_server_config *conf = ap_get_module_config(sconf, &core_module);
1159
1160     const char *err = ap_check_cmd_context(cmd,
1161                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1162     if (err != NULL) {
1163         return err;
1164     }
1165
1166     /* Make it absolute, relative to ServerRoot */
1167     arg = ap_server_root_relative(cmd->pool, arg);
1168     if (arg == NULL) {
1169         return "DocumentRoot must be a directory";
1170     }
1171
1172     /* TODO: ap_configtestonly && ap_docrootcheck && */
1173     if (apr_filepath_merge((char**)&conf->ap_document_root, NULL, arg,
1174                            APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS
1175         || !ap_is_directory(cmd->pool, arg)) {
1176         if (cmd->server->is_virtual) {
1177             ap_log_perror(APLOG_MARK, APLOG_STARTUP, 0,
1178                           cmd->pool,
1179                           "Warning: DocumentRoot [%s] does not exist",
1180                           arg);
1181             conf->ap_document_root = arg;
1182         }
1183         else {
1184             return "DocumentRoot must be a directory";
1185         }
1186     }
1187     return NULL;
1188 }
1189
1190 AP_DECLARE(void) ap_custom_response(request_rec *r, int status,
1191                                     const char *string)
1192 {
1193     core_request_config *conf =
1194         ap_get_module_config(r->request_config, &core_module);
1195     int idx;
1196
1197     if (conf->response_code_strings == NULL) {
1198         conf->response_code_strings =
1199             apr_pcalloc(r->pool,
1200                         sizeof(*conf->response_code_strings) * RESPONSE_CODES);
1201     }
1202
1203     idx = ap_index_of_response(status);
1204
1205     conf->response_code_strings[idx] =
1206        ((ap_is_url(string) || (*string == '/')) && (*string != '"')) ?
1207        apr_pstrdup(r->pool, string) : apr_pstrcat(r->pool, "\"", string, NULL);
1208 }
1209
1210 static const char *set_error_document(cmd_parms *cmd, void *conf_,
1211                                       const char *errno_str, const char *msg)
1212 {
1213     core_dir_config *conf = conf_;
1214     int error_number, index_number, idx500;
1215     enum { MSG, LOCAL_PATH, REMOTE_PATH } what = MSG;
1216
1217     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1218     if (err != NULL) {
1219         return err;
1220     }
1221
1222     /* 1st parameter should be a 3 digit number, which we recognize;
1223      * convert it into an array index
1224      */
1225     error_number = atoi(errno_str);
1226     idx500 = ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR);
1227
1228     if (error_number == HTTP_INTERNAL_SERVER_ERROR) {
1229         index_number = idx500;
1230     }
1231     else if ((index_number = ap_index_of_response(error_number)) == idx500) {
1232         return apr_pstrcat(cmd->pool, "Unsupported HTTP response code ",
1233                            errno_str, NULL);
1234     }
1235
1236     /* Heuristic to determine second argument. */
1237     if (ap_strchr_c(msg,' '))
1238         what = MSG;
1239     else if (msg[0] == '/')
1240         what = LOCAL_PATH;
1241     else if (ap_is_url(msg))
1242         what = REMOTE_PATH;
1243     else
1244         what = MSG;
1245
1246     /* The entry should be ignored if it is a full URL for a 401 error */
1247
1248     if (error_number == 401 && what == REMOTE_PATH) {
1249         ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, cmd->server,
1250                      "cannot use a full URL in a 401 ErrorDocument "
1251                      "directive --- ignoring!");
1252     }
1253     else { /* Store it... */
1254         if (conf->response_code_strings == NULL) {
1255             conf->response_code_strings =
1256                 apr_pcalloc(cmd->pool,
1257                             sizeof(*conf->response_code_strings) *
1258                             RESPONSE_CODES);
1259         }
1260
1261         if (strcmp(msg, "default") == 0) {
1262             /* special case: ErrorDocument 404 default restores the
1263              * canned server error response
1264              */
1265             conf->response_code_strings[index_number] = &errordocument_default;
1266         }
1267         else {
1268             /* hack. Prefix a " if it is a msg; as that is what
1269              * http_protocol.c relies on to distinguish between
1270              * a msg and a (local) path.
1271              */
1272             conf->response_code_strings[index_number] = (what == MSG) ?
1273                     apr_pstrcat(cmd->pool, "\"",msg,NULL) :
1274                     apr_pstrdup(cmd->pool, msg);
1275         }
1276     }
1277
1278     return NULL;
1279 }
1280
1281 static const char *set_allow_opts(cmd_parms *cmd, allow_options_t *opts,
1282                                   const char *l)
1283 {
1284     allow_options_t opt;
1285     int first = 1;
1286
1287     char *w, *p = (char *) l;
1288     char *tok_state;
1289
1290     while ((w = apr_strtok(p, ",", &tok_state)) != NULL) {
1291
1292         if (first) {
1293             p = NULL;
1294             *opts = OPT_NONE;
1295             first = 0;
1296         }
1297
1298         if (!strcasecmp(w, "Indexes")) {
1299             opt = OPT_INDEXES;
1300         }
1301         else if (!strcasecmp(w, "Includes")) {
1302             opt = OPT_INCLUDES;
1303         }
1304         else if (!strcasecmp(w, "IncludesNOEXEC")) {
1305             opt = (OPT_INCLUDES | OPT_INCNOEXEC);
1306         }
1307         else if (!strcasecmp(w, "FollowSymLinks")) {
1308             opt = OPT_SYM_LINKS;
1309         }
1310         else if (!strcasecmp(w, "SymLinksIfOwnerMatch")) {
1311             opt = OPT_SYM_OWNER;
1312         }
1313         else if (!strcasecmp(w, "ExecCGI")) {
1314             opt = OPT_EXECCGI;
1315         }
1316         else if (!strcasecmp(w, "MultiViews")) {
1317             opt = OPT_MULTI;
1318         }
1319         else if (!strcasecmp(w, "RunScripts")) { /* AI backcompat. Yuck */
1320             opt = OPT_MULTI|OPT_EXECCGI;
1321         }
1322         else if (!strcasecmp(w, "None")) {
1323             opt = OPT_NONE;
1324         }
1325         else if (!strcasecmp(w, "All")) {
1326             opt = OPT_ALL;
1327         }
1328         else {
1329             return apr_pstrcat(cmd->pool, "Illegal option ", w, NULL);
1330         }
1331
1332         *opts |= opt;
1333     }
1334
1335     (*opts) &= (~OPT_UNSET);
1336
1337     return NULL;
1338 }
1339
1340 static const char *set_override(cmd_parms *cmd, void *d_, const char *l)
1341 {
1342     core_dir_config *d = d_;
1343     char *w;
1344     char *k, *v;
1345
1346     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1347     if (err != NULL) {
1348         return err;
1349     }
1350
1351     /* Throw a warning if we're in <Location> or <Files> */
1352     if (ap_check_cmd_context(cmd, NOT_IN_LOCATION | NOT_IN_FILES)) {
1353         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
1354                      "Useless use of AllowOverride in line %d of %s.",
1355                      cmd->directive->line_num, cmd->directive->filename);
1356     }
1357
1358     d->override = OR_NONE;
1359     while (l[0]) {
1360         w = ap_getword_conf(cmd->pool, &l);
1361
1362         k = w;
1363         v = strchr(k, '=');
1364         if (v) {
1365                 *v++ = '\0';
1366         }
1367
1368         if (!strcasecmp(w, "Limit")) {
1369             d->override |= OR_LIMIT;
1370         }
1371         else if (!strcasecmp(k, "Options")) {
1372             d->override |= OR_OPTIONS;
1373             if (v)
1374                 set_allow_opts(cmd, &(d->override_opts), v);
1375             else
1376                 d->override_opts = OPT_ALL;
1377         }
1378         else if (!strcasecmp(w, "FileInfo")) {
1379             d->override |= OR_FILEINFO;
1380         }
1381         else if (!strcasecmp(w, "AuthConfig")) {
1382             d->override |= OR_AUTHCFG;
1383         }
1384         else if (!strcasecmp(w, "Indexes")) {
1385             d->override |= OR_INDEXES;
1386         }
1387         else if (!strcasecmp(w, "None")) {
1388             d->override = OR_NONE;
1389         }
1390         else if (!strcasecmp(w, "All")) {
1391             d->override = OR_ALL;
1392         }
1393         else {
1394             return apr_pstrcat(cmd->pool, "Illegal override option ", w, NULL);
1395         }
1396
1397         d->override &= ~OR_UNSET;
1398     }
1399
1400     return NULL;
1401 }
1402
1403 static const char *set_options(cmd_parms *cmd, void *d_, const char *l)
1404 {
1405     core_dir_config *d = d_;
1406     allow_options_t opt;
1407     int first = 1;
1408     char action;
1409
1410     while (l[0]) {
1411         char *w = ap_getword_conf(cmd->pool, &l);
1412         action = '\0';
1413
1414         if (*w == '+' || *w == '-') {
1415             action = *(w++);
1416         }
1417         else if (first) {
1418               d->opts = OPT_NONE;
1419             first = 0;
1420         }
1421
1422         if (!strcasecmp(w, "Indexes")) {
1423             opt = OPT_INDEXES;
1424         }
1425         else if (!strcasecmp(w, "Includes")) {
1426             opt = OPT_INCLUDES;
1427         }
1428         else if (!strcasecmp(w, "IncludesNOEXEC")) {
1429             opt = (OPT_INCLUDES | OPT_INCNOEXEC);
1430         }
1431         else if (!strcasecmp(w, "FollowSymLinks")) {
1432             opt = OPT_SYM_LINKS;
1433         }
1434         else if (!strcasecmp(w, "SymLinksIfOwnerMatch")) {
1435             opt = OPT_SYM_OWNER;
1436         }
1437         else if (!strcasecmp(w, "ExecCGI")) {
1438             opt = OPT_EXECCGI;
1439         }
1440         else if (!strcasecmp(w, "MultiViews")) {
1441             opt = OPT_MULTI;
1442         }
1443         else if (!strcasecmp(w, "RunScripts")) { /* AI backcompat. Yuck */
1444             opt = OPT_MULTI|OPT_EXECCGI;
1445         }
1446         else if (!strcasecmp(w, "None")) {
1447             opt = OPT_NONE;
1448         }
1449         else if (!strcasecmp(w, "All")) {
1450             opt = OPT_ALL;
1451         }
1452         else {
1453             return apr_pstrcat(cmd->pool, "Illegal option ", w, NULL);
1454         }
1455
1456         if (!(cmd->override_opts & opt) && opt != OPT_NONE) {
1457             return apr_pstrcat(cmd->pool, "Option ", w, " not allowed here", NULL);
1458         }
1459         else if (action == '-') {
1460             /* we ensure the invariant (d->opts_add & d->opts_remove) == 0 */
1461             d->opts_remove |= opt;
1462             d->opts_add &= ~opt;
1463             d->opts &= ~opt;
1464         }
1465         else if (action == '+') {
1466             d->opts_add |= opt;
1467             d->opts_remove &= ~opt;
1468             d->opts |= opt;
1469         }
1470         else {
1471             d->opts |= opt;
1472         }
1473     }
1474
1475     return NULL;
1476 }
1477
1478 /*
1479  * Note what data should be used when forming file ETag values.
1480  * It would be nicer to do this as an ITERATE, but then we couldn't
1481  * remember the +/- state properly.
1482  */
1483 static const char *set_etag_bits(cmd_parms *cmd, void *mconfig,
1484                                  const char *args_p)
1485 {
1486     core_dir_config *cfg;
1487     etag_components_t bit;
1488     char action;
1489     char *token;
1490     const char *args;
1491     int valid;
1492     int first;
1493     int explicit;
1494
1495     cfg = (core_dir_config *)mconfig;
1496
1497     args = args_p;
1498     first = 1;
1499     explicit = 0;
1500     while (args[0] != '\0') {
1501         action = '*';
1502         bit = ETAG_UNSET;
1503         valid = 1;
1504         token = ap_getword_conf(cmd->pool, &args);
1505         if ((*token == '+') || (*token == '-')) {
1506             action = *token;
1507             token++;
1508         }
1509         else {
1510             /*
1511              * The occurrence of an absolute setting wipes
1512              * out any previous relative ones.  The first such
1513              * occurrence forgets any inherited ones, too.
1514              */
1515             if (first) {
1516                 cfg->etag_bits = ETAG_UNSET;
1517                 cfg->etag_add = ETAG_UNSET;
1518                 cfg->etag_remove = ETAG_UNSET;
1519                 first = 0;
1520             }
1521         }
1522
1523         if (strcasecmp(token, "None") == 0) {
1524             if (action != '*') {
1525                 valid = 0;
1526             }
1527             else {
1528                 cfg->etag_bits = bit = ETAG_NONE;
1529                 explicit = 1;
1530             }
1531         }
1532         else if (strcasecmp(token, "All") == 0) {
1533             if (action != '*') {
1534                 valid = 0;
1535             }
1536             else {
1537                 explicit = 1;
1538                 cfg->etag_bits = bit = ETAG_ALL;
1539             }
1540         }
1541         else if (strcasecmp(token, "Size") == 0) {
1542             bit = ETAG_SIZE;
1543         }
1544         else if ((strcasecmp(token, "LMTime") == 0)
1545                  || (strcasecmp(token, "MTime") == 0)
1546                  || (strcasecmp(token, "LastModified") == 0)) {
1547             bit = ETAG_MTIME;
1548         }
1549         else if (strcasecmp(token, "INode") == 0) {
1550             bit = ETAG_INODE;
1551         }
1552         else {
1553             return apr_pstrcat(cmd->pool, "Unknown keyword '",
1554                                token, "' for ", cmd->cmd->name,
1555                                " directive", NULL);
1556         }
1557
1558         if (! valid) {
1559             return apr_pstrcat(cmd->pool, cmd->cmd->name, " keyword '",
1560                                token, "' cannot be used with '+' or '-'",
1561                                NULL);
1562         }
1563
1564         if (action == '+') {
1565             /*
1566              * Make sure it's in the 'add' list and absent from the
1567              * 'subtract' list.
1568              */
1569             cfg->etag_add |= bit;
1570             cfg->etag_remove &= (~ bit);
1571         }
1572         else if (action == '-') {
1573             cfg->etag_remove |= bit;
1574             cfg->etag_add &= (~ bit);
1575         }
1576         else {
1577             /*
1578              * Non-relative values wipe out any + or - values
1579              * accumulated so far.
1580              */
1581             cfg->etag_bits |= bit;
1582             cfg->etag_add = ETAG_UNSET;
1583             cfg->etag_remove = ETAG_UNSET;
1584             explicit = 1;
1585         }
1586     }
1587
1588     /*
1589      * Any setting at all will clear the 'None' and 'Unset' bits.
1590      */
1591
1592     if (cfg->etag_add != ETAG_UNSET) {
1593         cfg->etag_add &= (~ ETAG_UNSET);
1594     }
1595
1596     if (cfg->etag_remove != ETAG_UNSET) {
1597         cfg->etag_remove &= (~ ETAG_UNSET);
1598     }
1599
1600     if (explicit) {
1601         cfg->etag_bits &= (~ ETAG_UNSET);
1602
1603         if ((cfg->etag_bits & ETAG_NONE) != ETAG_NONE) {
1604             cfg->etag_bits &= (~ ETAG_NONE);
1605         }
1606     }
1607
1608     return NULL;
1609 }
1610
1611 static const char *set_enable_mmap(cmd_parms *cmd, void *d_,
1612                                    const char *arg)
1613 {
1614     core_dir_config *d = d_;
1615     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1616
1617     if (err != NULL) {
1618         return err;
1619     }
1620
1621     if (strcasecmp(arg, "on") == 0) {
1622         d->enable_mmap = ENABLE_MMAP_ON;
1623     }
1624     else if (strcasecmp(arg, "off") == 0) {
1625         d->enable_mmap = ENABLE_MMAP_OFF;
1626     }
1627     else {
1628         return "parameter must be 'on' or 'off'";
1629     }
1630
1631     return NULL;
1632 }
1633
1634 static const char *set_enable_sendfile(cmd_parms *cmd, void *d_,
1635                                    const char *arg)
1636 {
1637     core_dir_config *d = d_;
1638     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1639
1640     if (err != NULL) {
1641         return err;
1642     }
1643
1644     if (strcasecmp(arg, "on") == 0) {
1645         d->enable_sendfile = ENABLE_SENDFILE_ON;
1646     }
1647     else if (strcasecmp(arg, "off") == 0) {
1648         d->enable_sendfile = ENABLE_SENDFILE_OFF;
1649     }
1650     else {
1651         return "parameter must be 'on' or 'off'";
1652     }
1653
1654     return NULL;
1655 }
1656
1657
1658 /*
1659  * Report a missing-'>' syntax error.
1660  */
1661 static char *unclosed_directive(cmd_parms *cmd)
1662 {
1663     return apr_pstrcat(cmd->pool, cmd->cmd->name,
1664                        "> directive missing closing '>'", NULL);
1665 }
1666
1667 /*
1668  * Report a missing args in '<Foo >' syntax error.
1669  */
1670 static char *missing_container_arg(cmd_parms *cmd)
1671 {
1672     return apr_pstrcat(cmd->pool, cmd->cmd->name,
1673                        "> directive requires additional arguments", NULL);
1674 }
1675
1676 AP_CORE_DECLARE_NONSTD(const char *) ap_limit_section(cmd_parms *cmd,
1677                                                       void *dummy,
1678                                                       const char *arg)
1679 {
1680     const char *endp = ap_strrchr_c(arg, '>');
1681     const char *limited_methods;
1682     void *tog = cmd->cmd->cmd_data;
1683     apr_int64_t limited = 0;
1684     const char *errmsg;
1685
1686     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
1687     if (err != NULL) {
1688         return err;
1689     }
1690
1691     if (endp == NULL) {
1692         return unclosed_directive(cmd);
1693     }
1694
1695     limited_methods = apr_pstrndup(cmd->pool, arg, endp - arg);
1696
1697     if (!limited_methods[0]) {
1698         return missing_container_arg(cmd);
1699     }
1700
1701     while (limited_methods[0]) {
1702         char *method = ap_getword_conf(cmd->pool, &limited_methods);
1703         int methnum;
1704
1705         /* check for builtin or module registered method number */
1706         methnum = ap_method_number_of(method);
1707
1708         if (methnum == M_TRACE && !tog) {
1709             return "TRACE cannot be controlled by <Limit>, see TraceEnable";
1710         }
1711         else if (methnum == M_INVALID) {
1712             /* method has not been registered yet, but resorce restriction
1713              * is always checked before method handling, so register it.
1714              */
1715             methnum = ap_method_register(cmd->pool, method);
1716         }
1717
1718         limited |= (AP_METHOD_BIT << methnum);
1719     }
1720
1721     /* Killing two features with one function,
1722      * if (tog == NULL) <Limit>, else <LimitExcept>
1723      */
1724     cmd->limited = tog ? ~limited : limited;
1725
1726     errmsg = ap_walk_config(cmd->directive->first_child, cmd, cmd->context);
1727
1728     cmd->limited = -1;
1729
1730     return errmsg;
1731 }
1732
1733 /* XXX: Bogus - need to do this differently (at least OS2/Netware suffer
1734  * the same problem!!!
1735  * We use this in <DirectoryMatch> and <FilesMatch>, to ensure that
1736  * people don't get bitten by wrong-cased regex matches
1737  */
1738
1739 #ifdef WIN32
1740 #define USE_ICASE AP_REG_ICASE
1741 #else
1742 #define USE_ICASE 0
1743 #endif
1744
1745 static const char *dirsection(cmd_parms *cmd, void *mconfig, const char *arg)
1746 {
1747     const char *errmsg;
1748     const char *endp = ap_strrchr_c(arg, '>');
1749     int old_overrides = cmd->override;
1750     char *old_path = cmd->path;
1751     core_dir_config *conf;
1752     ap_conf_vector_t *new_dir_conf = ap_create_per_dir_config(cmd->pool);
1753     ap_regex_t *r = NULL;
1754     const command_rec *thiscmd = cmd->cmd;
1755
1756     const char *err = ap_check_cmd_context(cmd,
1757                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1758     if (err != NULL) {
1759         return err;
1760     }
1761
1762     if (endp == NULL) {
1763         return unclosed_directive(cmd);
1764     }
1765
1766     arg = apr_pstrndup(cmd->pool, arg, endp - arg);
1767
1768     if (!arg[0]) {
1769         return missing_container_arg(cmd);
1770     }
1771
1772     if (!arg) {
1773         if (thiscmd->cmd_data)
1774             return "<DirectoryMatch > block must specify a path";
1775         else
1776             return "<Directory > block must specify a path";
1777     }
1778
1779     cmd->path = ap_getword_conf(cmd->pool, &arg);
1780     cmd->override = OR_ALL|ACCESS_CONF;
1781
1782     if (!strcmp(cmd->path, "~")) {
1783         cmd->path = ap_getword_conf(cmd->pool, &arg);
1784         if (!cmd->path)
1785             return "<Directory ~ > block must specify a path";
1786         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
1787         if (!r) {
1788             return "Regex could not be compiled";
1789         }
1790     }
1791     else if (thiscmd->cmd_data) { /* <DirectoryMatch> */
1792         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
1793         if (!r) {
1794             return "Regex could not be compiled";
1795         }
1796     }
1797     else if (!strcmp(cmd->path, "/") == 0)
1798     {
1799         char *newpath;
1800
1801         /*
1802          * Ensure that the pathname is canonical, and append the trailing /
1803          */
1804         apr_status_t rv = apr_filepath_merge(&newpath, NULL, cmd->path,
1805                                              APR_FILEPATH_TRUENAME, cmd->pool);
1806         if (rv != APR_SUCCESS && rv != APR_EPATHWILD) {
1807             return apr_pstrcat(cmd->pool, "<Directory \"", cmd->path,
1808                                "\"> path is invalid.", NULL);
1809         }
1810
1811         cmd->path = newpath;
1812         if (cmd->path[strlen(cmd->path) - 1] != '/')
1813             cmd->path = apr_pstrcat(cmd->pool, cmd->path, "/", NULL);
1814     }
1815
1816     /* initialize our config and fetch it */
1817     conf = ap_set_config_vectors(cmd->server, new_dir_conf, cmd->path,
1818                                  &core_module, cmd->pool);
1819
1820     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_dir_conf);
1821     if (errmsg != NULL)
1822         return errmsg;
1823
1824     conf->r = r;
1825     conf->d = cmd->path;
1826     conf->d_is_fnmatch = (apr_fnmatch_test(conf->d) != 0);
1827
1828     /* Make this explicit - the "/" root has 0 elements, that is, we
1829      * will always merge it, and it will always sort and merge first.
1830      * All others are sorted and tested by the number of slashes.
1831      */
1832     if (strcmp(conf->d, "/") == 0)
1833         conf->d_components = 0;
1834     else
1835         conf->d_components = ap_count_dirs(conf->d);
1836
1837     ap_add_per_dir_conf(cmd->server, new_dir_conf);
1838
1839     if (*arg != '\0') {
1840         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1841                            "> arguments not (yet) supported.", NULL);
1842     }
1843
1844     cmd->path = old_path;
1845     cmd->override = old_overrides;
1846
1847     return NULL;
1848 }
1849
1850 static const char *urlsection(cmd_parms *cmd, void *mconfig, const char *arg)
1851 {
1852     const char *errmsg;
1853     const char *endp = ap_strrchr_c(arg, '>');
1854     int old_overrides = cmd->override;
1855     char *old_path = cmd->path;
1856     core_dir_config *conf;
1857     ap_regex_t *r = NULL;
1858     const command_rec *thiscmd = cmd->cmd;
1859     ap_conf_vector_t *new_url_conf = ap_create_per_dir_config(cmd->pool);
1860     const char *err = ap_check_cmd_context(cmd,
1861                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1862     if (err != NULL) {
1863         return err;
1864     }
1865
1866     if (endp == NULL) {
1867         return unclosed_directive(cmd);
1868     }
1869
1870     arg = apr_pstrndup(cmd->pool, arg, endp - arg);
1871
1872     if (!arg[0]) {
1873         return missing_container_arg(cmd);
1874     }
1875
1876     cmd->path = ap_getword_conf(cmd->pool, &arg);
1877     cmd->override = OR_ALL|ACCESS_CONF;
1878
1879     if (thiscmd->cmd_data) { /* <LocationMatch> */
1880         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED);
1881         if (!r) {
1882             return "Regex could not be compiled";
1883         }
1884     }
1885     else if (!strcmp(cmd->path, "~")) {
1886         cmd->path = ap_getword_conf(cmd->pool, &arg);
1887         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED);
1888         if (!r) {
1889             return "Regex could not be compiled";
1890         }
1891     }
1892
1893     /* initialize our config and fetch it */
1894     conf = ap_set_config_vectors(cmd->server, new_url_conf, cmd->path,
1895                                  &core_module, cmd->pool);
1896
1897     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_url_conf);
1898     if (errmsg != NULL)
1899         return errmsg;
1900
1901     conf->d = apr_pstrdup(cmd->pool, cmd->path);     /* No mangling, please */
1902     conf->d_is_fnmatch = apr_fnmatch_test(conf->d) != 0;
1903     conf->r = r;
1904
1905     ap_add_per_url_conf(cmd->server, new_url_conf);
1906
1907     if (*arg != '\0') {
1908         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1909                            "> arguments not (yet) supported.", NULL);
1910     }
1911
1912     cmd->path = old_path;
1913     cmd->override = old_overrides;
1914
1915     return NULL;
1916 }
1917
1918 static const char *filesection(cmd_parms *cmd, void *mconfig, const char *arg)
1919 {
1920     const char *errmsg;
1921     const char *endp = ap_strrchr_c(arg, '>');
1922     int old_overrides = cmd->override;
1923     char *old_path = cmd->path;
1924     core_dir_config *conf;
1925     ap_regex_t *r = NULL;
1926     const command_rec *thiscmd = cmd->cmd;
1927     core_dir_config *c = mconfig;
1928     ap_conf_vector_t *new_file_conf = ap_create_per_dir_config(cmd->pool);
1929     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_LOCATION);
1930
1931     if (err != NULL) {
1932         return err;
1933     }
1934
1935     if (endp == NULL) {
1936         return unclosed_directive(cmd);
1937     }
1938
1939     arg = apr_pstrndup(cmd->pool, arg, endp - arg);
1940
1941     if (!arg[0]) {
1942         return missing_container_arg(cmd);
1943     }
1944
1945     cmd->path = ap_getword_conf(cmd->pool, &arg);
1946     /* Only if not an .htaccess file */
1947     if (!old_path) {
1948         cmd->override = OR_ALL|ACCESS_CONF;
1949     }
1950
1951     if (thiscmd->cmd_data) { /* <FilesMatch> */
1952         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
1953         if (!r) {
1954             return "Regex could not be compiled";
1955         }
1956     }
1957     else if (!strcmp(cmd->path, "~")) {
1958         cmd->path = ap_getword_conf(cmd->pool, &arg);
1959         r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED|USE_ICASE);
1960         if (!r) {
1961             return "Regex could not be compiled";
1962         }
1963     }
1964     else {
1965         char *newpath;
1966         /* Ensure that the pathname is canonical, but we
1967          * can't test the case/aliases without a fixed path */
1968         if (apr_filepath_merge(&newpath, "", cmd->path,
1969                                0, cmd->pool) != APR_SUCCESS)
1970                 return apr_pstrcat(cmd->pool, "<Files \"", cmd->path,
1971                                "\"> is invalid.", NULL);
1972         cmd->path = newpath;
1973     }
1974
1975     /* initialize our config and fetch it */
1976     conf = ap_set_config_vectors(cmd->server, new_file_conf, cmd->path,
1977                                  &core_module, cmd->pool);
1978
1979     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_file_conf);
1980     if (errmsg != NULL)
1981         return errmsg;
1982
1983     conf->d = cmd->path;
1984     conf->d_is_fnmatch = apr_fnmatch_test(conf->d) != 0;
1985     conf->r = r;
1986
1987     ap_add_file_conf(c, new_file_conf);
1988
1989     if (*arg != '\0') {
1990         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
1991                            "> arguments not (yet) supported.", NULL);
1992     }
1993
1994     cmd->path = old_path;
1995     cmd->override = old_overrides;
1996
1997     return NULL;
1998 }
1999 static const char *ifsection(cmd_parms *cmd, void *mconfig, const char *arg)
2000 {
2001     const char *errmsg;
2002     const char *endp = ap_strrchr_c(arg, '>');
2003     int old_overrides = cmd->override;
2004     char *old_path = cmd->path;
2005     core_dir_config *conf;
2006     const command_rec *thiscmd = cmd->cmd;
2007     core_dir_config *c = mconfig;
2008     ap_conf_vector_t *new_file_conf = ap_create_per_dir_config(cmd->pool);
2009     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_LOCATION);
2010     const char *condition;
2011     int expr_err = 0;
2012
2013     if (err != NULL) {
2014         return err;
2015     }
2016
2017     if (endp == NULL) {
2018         return unclosed_directive(cmd);
2019     }
2020
2021     arg = apr_pstrndup(cmd->pool, arg, endp - arg);
2022
2023     if (!arg[0]) {
2024         return missing_container_arg(cmd);
2025     }
2026
2027     condition = ap_getword_conf(cmd->pool, &arg);
2028     /* Only if not an .htaccess file */
2029     if (!old_path) {
2030         cmd->override = OR_ALL|ACCESS_CONF;
2031     }
2032
2033     /* initialize our config and fetch it */
2034     conf = ap_set_config_vectors(cmd->server, new_file_conf, cmd->path,
2035                                  &core_module, cmd->pool);
2036
2037     conf->condition = ap_expr_parse(cmd->pool, condition, &expr_err);
2038     if (expr_err) {
2039         return "Cannot parse condition clause";
2040     }
2041
2042     errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_file_conf);
2043     if (errmsg != NULL)
2044         return errmsg;
2045
2046     conf->d = cmd->path;
2047     conf->d_is_fnmatch = 0;
2048     conf->r = NULL;
2049
2050     ap_add_file_conf(c, new_file_conf);
2051
2052     if (*arg != '\0') {
2053         return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
2054                            "> arguments not supported.", NULL);
2055     }
2056
2057     cmd->path = old_path;
2058     cmd->override = old_overrides;
2059
2060     return NULL;
2061 }
2062
2063 static const char *start_ifmod(cmd_parms *cmd, void *mconfig, const char *arg)
2064 {
2065     const char *endp = ap_strrchr_c(arg, '>');
2066     int not = (arg[0] == '!');
2067     module *found;
2068
2069     if (endp == NULL) {
2070         return unclosed_directive(cmd);
2071     }
2072
2073     arg = apr_pstrndup(cmd->pool, arg, endp - arg);
2074
2075     if (not) {
2076         arg++;
2077     }
2078
2079     if (!arg[0]) {
2080         return missing_container_arg(cmd);
2081     }
2082
2083     found = ap_find_linked_module(arg);
2084
2085     /* search prelinked stuff */
2086     if (!found) {
2087         ap_module_symbol_t *current = ap_prelinked_module_symbols;
2088
2089         for (; current->name; ++current) {
2090             if (!strcmp(current->name, arg)) {
2091                 found = current->modp;
2092                 break;
2093             }
2094         }
2095     }
2096
2097     /* search dynamic stuff */
2098     if (!found) {
2099         APR_OPTIONAL_FN_TYPE(ap_find_loaded_module_symbol) *check_symbol =
2100             APR_RETRIEVE_OPTIONAL_FN(ap_find_loaded_module_symbol);
2101
2102         if (check_symbol) {
2103             found = check_symbol(cmd->server, arg);
2104         }
2105     }
2106
2107     if ((!not && found) || (not && !found)) {
2108         ap_directive_t *parent = NULL;
2109         ap_directive_t *current = NULL;
2110         const char *retval;
2111
2112         retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd,
2113                                       &current, &parent, "<IfModule");
2114         *(ap_directive_t **)mconfig = current;
2115         return retval;
2116     }
2117     else {
2118         *(ap_directive_t **)mconfig = NULL;
2119         return ap_soak_end_container(cmd, "<IfModule");
2120     }
2121 }
2122
2123 AP_DECLARE(int) ap_exists_config_define(const char *name)
2124 {
2125     char **defines;
2126     int i;
2127
2128     defines = (char **)ap_server_config_defines->elts;
2129     for (i = 0; i < ap_server_config_defines->nelts; i++) {
2130         if (strcmp(defines[i], name) == 0) {
2131             return 1;
2132         }
2133     }
2134
2135     return 0;
2136 }
2137
2138 static const char *start_ifdefine(cmd_parms *cmd, void *dummy, const char *arg)
2139 {
2140     const char *endp;
2141     int defined;
2142     int not = 0;
2143
2144     endp = ap_strrchr_c(arg, '>');
2145     if (endp == NULL) {
2146         return unclosed_directive(cmd);
2147     }
2148
2149     arg = apr_pstrndup(cmd->pool, arg, endp - arg);
2150
2151     if (arg[0] == '!') {
2152         not = 1;
2153         arg++;
2154     }
2155
2156     if (!arg[0]) {
2157         return missing_container_arg(cmd);
2158     }
2159
2160     defined = ap_exists_config_define(arg);
2161     if ((!not && defined) || (not && !defined)) {
2162         ap_directive_t *parent = NULL;
2163         ap_directive_t *current = NULL;
2164         const char *retval;
2165
2166         retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd,
2167                                       &current, &parent, "<IfDefine");
2168         *(ap_directive_t **)dummy = current;
2169         return retval;
2170     }
2171     else {
2172         *(ap_directive_t **)dummy = NULL;
2173         return ap_soak_end_container(cmd, "<IfDefine");
2174     }
2175 }
2176
2177 /* httpd.conf commands... beginning with the <VirtualHost> business */
2178
2179 static const char *virtualhost_section(cmd_parms *cmd, void *dummy,
2180                                        const char *arg)
2181 {
2182     server_rec *main_server = cmd->server, *s;
2183     const char *errmsg;
2184     const char *endp = ap_strrchr_c(arg, '>');
2185     apr_pool_t *p = cmd->pool;
2186
2187     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2188     if (err != NULL) {
2189         return err;
2190     }
2191
2192     if (endp == NULL) {
2193         return unclosed_directive(cmd);
2194     }
2195
2196     arg = apr_pstrndup(cmd->pool, arg, endp - arg);
2197
2198     if (!arg[0]) {
2199         return missing_container_arg(cmd);
2200     }
2201
2202     /* FIXME: There's another feature waiting to happen here -- since you
2203         can now put multiple addresses/names on a single <VirtualHost>
2204         you might want to use it to group common definitions and then
2205         define other "subhosts" with their individual differences.  But
2206         personally I'd rather just do it with a macro preprocessor. -djg */
2207     if (main_server->is_virtual) {
2208         return "<VirtualHost> doesn't nest!";
2209     }
2210
2211     errmsg = ap_init_virtual_host(p, arg, main_server, &s);
2212     if (errmsg) {
2213         return errmsg;
2214     }
2215
2216     s->next = main_server->next;
2217     main_server->next = s;
2218
2219     s->defn_name = cmd->directive->filename;
2220     s->defn_line_number = cmd->directive->line_num;
2221
2222     cmd->server = s;
2223
2224     errmsg = ap_walk_config(cmd->directive->first_child, cmd,
2225                             s->lookup_defaults);
2226
2227     cmd->server = main_server;
2228
2229     return errmsg;
2230 }
2231
2232 static const char *set_server_alias(cmd_parms *cmd, void *dummy,
2233                                     const char *arg)
2234 {
2235     if (!cmd->server->names) {
2236         return "ServerAlias only used in <VirtualHost>";
2237     }
2238
2239     while (*arg) {
2240         char **item, *name = ap_getword_conf(cmd->pool, &arg);
2241
2242         if (ap_is_matchexp(name)) {
2243             item = (char **)apr_array_push(cmd->server->wild_names);
2244         }
2245         else {
2246             item = (char **)apr_array_push(cmd->server->names);
2247         }
2248
2249         *item = name;
2250     }
2251
2252     return NULL;
2253 }
2254
2255 static const char *set_accf_map(cmd_parms *cmd, void *dummy,
2256                                 const char *iproto, const char* iaccf)
2257 {
2258     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2259     core_server_config *conf = ap_get_module_config(cmd->server->module_config,
2260                                                     &core_module);
2261     char* proto;
2262     char* accf;
2263     if (err != NULL) {
2264         return err;
2265     }
2266
2267     proto = apr_pstrdup(cmd->pool, iproto);
2268     ap_str_tolower(proto);
2269     accf = apr_pstrdup(cmd->pool, iaccf);
2270     ap_str_tolower(accf);
2271     apr_table_set(conf->accf_map, proto, accf);
2272
2273     return NULL;
2274 }
2275
2276 AP_DECLARE(const char*) ap_get_server_protocol(server_rec* s)
2277 {
2278     core_server_config *conf = ap_get_module_config(s->module_config,
2279                                                     &core_module);
2280     return conf->protocol;
2281 }
2282
2283 AP_DECLARE(void) ap_set_server_protocol(server_rec* s, const char* proto)
2284 {
2285     core_server_config *conf = ap_get_module_config(s->module_config,
2286                                                     &core_module);
2287     conf->protocol = proto;
2288 }
2289
2290 static const char *set_protocol(cmd_parms *cmd, void *dummy,
2291                                 const char *arg)
2292 {
2293     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2294     core_server_config *conf = ap_get_module_config(cmd->server->module_config,
2295                                                     &core_module);
2296     char* proto;
2297
2298     if (err != NULL) {
2299         return err;
2300     }
2301
2302     proto = apr_pstrdup(cmd->pool, arg);
2303     ap_str_tolower(proto);
2304     conf->protocol = proto;
2305
2306     return NULL;
2307 }
2308
2309 static const char *set_server_string_slot(cmd_parms *cmd, void *dummy,
2310                                           const char *arg)
2311 {
2312     /* This one's pretty generic... */
2313
2314     int offset = (int)(long)cmd->info;
2315     char *struct_ptr = (char *)cmd->server;
2316
2317     const char *err = ap_check_cmd_context(cmd,
2318                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2319     if (err != NULL) {
2320         return err;
2321     }
2322
2323     *(const char **)(struct_ptr + offset) = arg;
2324     return NULL;
2325 }
2326
2327 /*
2328  * The ServerName directive takes one argument with format
2329  * [scheme://]fully-qualified-domain-name[:port], for instance
2330  * ServerName www.example.com
2331  * ServerName www.example.com:80
2332  * ServerName https://www.example.com:443
2333  */
2334
2335 static const char *server_hostname_port(cmd_parms *cmd, void *dummy, const char *arg)
2336 {
2337     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2338     const char *portstr, *part;
2339     char *scheme;
2340     int port;
2341
2342     if (err != NULL) {
2343         return err;
2344     }
2345
2346     part = ap_strstr_c(arg, "://");
2347
2348     if (part) {
2349       scheme = apr_pstrndup(cmd->pool, arg, part - arg);
2350       ap_str_tolower(scheme);
2351       cmd->server->server_scheme = (const char *)scheme;
2352       part += 3;
2353     } else {
2354       part = arg;
2355     }
2356
2357     portstr = ap_strchr_c(part, ':');
2358     if (portstr) {
2359         cmd->server->server_hostname = apr_pstrndup(cmd->pool, part,
2360                                                     portstr - part);
2361         portstr++;
2362         port = atoi(portstr);
2363         if (port <= 0 || port >= 65536) { /* 65536 == 1<<16 */
2364             return apr_pstrcat(cmd->temp_pool, "The port number \"", arg,
2365                           "\" is outside the appropriate range "
2366                           "(i.e., 1..65535).", NULL);
2367         }
2368     }
2369     else {
2370         cmd->server->server_hostname = apr_pstrdup(cmd->pool, part);
2371         port = 0;
2372     }
2373
2374     cmd->server->port = port;
2375     return NULL;
2376 }
2377
2378 static const char *set_signature_flag(cmd_parms *cmd, void *d_,
2379                                       const char *arg)
2380 {
2381     core_dir_config *d = d_;
2382     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2383
2384     if (err != NULL) {
2385         return err;
2386     }
2387
2388     if (strcasecmp(arg, "On") == 0) {
2389         d->server_signature = srv_sig_on;
2390     }
2391     else if (strcasecmp(arg, "Off") == 0) {
2392         d->server_signature = srv_sig_off;
2393     }
2394     else if (strcasecmp(arg, "EMail") == 0) {
2395         d->server_signature = srv_sig_withmail;
2396     }
2397     else {
2398         return "ServerSignature: use one of: off | on | email";
2399     }
2400
2401     return NULL;
2402 }
2403
2404 static const char *set_server_root(cmd_parms *cmd, void *dummy,
2405                                    const char *arg)
2406 {
2407     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2408
2409     if (err != NULL) {
2410         return err;
2411     }
2412
2413     if ((apr_filepath_merge((char**)&ap_server_root, NULL, arg,
2414                             APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS)
2415         || !ap_is_directory(cmd->pool, ap_server_root)) {
2416         return "ServerRoot must be a valid directory";
2417     }
2418
2419     return NULL;
2420 }
2421
2422 static const char *set_timeout(cmd_parms *cmd, void *dummy, const char *arg)
2423 {
2424     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2425
2426     if (err != NULL) {
2427         return err;
2428     }
2429
2430     cmd->server->timeout = apr_time_from_sec(atoi(arg));
2431     return NULL;
2432 }
2433
2434 static const char *set_allow2f(cmd_parms *cmd, void *d_, int arg)
2435 {
2436     core_dir_config *d = d_;
2437     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2438
2439     if (err != NULL) {
2440         return err;
2441     }
2442
2443     d->allow_encoded_slashes = arg != 0;
2444     return NULL;
2445 }
2446
2447 static const char *set_hostname_lookups(cmd_parms *cmd, void *d_,
2448                                         const char *arg)
2449 {
2450     core_dir_config *d = d_;
2451     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2452
2453     if (err != NULL) {
2454         return err;
2455     }
2456
2457     if (!strcasecmp(arg, "on")) {
2458         d->hostname_lookups = HOSTNAME_LOOKUP_ON;
2459     }
2460     else if (!strcasecmp(arg, "off")) {
2461         d->hostname_lookups = HOSTNAME_LOOKUP_OFF;
2462     }
2463     else if (!strcasecmp(arg, "double")) {
2464         d->hostname_lookups = HOSTNAME_LOOKUP_DOUBLE;
2465     }
2466     else {
2467         return "parameter must be 'on', 'off', or 'double'";
2468     }
2469
2470     return NULL;
2471 }
2472
2473 static const char *set_serverpath(cmd_parms *cmd, void *dummy,
2474                                   const char *arg)
2475 {
2476     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2477
2478     if (err != NULL) {
2479         return err;
2480     }
2481
2482     cmd->server->path = arg;
2483     cmd->server->pathlen = (int)strlen(arg);
2484     return NULL;
2485 }
2486
2487 static const char *set_content_md5(cmd_parms *cmd, void *d_, int arg)
2488 {
2489     core_dir_config *d = d_;
2490     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2491
2492     if (err != NULL) {
2493         return err;
2494     }
2495
2496     d->content_md5 = arg != 0;
2497     return NULL;
2498 }
2499
2500 static const char *set_accept_path_info(cmd_parms *cmd, void *d_, const char *arg)
2501 {
2502     core_dir_config *d = d_;
2503
2504     if (strcasecmp(arg, "on") == 0) {
2505         d->accept_path_info = AP_REQ_ACCEPT_PATH_INFO;
2506     }
2507     else if (strcasecmp(arg, "off") == 0) {
2508         d->accept_path_info = AP_REQ_REJECT_PATH_INFO;
2509     }
2510     else if (strcasecmp(arg, "default") == 0) {
2511         d->accept_path_info = AP_REQ_DEFAULT_PATH_INFO;
2512     }
2513     else {
2514         return "AcceptPathInfo must be set to on, off or default";
2515     }
2516
2517     return NULL;
2518 }
2519
2520 static const char *set_use_canonical_name(cmd_parms *cmd, void *d_,
2521                                           const char *arg)
2522 {
2523     core_dir_config *d = d_;
2524     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2525
2526     if (err != NULL) {
2527         return err;
2528     }
2529
2530     if (strcasecmp(arg, "on") == 0) {
2531         d->use_canonical_name = USE_CANONICAL_NAME_ON;
2532     }
2533     else if (strcasecmp(arg, "off") == 0) {
2534         d->use_canonical_name = USE_CANONICAL_NAME_OFF;
2535     }
2536     else if (strcasecmp(arg, "dns") == 0) {
2537         d->use_canonical_name = USE_CANONICAL_NAME_DNS;
2538     }
2539     else {
2540         return "parameter must be 'on', 'off', or 'dns'";
2541     }
2542
2543     return NULL;
2544 }
2545
2546 static const char *set_use_canonical_phys_port(cmd_parms *cmd, void *d_,
2547                                           const char *arg)
2548 {
2549     core_dir_config *d = d_;
2550     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2551
2552     if (err != NULL) {
2553         return err;
2554     }
2555
2556     if (strcasecmp(arg, "on") == 0) {
2557         d->use_canonical_phys_port = USE_CANONICAL_PHYS_PORT_ON;
2558     }
2559     else if (strcasecmp(arg, "off") == 0) {
2560         d->use_canonical_phys_port = USE_CANONICAL_PHYS_PORT_OFF;
2561     }
2562     else {
2563         return "parameter must be 'on' or 'off'";
2564     }
2565
2566     return NULL;
2567 }
2568
2569
2570 static const char *include_config (cmd_parms *cmd, void *dummy,
2571                                    const char *name)
2572 {
2573     ap_directive_t *conftree = NULL;
2574     const char* conffile, *error;
2575     unsigned *recursion;
2576     void *data;
2577
2578     apr_pool_userdata_get(&data, "ap_include_sentinel", cmd->pool);
2579     if (data) {
2580         recursion = data;
2581     }
2582     else {
2583         data = recursion = apr_palloc(cmd->pool, sizeof(*recursion));
2584         *recursion = 0;
2585         apr_pool_userdata_setn(data, "ap_include_sentinel", NULL, cmd->pool);
2586     }
2587
2588     if (++*recursion > AP_MAX_INCLUDE_DEPTH) {
2589         *recursion = 0;
2590         return apr_psprintf(cmd->pool, "Exceeded maximum include depth of %u. "
2591                             "You have probably a recursion somewhere.",
2592                             AP_MAX_INCLUDE_DEPTH);
2593     }
2594
2595     conffile = ap_server_root_relative(cmd->pool, name);
2596     if (!conffile) {
2597         *recursion = 0;
2598         return apr_pstrcat(cmd->pool, "Invalid Include path ",
2599                            name, NULL);
2600     }
2601
2602     error = ap_process_resource_config(cmd->server, conffile,
2603                                        &conftree, cmd->pool, cmd->temp_pool);
2604     if (error) {
2605         *recursion = 0;
2606         return error;
2607     }
2608
2609     *(ap_directive_t **)dummy = conftree;
2610
2611     /* recursion level done */
2612     if (*recursion) {
2613         --*recursion;
2614     }
2615
2616     return NULL;
2617 }
2618
2619 static const char *set_loglevel(cmd_parms *cmd, void *dummy, const char *arg)
2620 {
2621     char *str;
2622
2623     const char *err = ap_check_cmd_context(cmd,
2624                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2625     if (err != NULL) {
2626         return err;
2627     }
2628
2629     if ((str = ap_getword_conf(cmd->pool, &arg))) {
2630         if (!strcasecmp(str, "emerg")) {
2631             cmd->server->loglevel = APLOG_EMERG;
2632         }
2633         else if (!strcasecmp(str, "alert")) {
2634             cmd->server->loglevel = APLOG_ALERT;
2635         }
2636         else if (!strcasecmp(str, "crit")) {
2637             cmd->server->loglevel = APLOG_CRIT;
2638         }
2639         else if (!strcasecmp(str, "error")) {
2640             cmd->server->loglevel = APLOG_ERR;
2641         }
2642         else if (!strcasecmp(str, "warn")) {
2643             cmd->server->loglevel = APLOG_WARNING;
2644         }
2645         else if (!strcasecmp(str, "notice")) {
2646             cmd->server->loglevel = APLOG_NOTICE;
2647         }
2648         else if (!strcasecmp(str, "info")) {
2649             cmd->server->loglevel = APLOG_INFO;
2650         }
2651         else if (!strcasecmp(str, "debug")) {
2652             cmd->server->loglevel = APLOG_DEBUG;
2653         }
2654         else {
2655             return "LogLevel requires level keyword: one of "
2656                    "emerg/alert/crit/error/warn/notice/info/debug";
2657         }
2658     }
2659     else {
2660         return "LogLevel requires level keyword";
2661     }
2662
2663     return NULL;
2664 }
2665
2666 AP_DECLARE(const char *) ap_psignature(const char *prefix, request_rec *r)
2667 {
2668     char sport[20];
2669     core_dir_config *conf;
2670
2671     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
2672                                                    &core_module);
2673     if ((conf->server_signature == srv_sig_off)
2674             || (conf->server_signature == srv_sig_unset)) {
2675         return "";
2676     }
2677
2678     apr_snprintf(sport, sizeof sport, "%u", (unsigned) ap_get_server_port(r));
2679
2680     if (conf->server_signature == srv_sig_withmail) {
2681         return apr_pstrcat(r->pool, prefix, "<address>",
2682                            ap_get_server_banner(),
2683                            " Server at <a href=\"",
2684                            ap_is_url(r->server->server_admin) ? "" : "mailto:",
2685                            ap_escape_html(r->pool, r->server->server_admin),
2686                            "\">",
2687                            ap_escape_html(r->pool, ap_get_server_name(r)),
2688                            "</a> Port ", sport,
2689                            "</address>\n", NULL);
2690     }
2691
2692     return apr_pstrcat(r->pool, prefix, "<address>", ap_get_server_banner(),
2693                        " Server at ",
2694                        ap_escape_html(r->pool, ap_get_server_name(r)),
2695                        " Port ", sport,
2696                        "</address>\n", NULL);
2697 }
2698
2699 /*
2700  * Handle a request to include the server's OS platform in the Server
2701  * response header field (the ServerTokens directive).  Unfortunately
2702  * this requires a new global in order to communicate the setting back to
2703  * http_main so it can insert the information in the right place in the
2704  * string.
2705  */
2706
2707 static char *server_banner = NULL;
2708 static int banner_locked = 0;
2709 static char *server_description = NULL;
2710
2711 enum server_token_type {
2712     SrvTk_MAJOR,        /* eg: Apache/2 */
2713     SrvTk_MINOR,        /* eg. Apache/2.0 */
2714     SrvTk_MINIMAL,      /* eg: Apache/2.0.41 */
2715     SrvTk_OS,           /* eg: Apache/2.0.41 (UNIX) */
2716     SrvTk_FULL,         /* eg: Apache/2.0.41 (UNIX) PHP/4.2.2 FooBar/1.2b */
2717     SrvTk_PRODUCT_ONLY  /* eg: Apache */
2718 };
2719 static enum server_token_type ap_server_tokens = SrvTk_FULL;
2720
2721 static apr_status_t reset_banner(void *dummy)
2722 {
2723     banner_locked = 0;
2724     ap_server_tokens = SrvTk_FULL;
2725     server_banner = NULL;
2726     server_description = NULL;
2727     return APR_SUCCESS;
2728 }
2729
2730 AP_DECLARE(void) ap_get_server_revision(ap_version_t *version)
2731 {
2732     version->major = AP_SERVER_MAJORVERSION_NUMBER;
2733     version->minor = AP_SERVER_MINORVERSION_NUMBER;
2734     version->patch = AP_SERVER_PATCHLEVEL_NUMBER;
2735     version->add_string = AP_SERVER_ADD_STRING;
2736 }
2737
2738 AP_DECLARE(const char *) ap_get_server_description(void)
2739 {
2740     return server_description ? server_description :
2741         AP_SERVER_BASEVERSION " (" PLATFORM ")";
2742 }
2743
2744 AP_DECLARE(const char *) ap_get_server_banner(void)
2745 {
2746     return server_banner ? server_banner : AP_SERVER_BASEVERSION;
2747 }
2748
2749 AP_DECLARE(void) ap_add_version_component(apr_pool_t *pconf, const char *component)
2750 {
2751     if (! banner_locked) {
2752         /*
2753          * If the version string is null, register our cleanup to reset the
2754          * pointer on pool destruction. We also know that, if NULL,
2755          * we are adding the original SERVER_BASEVERSION string.
2756          */
2757         if (server_banner == NULL) {
2758             apr_pool_cleanup_register(pconf, NULL, reset_banner,
2759                                       apr_pool_cleanup_null);
2760             server_banner = apr_pstrdup(pconf, component);
2761         }
2762         else {
2763             /*
2764              * Tack the given component identifier to the end of
2765              * the existing string.
2766              */
2767             server_banner = apr_pstrcat(pconf, server_banner, " ",
2768                                         component, NULL);
2769         }
2770     }
2771     server_description = apr_pstrcat(pconf, server_description, " ",
2772                                      component, NULL);
2773 }
2774
2775 /*
2776  * This routine adds the real server base identity to the banner string,
2777  * and then locks out changes until the next reconfig.
2778  */
2779 static void set_banner(apr_pool_t *pconf)
2780 {
2781     if (ap_server_tokens == SrvTk_PRODUCT_ONLY) {
2782         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT);
2783     }
2784     else if (ap_server_tokens == SrvTk_MINIMAL) {
2785         ap_add_version_component(pconf, AP_SERVER_BASEVERSION);
2786     }
2787     else if (ap_server_tokens == SrvTk_MINOR) {
2788         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MINORREVISION);
2789     }
2790     else if (ap_server_tokens == SrvTk_MAJOR) {
2791         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MAJORVERSION);
2792     }
2793     else {
2794         ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ")");
2795     }
2796
2797     /*
2798      * Lock the server_banner string if we're not displaying
2799      * the full set of tokens
2800      */
2801     if (ap_server_tokens != SrvTk_FULL) {
2802         banner_locked++;
2803     }
2804     server_description = AP_SERVER_BASEVERSION " (" PLATFORM ")";
2805 }
2806
2807 static const char *set_serv_tokens(cmd_parms *cmd, void *dummy,
2808                                    const char *arg)
2809 {
2810     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2811
2812     if (err != NULL) {
2813         return err;
2814     }
2815
2816     if (!strcasecmp(arg, "OS")) {
2817         ap_server_tokens = SrvTk_OS;
2818     }
2819     else if (!strcasecmp(arg, "Min") || !strcasecmp(arg, "Minimal")) {
2820         ap_server_tokens = SrvTk_MINIMAL;
2821     }
2822     else if (!strcasecmp(arg, "Major")) {
2823         ap_server_tokens = SrvTk_MAJOR;
2824     }
2825     else if (!strcasecmp(arg, "Minor") ) {
2826         ap_server_tokens = SrvTk_MINOR;
2827     }
2828     else if (!strcasecmp(arg, "Prod") || !strcasecmp(arg, "ProductOnly")) {
2829         ap_server_tokens = SrvTk_PRODUCT_ONLY;
2830     }
2831     else {
2832         ap_server_tokens = SrvTk_FULL;
2833     }
2834
2835     return NULL;
2836 }
2837
2838 static const char *set_limit_req_line(cmd_parms *cmd, void *dummy,
2839                                       const char *arg)
2840 {
2841     const char *err = ap_check_cmd_context(cmd,
2842                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2843     int lim;
2844
2845     if (err != NULL) {
2846         return err;
2847     }
2848
2849     lim = atoi(arg);
2850     if (lim < 0) {
2851         return apr_pstrcat(cmd->temp_pool, "LimitRequestLine \"", arg,
2852                            "\" must be a non-negative integer", NULL);
2853     }
2854
2855     cmd->server->limit_req_line = lim;
2856     return NULL;
2857 }
2858
2859 static const char *set_limit_req_fieldsize(cmd_parms *cmd, void *dummy,
2860                                            const char *arg)
2861 {
2862     const char *err = ap_check_cmd_context(cmd,
2863                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2864     int lim;
2865
2866     if (err != NULL) {
2867         return err;
2868     }
2869
2870     lim = atoi(arg);
2871     if (lim < 0) {
2872         return apr_pstrcat(cmd->temp_pool, "LimitRequestFieldsize \"", arg,
2873                           "\" must be a non-negative integer",
2874                           NULL);
2875     }
2876
2877     cmd->server->limit_req_fieldsize = lim;
2878     return NULL;
2879 }
2880
2881 static const char *set_limit_req_fields(cmd_parms *cmd, void *dummy,
2882                                         const char *arg)
2883 {
2884     const char *err = ap_check_cmd_context(cmd,
2885                                            NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2886     int lim;
2887
2888     if (err != NULL) {
2889         return err;
2890     }
2891
2892     lim = atoi(arg);
2893     if (lim < 0) {
2894         return apr_pstrcat(cmd->temp_pool, "LimitRequestFields \"", arg,
2895                            "\" must be a non-negative integer (0 = no limit)",
2896                            NULL);
2897     }
2898
2899     cmd->server->limit_req_fields = lim;
2900     return NULL;
2901 }
2902
2903 static const char *set_limit_req_body(cmd_parms *cmd, void *conf_,
2904                                       const char *arg)
2905 {
2906     core_dir_config *conf = conf_;
2907     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2908     char *errp;
2909
2910     if (err != NULL) {
2911         return err;
2912     }
2913
2914     if (APR_SUCCESS != apr_strtoff(&conf->limit_req_body, arg, &errp, 10)) {
2915         return "LimitRequestBody argument is not parsable.";
2916     }
2917     if (*errp || conf->limit_req_body < 0) {
2918         return "LimitRequestBody requires a non-negative integer.";
2919     }
2920
2921     return NULL;
2922 }
2923
2924 static const char *set_limit_xml_req_body(cmd_parms *cmd, void *conf_,
2925                                           const char *arg)
2926 {
2927     core_dir_config *conf = conf_;
2928     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
2929
2930     if (err != NULL) {
2931         return err;
2932     }
2933
2934     conf->limit_xml_body = atol(arg);
2935     if (conf->limit_xml_body < 0)
2936         return "LimitXMLRequestBody requires a non-negative integer.";
2937
2938     return NULL;
2939 }
2940
2941 AP_DECLARE(size_t) ap_get_limit_xml_body(const request_rec *r)
2942 {
2943     core_dir_config *conf;
2944
2945     conf = ap_get_module_config(r->per_dir_config, &core_module);
2946     if (conf->limit_xml_body == AP_LIMIT_UNSET)
2947         return AP_DEFAULT_LIMIT_XML_BODY;
2948
2949     return (size_t)conf->limit_xml_body;
2950 }
2951
2952 #if !defined (RLIMIT_CPU) || !(defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)) || !defined (RLIMIT_NPROC)
2953 static const char *no_set_limit(cmd_parms *cmd, void *conf_,
2954                                 const char *arg, const char *arg2)
2955 {
2956     ap_log_error(APLOG_MARK, APLOG_ERR, 0, cmd->server,
2957                 "%s not supported on this platform", cmd->cmd->name);
2958
2959     return NULL;
2960 }
2961 #endif
2962
2963 #ifdef RLIMIT_CPU
2964 static const char *set_limit_cpu(cmd_parms *cmd, void *conf_,
2965                                  const char *arg, const char *arg2)
2966 {
2967     core_dir_config *conf = conf_;
2968
2969     unixd_set_rlimit(cmd, &conf->limit_cpu, arg, arg2, RLIMIT_CPU);
2970     return NULL;
2971 }
2972 #endif
2973
2974 #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)
2975 static const char *set_limit_mem(cmd_parms *cmd, void *conf_,
2976                                  const char *arg, const char * arg2)
2977 {
2978     core_dir_config *conf = conf_;
2979
2980 #if defined(RLIMIT_AS)
2981     unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2 ,RLIMIT_AS);
2982 #elif defined(RLIMIT_DATA)
2983     unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_DATA);
2984 #elif defined(RLIMIT_VMEM)
2985     unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_VMEM);
2986 #endif
2987
2988     return NULL;
2989 }
2990 #endif
2991
2992 #ifdef RLIMIT_NPROC
2993 static const char *set_limit_nproc(cmd_parms *cmd, void *conf_,
2994                                    const char *arg, const char * arg2)
2995 {
2996     core_dir_config *conf = conf_;
2997
2998     unixd_set_rlimit(cmd, &conf->limit_nproc, arg, arg2, RLIMIT_NPROC);
2999     return NULL;
3000 }
3001 #endif
3002
3003 static const char *set_recursion_limit(cmd_parms *cmd, void *dummy,
3004                                        const char *arg1, const char *arg2)
3005 {
3006     core_server_config *conf = ap_get_module_config(cmd->server->module_config,
3007                                                     &core_module);
3008     int limit = atoi(arg1);
3009
3010     if (limit <= 0) {
3011         return "The recursion limit must be greater than zero.";
3012     }
3013     if (limit < 4) {
3014         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
3015                      "Limiting internal redirects to very low numbers may "
3016                      "cause normal requests to fail.");
3017     }
3018
3019     conf->redirect_limit = limit;
3020
3021     if (arg2) {
3022         limit = atoi(arg2);
3023
3024         if (limit <= 0) {
3025             return "The recursion limit must be greater than zero.";
3026         }
3027         if (limit < 4) {
3028             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
3029                          "Limiting the subrequest depth to a very low level may"
3030                          " cause normal requests to fail.");
3031         }
3032     }
3033
3034     conf->subreq_limit = limit;
3035
3036     return NULL;
3037 }
3038
3039 static void log_backtrace(const request_rec *r)
3040 {
3041     const request_rec *top = r;
3042
3043     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
3044                   "r->uri = %s", r->uri ? r->uri : "(unexpectedly NULL)");
3045
3046     while (top && (top->prev || top->main)) {
3047         if (top->prev) {
3048             top = top->prev;
3049             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
3050                           "redirected from r->uri = %s",
3051                           top->uri ? top->uri : "(unexpectedly NULL)");
3052         }
3053
3054         if (!top->prev && top->main) {
3055             top = top->main;
3056             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
3057                           "subrequested from r->uri = %s",
3058                           top->uri ? top->uri : "(unexpectedly NULL)");
3059         }
3060     }
3061 }
3062
3063 /*
3064  * check whether redirect limit is reached
3065  */
3066 AP_DECLARE(int) ap_is_recursion_limit_exceeded(const request_rec *r)
3067 {
3068     core_server_config *conf = ap_get_module_config(r->server->module_config,
3069                                                     &core_module);
3070     const request_rec *top = r;
3071     int redirects = 0, subreqs = 0;
3072     int rlimit = conf->redirect_limit
3073                  ? conf->redirect_limit
3074                  : AP_DEFAULT_MAX_INTERNAL_REDIRECTS;
3075     int slimit = conf->subreq_limit
3076                  ? conf->subreq_limit
3077                  : AP_DEFAULT_MAX_SUBREQ_DEPTH;
3078
3079
3080     while (top->prev || top->main) {
3081         if (top->prev) {
3082             if (++redirects >= rlimit) {
3083                 /* uuh, too much. */
3084                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3085                               "Request exceeded the limit of %d internal "
3086                               "redirects due to probable configuration error. "
3087                               "Use 'LimitInternalRecursion' to increase the "
3088                               "limit if necessary. Use 'LogLevel debug' to get "
3089                               "a backtrace.", rlimit);
3090
3091                 /* post backtrace */
3092                 log_backtrace(r);
3093
3094                 /* return failure */
3095                 return 1;
3096             }
3097
3098             top = top->prev;
3099         }
3100
3101         if (!top->prev && top->main) {
3102             if (++subreqs >= slimit) {
3103                 /* uuh, too much. */
3104                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3105                               "Request exceeded the limit of %d subrequest "
3106                               "nesting levels due to probable configuration "
3107                               "error. Use 'LimitInternalRecursion' to increase "
3108                               "the limit if necessary. Use 'LogLevel debug' to "
3109                               "get a backtrace.", slimit);
3110
3111                 /* post backtrace */
3112                 log_backtrace(r);
3113
3114                 /* return failure */
3115                 return 1;
3116             }
3117
3118             top = top->main;
3119         }
3120     }
3121
3122     /* recursion state: ok */
3123     return 0;
3124 }
3125
3126 static const char *add_ct_output_filters(cmd_parms *cmd, void *conf_,
3127                                          const char *arg, const char *arg2)
3128 {
3129     core_dir_config *conf = conf_;
3130     ap_filter_rec_t *old, *new = NULL;
3131     const char *filter_name;
3132
3133     if (!conf->ct_output_filters) {
3134         conf->ct_output_filters = apr_hash_make(cmd->pool);
3135         old = NULL;
3136     }
3137     else {
3138         old = (ap_filter_rec_t*) apr_hash_get(conf->ct_output_filters, arg2,
3139                                               APR_HASH_KEY_STRING);
3140         /* find last entry */
3141         if (old) {
3142             while (old->next) {
3143                 old = old->next;
3144             }
3145         }
3146     }
3147
3148     while (*arg &&
3149            (filter_name = ap_getword(cmd->pool, &arg, ';')) &&
3150            strcmp(filter_name, "")) {
3151         new = apr_pcalloc(cmd->pool, sizeof(ap_filter_rec_t));
3152         new->name = filter_name;
3153
3154         /* We found something, so let's append it.  */
3155         if (old) {
3156             old->next = new;
3157         }
3158         else {
3159             apr_hash_set(conf->ct_output_filters, arg2,
3160                          APR_HASH_KEY_STRING, new);
3161         }
3162         old = new;
3163     }
3164
3165     if (!new) {
3166         return "invalid filter name";
3167     }
3168
3169     return NULL;
3170 }
3171 /*
3172  * Insert filters requested by the AddOutputFilterByType
3173  * configuration directive. We cannot add filters based
3174  * on content-type until after the handler has started
3175  * to run. Only then do we reliably know the content-type.
3176  */
3177 void ap_add_output_filters_by_type(request_rec *r)
3178 {
3179     core_dir_config *conf;
3180     const char *ctype;
3181
3182     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
3183                                                    &core_module);
3184
3185     /* We can't do anything with no content-type or if we don't have a
3186      * filter configured.
3187      */
3188     if (!r->content_type || !conf->ct_output_filters) {
3189         return;
3190     }
3191
3192     /* remove c-t decoration */
3193     ctype = ap_field_noparam(r->pool, r->content_type);
3194     if (ctype) {
3195         ap_filter_rec_t *ct_filter;
3196         ct_filter = apr_hash_get(conf->ct_output_filters, ctype,
3197                                  APR_HASH_KEY_STRING);
3198         while (ct_filter) {
3199             ap_add_output_filter(ct_filter->name, NULL, r, r->connection);
3200             ct_filter = ct_filter->next;
3201         }
3202     }
3203
3204     return;
3205 }
3206
3207 static const char *set_trace_enable(cmd_parms *cmd, void *dummy,
3208                                     const char *arg1)
3209 {
3210     core_server_config *conf = ap_get_module_config(cmd->server->module_config,
3211                                                     &core_module);
3212
3213     if (strcasecmp(arg1, "on") == 0) {
3214         conf->trace_enable = AP_TRACE_ENABLE;
3215     }
3216     else if (strcasecmp(arg1, "off") == 0) {
3217         conf->trace_enable = AP_TRACE_DISABLE;
3218     }
3219     else if (strcasecmp(arg1, "extended") == 0) {
3220         conf->trace_enable = AP_TRACE_EXTENDED;
3221     }
3222     else {
3223         return "TraceEnable must be one of 'on', 'off', or 'extended'";
3224     }
3225
3226     return NULL;
3227 }
3228
3229 /* Note --- ErrorDocument will now work from .htaccess files.
3230  * The AllowOverride of Fileinfo allows webmasters to turn it off
3231  */
3232
3233 static const command_rec core_cmds[] = {
3234
3235 /* Old access config file commands */
3236
3237 AP_INIT_RAW_ARGS("<Directory", dirsection, NULL, RSRC_CONF,
3238   "Container for directives affecting resources located in the specified "
3239   "directories"),
3240 AP_INIT_RAW_ARGS("<Location", urlsection, NULL, RSRC_CONF,
3241   "Container for directives affecting resources accessed through the "
3242   "specified URL paths"),
3243 AP_INIT_RAW_ARGS("<VirtualHost", virtualhost_section, NULL, RSRC_CONF,
3244   "Container to map directives to a particular virtual host, takes one or "
3245   "more host addresses"),
3246 AP_INIT_RAW_ARGS("<Files", filesection, NULL, OR_ALL,
3247   "Container for directives affecting files matching specified patterns"),
3248 AP_INIT_RAW_ARGS("<Limit", ap_limit_section, NULL, OR_ALL,
3249   "Container for authentication directives when accessed using specified HTTP "
3250   "methods"),
3251 AP_INIT_RAW_ARGS("<LimitExcept", ap_limit_section, (void*)1, OR_ALL,
3252   "Container for authentication directives to be applied when any HTTP "
3253   "method other than those specified is used to access the resource"),
3254 AP_INIT_TAKE1("<IfModule", start_ifmod, NULL, EXEC_ON_READ | OR_ALL,
3255   "Container for directives based on existance of specified modules"),
3256 AP_INIT_TAKE1("<IfDefine", start_ifdefine, NULL, EXEC_ON_READ | OR_ALL,
3257   "Container for directives based on existance of command line defines"),
3258 AP_INIT_RAW_ARGS("<DirectoryMatch", dirsection, (void*)1, RSRC_CONF,
3259   "Container for directives affecting resources located in the "
3260   "specified directories"),
3261 AP_INIT_RAW_ARGS("<LocationMatch", urlsection, (void*)1, RSRC_CONF,
3262   "Container for directives affecting resources accessed through the "
3263   "specified URL paths"),
3264 AP_INIT_RAW_ARGS("<FilesMatch", filesection, (void*)1, OR_ALL,
3265   "Container for directives affecting files matching specified patterns"),
3266 #ifdef GPROF
3267 AP_INIT_TAKE1("GprofDir", set_gprof_dir, NULL, RSRC_CONF,
3268   "Directory to plop gmon.out files"),
3269 #endif
3270 AP_INIT_TAKE1("AddDefaultCharset", set_add_default_charset, NULL, OR_FILEINFO,
3271   "The name of the default charset to add to any Content-Type without one or 'Off' to disable"),
3272 AP_INIT_TAKE1("AcceptPathInfo", set_accept_path_info, NULL, OR_FILEINFO,
3273   "Set to on or off for PATH_INFO to be accepted by handlers, or default for the per-handler preference"),
3274 AP_INIT_TAKE1("Define", set_define, NULL, RSRC_CONF,
3275               "Define the existance of a variable.  Same as passing -D to the command line."),
3276 AP_INIT_RAW_ARGS("<If", ifsection, NULL, OR_ALL,
3277   "Container for directives to be conditionally applied"),
3278
3279 /* Old resource config file commands */
3280
3281 AP_INIT_RAW_ARGS("AccessFileName", set_access_name, NULL, RSRC_CONF,
3282   "Name(s) of per-directory config files (default: .htaccess)"),
3283 AP_INIT_TAKE1("DocumentRoot", set_document_root, NULL, RSRC_CONF,
3284   "Root directory of the document tree"),
3285 AP_INIT_TAKE2("ErrorDocument", set_error_document, NULL, OR_FILEINFO,
3286   "Change responses for HTTP errors"),
3287 AP_INIT_RAW_ARGS("AllowOverride", set_override, NULL, ACCESS_CONF,
3288   "Controls what groups of directives can be configured by per-directory "
3289   "config files"),
3290 AP_INIT_RAW_ARGS("Options", set_options, NULL, OR_OPTIONS,
3291   "Set a number of attributes for a given directory"),
3292 AP_INIT_TAKE1("DefaultType", ap_set_string_slot,
3293   (void*)APR_OFFSETOF(core_dir_config, ap_default_type),
3294   OR_FILEINFO, "the default MIME type for untypable files"),
3295 AP_INIT_RAW_ARGS("FileETag", set_etag_bits, NULL, OR_FILEINFO,
3296   "Specify components used to construct a file's ETag"),
3297 AP_INIT_TAKE1("EnableMMAP", set_enable_mmap, NULL, OR_FILEINFO,
3298   "Controls whether memory-mapping may be used to read files"),
3299 AP_INIT_TAKE1("EnableSendfile", set_enable_sendfile, NULL, OR_FILEINFO,
3300   "Controls whether sendfile may be used to transmit files"),
3301
3302 /* Old server config file commands */
3303
3304 AP_INIT_TAKE1("Protocol", set_protocol, NULL, RSRC_CONF,
3305   "Set the Protocol for httpd to use."),
3306 AP_INIT_TAKE2("AcceptFilter", set_accf_map, NULL, RSRC_CONF,
3307   "Set the Accept Filter to use for a protocol"),
3308 AP_INIT_TAKE1("Port", ap_set_deprecated, NULL, RSRC_CONF,
3309   "Port was replaced with Listen in Apache 2.0"),
3310 AP_INIT_TAKE1("HostnameLookups", set_hostname_lookups, NULL,
3311   ACCESS_CONF|RSRC_CONF,
3312   "\"on\" to enable, \"off\" to disable reverse DNS lookups, or \"double\" to "
3313   "enable double-reverse DNS lookups"),
3314 AP_INIT_TAKE1("ServerAdmin", set_server_string_slot,
3315   (void *)APR_OFFSETOF(server_rec, server_admin), RSRC_CONF,
3316   "The email address of the server administrator"),
3317 AP_INIT_TAKE1("ServerName", server_hostname_port, NULL, RSRC_CONF,
3318   "The hostname and port of the server"),
3319 AP_INIT_TAKE1("ServerSignature", set_signature_flag, NULL, OR_ALL,
3320   "En-/disable server signature (on|off|email)"),
3321 AP_INIT_TAKE1("ServerRoot", set_server_root, NULL, RSRC_CONF | EXEC_ON_READ,
3322   "Common directory of server-related files (logs, confs, etc.)"),
3323 AP_INIT_TAKE1("ErrorLog", set_server_string_slot,
3324   (void *)APR_OFFSETOF(server_rec, error_fname), RSRC_CONF,
3325   "The filename of the error log"),
3326 AP_INIT_RAW_ARGS("ServerAlias", set_server_alias, NULL, RSRC_CONF,
3327   "A name or names alternately used to access the server"),
3328 AP_INIT_TAKE1("ServerPath", set_serverpath, NULL, RSRC_CONF,
3329   "The pathname the server can be reached at"),
3330 AP_INIT_TAKE1("Timeout", set_timeout, NULL, RSRC_CONF,
3331   "Timeout duration (sec)"),
3332 AP_INIT_FLAG("ContentDigest", set_content_md5, NULL, OR_OPTIONS,
3333   "whether or not to send a Content-MD5 header with each request"),
3334 AP_INIT_TAKE1("UseCanonicalName", set_use_canonical_name, NULL,
3335   RSRC_CONF|ACCESS_CONF,
3336   "How to work out the ServerName : Port when constructing URLs"),
3337 AP_INIT_TAKE1("UseCanonicalPhysicalPort", set_use_canonical_phys_port, NULL,
3338   RSRC_CONF|ACCESS_CONF,
3339   "Whether to use the physical Port when constructing URLs"),
3340 /* TODO: RlimitFoo should all be part of mod_cgi, not in the core */
3341 /* TODO: ListenBacklog in MPM */
3342 AP_INIT_TAKE1("Include", include_config, NULL,
3343   (RSRC_CONF | ACCESS_CONF | EXEC_ON_READ),
3344   "Name of the config file to be included"),
3345 AP_INIT_TAKE1("LogLevel", set_loglevel, NULL, RSRC_CONF,
3346   "Level of verbosity in error logging"),
3347 AP_INIT_TAKE1("NameVirtualHost", ap_set_name_virtual_host, NULL, RSRC_CONF,
3348   "A numeric IP address:port, or the name of a host"),
3349 AP_INIT_TAKE1("ServerTokens", set_serv_tokens, NULL, RSRC_CONF,
3350   "Determine tokens displayed in the Server: header - Min(imal), OS or Full"),
3351 AP_INIT_TAKE1("LimitRequestLine", set_limit_req_line, NULL, RSRC_CONF,
3352   "Limit on maximum size of an HTTP request line"),
3353 AP_INIT_TAKE1("LimitRequestFieldsize", set_limit_req_fieldsize, NULL,
3354   RSRC_CONF,
3355   "Limit on maximum size of an HTTP request header field"),
3356 AP_INIT_TAKE1("LimitRequestFields", set_limit_req_fields, NULL, RSRC_CONF,
3357   "Limit (0 = unlimited) on max number of header fields in a request message"),
3358 AP_INIT_TAKE1("LimitRequestBody", set_limit_req_body,
3359   (void*)APR_OFFSETOF(core_dir_config, limit_req_body), OR_ALL,
3360   "Limit (in bytes) on maximum size of request message body"),
3361 AP_INIT_TAKE1("LimitXMLRequestBody", set_limit_xml_req_body, NULL, OR_ALL,
3362               "Limit (in bytes) on maximum size of an XML-based request "
3363               "body"),
3364
3365 /* System Resource Controls */
3366 #ifdef RLIMIT_CPU
3367 AP_INIT_TAKE12("RLimitCPU", set_limit_cpu,
3368   (void*)APR_OFFSETOF(core_dir_config, limit_cpu),
3369   OR_ALL, "Soft/hard limits for max CPU usage in seconds"),
3370 #else
3371 AP_INIT_TAKE12("RLimitCPU", no_set_limit, NULL,
3372   OR_ALL, "Soft/hard limits for max CPU usage in seconds"),
3373 #endif
3374 #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined (RLIMIT_AS)
3375 AP_INIT_TAKE12("RLimitMEM", set_limit_mem,
3376   (void*)APR_OFFSETOF(core_dir_config, limit_mem),
3377   OR_ALL, "Soft/hard limits for max memory usage per process"),
3378 #else
3379 AP_INIT_TAKE12("RLimitMEM", no_set_limit, NULL,
3380   OR_ALL, "Soft/hard limits for max memory usage per process"),
3381 #endif
3382 #ifdef RLIMIT_NPROC
3383 AP_INIT_TAKE12("RLimitNPROC", set_limit_nproc,
3384   (void*)APR_OFFSETOF(core_dir_config, limit_nproc),
3385   OR_ALL, "soft/hard limits for max number of processes per uid"),
3386 #else
3387 AP_INIT_TAKE12("RLimitNPROC", no_set_limit, NULL,
3388    OR_ALL, "soft/hard limits for max number of processes per uid"),
3389 #endif
3390
3391 /* internal recursion stopper */
3392 AP_INIT_TAKE12("LimitInternalRecursion", set_recursion_limit, NULL, RSRC_CONF,
3393               "maximum recursion depth of internal redirects and subrequests"),
3394
3395 AP_INIT_TAKE1("ForceType", ap_set_string_slot_lower,
3396        (void *)APR_OFFSETOF(core_dir_config, mime_type), OR_FILEINFO,
3397      "a mime type that overrides other configured type"),
3398 AP_INIT_TAKE1("SetHandler", ap_set_string_slot_lower,
3399        (void *)APR_OFFSETOF(core_dir_config, handler), OR_FILEINFO,
3400    "a handler name that overrides any other configured handler"),
3401 AP_INIT_TAKE1("SetOutputFilter", ap_set_string_slot,
3402        (void *)APR_OFFSETOF(core_dir_config, output_filters), OR_FILEINFO,
3403    "filter (or ; delimited list of filters) to be run on the request content"),
3404 AP_INIT_TAKE1("SetInputFilter", ap_set_string_slot,
3405        (void *)APR_OFFSETOF(core_dir_config, input_filters), OR_FILEINFO,
3406    "filter (or ; delimited list of filters) to be run on the request body"),
3407 AP_INIT_ITERATE2("AddOutputFilterByType", add_ct_output_filters,
3408        (void *)APR_OFFSETOF(core_dir_config, ct_output_filters), OR_FILEINFO,
3409      "output filter name followed by one or more content-types"),
3410 AP_INIT_FLAG("AllowEncodedSlashes", set_allow2f, NULL, RSRC_CONF,
3411              "Allow URLs containing '/' encoded as '%2F'"),
3412
3413 /*
3414  * These are default configuration directives that mpms can/should
3415  * pay attention to. If an mpm wishes to use these, they should
3416  * #defined them in mpm.h.
3417  */
3418 #ifdef AP_MPM_WANT_SET_PIDFILE
3419 AP_INIT_TAKE1("PidFile",  ap_mpm_set_pidfile, NULL, RSRC_CONF,
3420               "A file for logging the server process ID"),
3421 #endif
3422 #ifdef AP_MPM_WANT_SET_SCOREBOARD
3423 AP_INIT_TAKE1("ScoreBoardFile", ap_mpm_set_scoreboard, NULL, RSRC_CONF,
3424               "A file for Apache to maintain runtime process management information"),
3425 #endif
3426 #ifdef AP_MPM_WANT_SET_LOCKFILE
3427 AP_INIT_TAKE1("LockFile",  ap_mpm_set_lockfile, NULL, RSRC_CONF,
3428               "The lockfile used when Apache needs to lock the accept() call (deprecated)"),
3429 #endif
3430 #ifdef AP_MPM_WANT_SET_MAX_REQUESTS
3431 AP_INIT_TAKE1("MaxRequestsPerChild", ap_mpm_set_max_requests, NULL, RSRC_CONF,
3432               "Maximum number of requests a particular child serves before dying."),
3433 #endif
3434 #ifdef AP_MPM_WANT_SET_COREDUMPDIR
3435 AP_INIT_TAKE1("CoreDumpDirectory", ap_mpm_set_coredumpdir, NULL, RSRC_CONF,
3436               "The location of the directory Apache changes to before dumping core"),
3437 #endif
3438 #ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
3439 AP_INIT_TAKE1("AcceptMutex", ap_mpm_set_accept_lock_mech, NULL, RSRC_CONF,
3440               AP_AVAILABLE_MUTEXES_STRING),
3441 #endif
3442 #ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
3443 AP_INIT_TAKE1("MaxMemFree", ap_mpm_set_max_mem_free, NULL, RSRC_CONF,
3444               "Maximum number of 1k blocks a particular childs allocator may hold."),
3445 #endif
3446 #ifdef AP_MPM_WANT_SET_STACKSIZE
3447 AP_INIT_TAKE1("ThreadStackSize", ap_mpm_set_thread_stacksize, NULL, RSRC_CONF,
3448               "Size in bytes of stack used by threads handling client connections"),
3449 #endif
3450 #if AP_ENABLE_EXCEPTION_HOOK
3451 AP_INIT_TAKE1("EnableExceptionHook", ap_mpm_set_exception_hook, NULL, RSRC_CONF,
3452               "Controls whether exception hook may be called after a crash"),
3453 #endif
3454 AP_INIT_TAKE1("TraceEnable", set_trace_enable, NULL, RSRC_CONF,
3455               "'on' (default), 'off' or 'extended' to trace request body content"),
3456 { NULL }
3457 };
3458
3459 /*****************************************************************
3460  *
3461  * Core handlers for various phases of server operation...
3462  */
3463
3464 AP_DECLARE_NONSTD(int) ap_core_translate(request_rec *r)
3465 {
3466     void *sconf = r->server->module_config;
3467     core_server_config *conf = ap_get_module_config(sconf, &core_module);
3468     apr_status_t rv;
3469
3470     /* XXX this seems too specific, this should probably become
3471      * some general-case test
3472      */
3473     if (r->proxyreq) {
3474         return HTTP_FORBIDDEN;
3475     }
3476     if (!r->uri || ((r->uri[0] != '/') && strcmp(r->uri, "*"))) {
3477         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3478                      "Invalid URI in request %s", r->the_request);
3479         return HTTP_BAD_REQUEST;
3480     }
3481
3482     if (r->server->path
3483         && !strncmp(r->uri, r->server->path, r->server->pathlen)
3484         && (r->server->path[r->server->pathlen - 1] == '/'
3485             || r->uri[r->server->pathlen] == '/'
3486             || r->uri[r->server->pathlen] == '\0'))
3487     {
3488         /* skip all leading /'s (e.g. http://localhost///foo)
3489          * so we are looking at only the relative path.
3490          */
3491         char *path = r->uri + r->server->pathlen;
3492         while (*path == '/') {
3493             ++path;
3494         }
3495         if ((rv = apr_filepath_merge(&r->filename, conf->ap_document_root, path,
3496                                      APR_FILEPATH_TRUENAME
3497                                    | APR_FILEPATH_SECUREROOT, r->pool))
3498                     != APR_SUCCESS) {
3499             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
3500                          "Cannot map %s to file", r->the_request);
3501             return HTTP_FORBIDDEN;
3502         }
3503         r->canonical_filename = r->filename;
3504     }
3505     else {
3506         /*
3507          * Make sure that we do not mess up the translation by adding two
3508          * /'s in a row.  This happens under windows when the document
3509          * root ends with a /
3510          */
3511         /* skip all leading /'s (e.g. http://localhost///foo)
3512          * so we are looking at only the relative path.
3513          */
3514         char *path = r->uri;
3515         while (*path == '/') {
3516             ++path;
3517         }
3518         if ((rv = apr_filepath_merge(&r->filename, conf->ap_document_root, path,
3519                                      APR_FILEPATH_TRUENAME
3520                                    | APR_FILEPATH_SECUREROOT, r->pool))
3521                     != APR_SUCCESS) {
3522             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
3523                          "Cannot map %s to file", r->the_request);
3524             return HTTP_FORBIDDEN;
3525         }
3526         r->canonical_filename = r->filename;
3527     }
3528
3529     return OK;
3530 }
3531
3532 /*****************************************************************
3533  *
3534  * Test the filesystem name through directory_walk and file_walk
3535  */
3536 static int core_map_to_storage(request_rec *r)
3537 {
3538     int access_status;
3539
3540     if ((access_status = ap_directory_walk(r))) {
3541         return access_status;
3542     }
3543
3544     if ((access_status = ap_file_walk(r))) {
3545         return access_status;
3546     }
3547
3548     return OK;
3549 }
3550
3551
3552 static int do_nothing(request_rec *r) { return OK; }
3553
3554
3555 static int core_override_type(request_rec *r)
3556 {
3557     core_dir_config *conf =
3558         (core_dir_config *)ap_get_module_config(r->per_dir_config,
3559                                                 &core_module);
3560
3561     /* Check for overrides with ForceType / SetHandler
3562      */
3563     if (conf->mime_type && strcmp(conf->mime_type, "none"))
3564         ap_set_content_type(r, (char*) conf->mime_type);
3565
3566     if (conf->handler && strcmp(conf->handler, "none"))
3567         r->handler = conf->handler;
3568
3569     /* Deal with the poor soul who is trying to force path_info to be
3570      * accepted within the core_handler, where they will let the subreq
3571      * address its contents.  This is toggled by the user in the very
3572      * beginning of the fixup phase, so modules should override the user's
3573      * discretion in their own module fixup phase.  It is tristate, if
3574      * the user doesn't specify, the result is 2 (which the module may
3575      * interpret to its own customary behavior.)  It won't be touched
3576      * if the value is no longer undefined (2), so any module changing
3577      * the value prior to the fixup phase OVERRIDES the user's choice.
3578      */
3579     if ((r->used_path_info == AP_REQ_DEFAULT_PATH_INFO)
3580         && (conf->accept_path_info != 3)) {
3581         r->used_path_info = conf->accept_path_info;
3582     }
3583
3584     return OK;
3585 }
3586
3587 static int default_handler(request_rec *r)
3588 {
3589     conn_rec *c = r->connection;
3590     apr_bucket_brigade *bb;
3591     apr_bucket *e;
3592     core_dir_config *d;
3593     int errstatus;
3594     apr_file_t *fd = NULL;
3595     apr_status_t status;
3596     /* XXX if/when somebody writes a content-md5 filter we either need to
3597      *     remove this support or coordinate when to use the filter vs.
3598      *     when to use this code
3599      *     The current choice of when to compute the md5 here matches the 1.3
3600      *     support fairly closely (unlike 1.3, we don't handle computing md5
3601      *     when the charset is translated).
3602      */
3603     int bld_content_md5;
3604
3605     d = (core_dir_config *)ap_get_module_config(r->per_dir_config,
3606                                                 &core_module);
3607     bld_content_md5 = (d->content_md5 & 1)
3608                       && r->output_filters->frec->ftype != AP_FTYPE_RESOURCE;
3609
3610     ap_allow_standard_methods(r, MERGE_ALLOW, M_GET, M_OPTIONS, M_POST, -1);
3611
3612     /* If filters intend to consume the request body, they must
3613      * register an InputFilter to slurp the contents of the POST
3614      * data from the POST input stream.  It no longer exists when
3615      * the output filters are invoked by the default handler.
3616      */
3617     if ((errstatus = ap_discard_request_body(r)) != OK) {
3618         return errstatus;
3619     }
3620
3621     if (r->method_number == M_GET || r->method_number == M_POST) {
3622         if (r->finfo.filetype == 0) {
3623             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3624                           "File does not exist: %s", r->filename);
3625             return HTTP_NOT_FOUND;
3626         }
3627
3628         /* Don't try to serve a dir.  Some OSs do weird things with
3629          * raw I/O on a dir.
3630          */
3631         if (r->finfo.filetype == APR_DIR) {
3632             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3633                           "Attempt to serve directory: %s", r->filename);
3634             return HTTP_NOT_FOUND;
3635         }
3636
3637         if ((r->used_path_info != AP_REQ_ACCEPT_PATH_INFO) &&
3638             r->path_info && *r->path_info)
3639         {
3640             /* default to reject */
3641             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3642                           "File does not exist: %s",
3643                           apr_pstrcat(r->pool, r->filename, r->path_info, NULL));
3644             return HTTP_NOT_FOUND;
3645         }
3646
3647         /* We understood the (non-GET) method, but it might not be legal for
3648            this particular resource. Check to see if the 'deliver_script'
3649            flag is set. If so, then we go ahead and deliver the file since
3650            it isn't really content (only GET normally returns content).
3651
3652            Note: based on logic further above, the only possible non-GET
3653            method at this point is POST. In the future, we should enable
3654            script delivery for all methods.  */
3655         if (r->method_number != M_GET) {
3656             core_request_config *req_cfg;
3657
3658             req_cfg = ap_get_module_config(r->request_config, &core_module);
3659             if (!req_cfg->deliver_script) {
3660                 /* The flag hasn't been set for this request. Punt. */
3661                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3662                               "This resource does not accept the %s method.",
3663                               r->method);
3664                 return HTTP_METHOD_NOT_ALLOWED;
3665             }
3666         }
3667
3668
3669         if ((status = apr_file_open(&fd, r->filename, APR_READ | APR_BINARY
3670 #if APR_HAS_SENDFILE
3671                             | ((d->enable_sendfile == ENABLE_SENDFILE_OFF)
3672                                                 ? 0 : APR_SENDFILE_ENABLED)
3673 #endif
3674                                     , 0, r->pool)) != APR_SUCCESS) {
3675             ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
3676                           "file permissions deny server access: %s", r->filename);
3677             return HTTP_FORBIDDEN;
3678         }
3679
3680         ap_update_mtime(r, r->finfo.mtime);
3681         ap_set_last_modified(r);
3682         ap_set_etag(r);
3683         apr_table_setn(r->headers_out, "Accept-Ranges", "bytes");
3684         ap_set_content_length(r, r->finfo.size);
3685
3686         bb = apr_brigade_create(r->pool, c->bucket_alloc);
3687
3688         if ((errstatus = ap_meets_conditions(r)) != OK) {
3689             apr_file_close(fd);
3690             r->status = errstatus;
3691         }
3692         else {
3693             if (bld_content_md5) {
3694                 apr_table_setn(r->headers_out, "Content-MD5",
3695                                ap_md5digest(r->pool, fd));
3696             }
3697
3698             e = apr_brigade_insert_file(bb, fd, 0, r->finfo.size, r->pool);
3699
3700 #if APR_HAS_MMAP
3701             if (d->enable_mmap == ENABLE_MMAP_OFF) {
3702                 (void)apr_bucket_file_enable_mmap(e, 0);
3703             }
3704 #endif
3705         }
3706
3707         e = apr_bucket_eos_create(c->bucket_alloc);
3708         APR_BRIGADE_INSERT_TAIL(bb, e);
3709
3710         status = ap_pass_brigade(r->output_filters, bb);
3711         if (status == APR_SUCCESS
3712             || r->status != HTTP_OK
3713             || c->aborted) {
3714             return OK;
3715         }
3716         else {
3717             /* no way to know what type of error occurred */
3718             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r,
3719                           "default_handler: ap_pass_brigade returned %i",
3720                           status);
3721             return HTTP_INTERNAL_SERVER_ERROR;
3722         }
3723     }
3724     else {              /* unusual method (not GET or POST) */
3725         if (r->method_number == M_INVALID) {
3726             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
3727                           "Invalid method in request %s", r->the_request);
3728             return HTTP_NOT_IMPLEMENTED;
3729         }
3730
3731         if (r->method_number == M_OPTIONS) {
3732             return ap_send_http_options(r);
3733         }
3734         return HTTP_METHOD_NOT_ALLOWED;
3735     }
3736 }
3737
3738 /* Optional function coming from mod_logio, used for logging of output
3739  * traffic
3740  */
3741 APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *logio_add_bytes_out;
3742 APR_OPTIONAL_FN_TYPE(authz_some_auth_required) *authz_ap_some_auth_required;
3743
3744 static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
3745 {
3746     logio_add_bytes_out = APR_RETRIEVE_OPTIONAL_FN(ap_logio_add_bytes_out);
3747     ident_lookup = APR_RETRIEVE_OPTIONAL_FN(ap_ident_lookup);
3748     authz_ap_some_auth_required = APR_RETRIEVE_OPTIONAL_FN(authz_some_auth_required);
3749     authn_ap_auth_type = APR_RETRIEVE_OPTIONAL_FN(authn_ap_auth_type);
3750     authn_ap_auth_name = APR_RETRIEVE_OPTIONAL_FN(authn_ap_auth_name);
3751     access_compat_ap_satisfies = APR_RETRIEVE_OPTIONAL_FN(access_compat_ap_satisfies);
3752
3753     set_banner(pconf);
3754     ap_setup_make_content_type(pconf);
3755     ap_setup_auth_internal(ptemp);
3756     return OK;
3757 }
3758
3759 static void core_insert_filter(request_rec *r)
3760 {
3761     core_dir_config *conf = (core_dir_config *)
3762                             ap_get_module_config(r->per_dir_config,
3763                                                  &core_module);
3764     const char *filter, *filters = conf->output_filters;
3765
3766     if (filters) {
3767         while (*filters && (filter = ap_getword(r->pool, &filters, ';'))) {
3768             ap_add_output_filter(filter, NULL, r, r->connection);
3769         }
3770     }
3771
3772     filters = conf->input_filters;
3773     if (filters) {
3774         while (*filters && (filter = ap_getword(r->pool, &filters, ';'))) {
3775             ap_add_input_filter(filter, NULL, r, r->connection);
3776         }
3777     }
3778 }
3779
3780 static apr_size_t num_request_notes = AP_NUM_STD_NOTES;
3781
3782 static apr_status_t reset_request_notes(void *dummy)
3783 {
3784     num_request_notes = AP_NUM_STD_NOTES;
3785     return APR_SUCCESS;
3786 }
3787
3788 AP_DECLARE(apr_size_t) ap_register_request_note(void)
3789 {
3790     apr_pool_cleanup_register(apr_hook_global_pool, NULL, reset_request_notes,
3791                               apr_pool_cleanup_null);
3792     return num_request_notes++;
3793 }
3794
3795 AP_DECLARE(void **) ap_get_request_note(request_rec *r, apr_size_t note_num)
3796 {
3797     core_request_config *req_cfg;
3798
3799     if (note_num >= num_request_notes) {
3800         return NULL;
3801     }
3802
3803     req_cfg = (core_request_config *)
3804         ap_get_module_config(r->request_config, &core_module);
3805
3806     if (!req_cfg) {
3807         return NULL;
3808     }
3809
3810     return &(req_cfg->notes[note_num]);
3811 }
3812
3813 static int core_create_req(request_rec *r)
3814 {
3815     /* Alloc the config struct and the array of request notes in
3816      * a single block for efficiency
3817      */
3818     core_request_config *req_cfg;
3819
3820     req_cfg = apr_pcalloc(r->pool, sizeof(core_request_config) +
3821                           sizeof(void *) * num_request_notes);
3822     req_cfg->notes = (void **)((char *)req_cfg + sizeof(core_request_config));
3823
3824     /* ### temporarily enable script delivery as the default */
3825     req_cfg->deliver_script = 1;
3826
3827     if (r->main) {
3828         core_request_config *main_req_cfg = (core_request_config *)
3829             ap_get_module_config(r->main->request_config, &core_module);
3830         req_cfg->bb = main_req_cfg->bb;
3831     }
3832     else {
3833         req_cfg->bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
3834     }
3835
3836     ap_set_module_config(r->request_config, &core_module, req_cfg);
3837
3838     return OK;
3839 }
3840
3841 static int core_create_proxy_req(request_rec *r, request_rec *pr)
3842 {
3843     return core_create_req(pr);
3844 }
3845
3846 static conn_rec *core_create_conn(apr_pool_t *ptrans, server_rec *server,
3847                                   apr_socket_t *csd, long id, void *sbh,
3848                                   apr_bucket_alloc_t *alloc)
3849 {
3850     apr_status_t rv;
3851     conn_rec *c = (conn_rec *) apr_pcalloc(ptrans, sizeof(conn_rec));
3852
3853     c->sbh = sbh;
3854     (void)ap_update_child_status(c->sbh, SERVER_BUSY_READ, (request_rec *)NULL);
3855
3856     /* Got a connection structure, so initialize what fields we can
3857      * (the rest are zeroed out by pcalloc).
3858      */
3859     c->conn_config = ap_create_conn_config(ptrans);
3860     c->notes = apr_table_make(ptrans, 5);
3861
3862     c->pool = ptrans;
3863     if ((rv = apr_socket_addr_get(&c->local_addr, APR_LOCAL, csd))
3864         != APR_SUCCESS) {
3865         ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
3866                      "apr_socket_addr_get(APR_LOCAL)");
3867         apr_socket_close(csd);
3868         return NULL;
3869     }
3870
3871     apr_sockaddr_ip_get(&c->local_ip, c->local_addr);
3872     if ((rv = apr_socket_addr_get(&c->remote_addr, APR_REMOTE, csd))
3873         != APR_SUCCESS) {
3874         ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
3875                      "apr_socket_addr_get(APR_REMOTE)");
3876         apr_socket_close(csd);
3877         return NULL;
3878     }
3879
3880     apr_sockaddr_ip_get(&c->remote_ip, c->remote_addr);
3881     c->base_server = server;
3882
3883     c->id = id;
3884     c->bucket_alloc = alloc;
3885
3886     c->cs = (conn_state_t *)apr_pcalloc(ptrans, sizeof(conn_state_t));
3887     APR_RING_INIT(&(c->cs->timeout_list), conn_state_t, timeout_list);
3888     c->cs->expiration_time = 0;
3889     c->cs->state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;
3890     c->cs->c = c;
3891     c->cs->p = ptrans;
3892     c->cs->bucket_alloc = alloc;
3893     c->clogging_input_filters = 0;
3894
3895     return c;
3896 }
3897
3898 static int core_pre_connection(conn_rec *c, void *csd)
3899 {
3900     core_net_rec *net = apr_palloc(c->pool, sizeof(*net));
3901     apr_status_t rv;
3902
3903 #ifdef AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
3904     /* The Nagle algorithm says that we should delay sending partial
3905      * packets in hopes of getting more data.  We don't want to do
3906      * this; we are not telnet.  There are bad interactions between
3907      * persistent connections and Nagle's algorithm that have very severe
3908      * performance penalties.  (Failing to disable Nagle is not much of a
3909      * problem with simple HTTP.)
3910      */
3911     rv = apr_socket_opt_set(csd, APR_TCP_NODELAY, 1);
3912     if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
3913         /* expected cause is that the client disconnected already,
3914          * hence the debug level
3915          */
3916         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c,
3917                       "apr_socket_opt_set(APR_TCP_NODELAY)");
3918     }
3919 #endif
3920
3921     /* The core filter requires the timeout mode to be set, which
3922      * incidentally sets the socket to be nonblocking.  If this
3923      * is not initialized correctly, Linux - for example - will
3924      * be initially blocking, while Solaris will be non blocking
3925      * and any initial read will fail.
3926      */
3927     rv = apr_socket_timeout_set(csd, c->base_server->timeout);
3928     if (rv != APR_SUCCESS) {
3929         /* expected cause is that the client disconnected already */
3930         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c,
3931                       "apr_socket_timeout_set");
3932     }
3933
3934     net->c = c;
3935     net->in_ctx = NULL;
3936     net->out_ctx = NULL;
3937     net->client_socket = csd;
3938
3939     ap_set_module_config(net->c->conn_config, &core_module, csd);
3940     ap_add_input_filter_handle(ap_core_input_filter_handle, net, NULL, net->c);
3941     ap_add_output_filter_handle(ap_core_output_filter_handle, net, NULL, net->c);
3942     return DONE;
3943 }
3944
3945 static void register_hooks(apr_pool_t *p)
3946 {
3947     /* create_connection and install_transport_filters are
3948      * hooks that should always be APR_HOOK_REALLY_LAST to give other
3949      * modules the opportunity to install alternate network transports
3950      * and stop other functions from being run.
3951      */
3952     ap_hook_create_connection(core_create_conn, NULL, NULL,
3953                               APR_HOOK_REALLY_LAST);
3954     ap_hook_pre_connection(core_pre_connection, NULL, NULL,
3955                            APR_HOOK_REALLY_LAST);
3956
3957     ap_hook_post_config(core_post_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
3958     ap_hook_translate_name(ap_core_translate,NULL,NULL,APR_HOOK_REALLY_LAST);
3959     ap_hook_map_to_storage(core_map_to_storage,NULL,NULL,APR_HOOK_REALLY_LAST);
3960     ap_hook_open_logs(ap_open_logs,NULL,NULL,APR_HOOK_REALLY_FIRST);
3961     ap_hook_child_init(ap_logs_child_init,NULL,NULL,APR_HOOK_MIDDLE);
3962     ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST);
3963     /* FIXME: I suspect we can eliminate the need for these do_nothings - Ben */
3964     ap_hook_type_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);
3965     ap_hook_fixups(core_override_type,NULL,NULL,APR_HOOK_REALLY_FIRST);
3966     ap_hook_create_request(core_create_req, NULL, NULL, APR_HOOK_MIDDLE);
3967     APR_OPTIONAL_HOOK(proxy, create_req, core_create_proxy_req, NULL, NULL,
3968                       APR_HOOK_MIDDLE);
3969     ap_hook_pre_mpm(ap_create_scoreboard, NULL, NULL, APR_HOOK_MIDDLE);
3970
3971     /* register the core's insert_filter hook and register core-provided
3972      * filters
3973      */
3974     ap_hook_insert_filter(core_insert_filter, NULL, NULL, APR_HOOK_MIDDLE);
3975
3976     ap_core_input_filter_handle =
3977         ap_register_input_filter("CORE_IN", ap_core_input_filter,
3978                                  NULL, AP_FTYPE_NETWORK);
3979     ap_content_length_filter_handle =
3980         ap_register_output_filter("CONTENT_LENGTH", ap_content_length_filter,
3981                                   NULL, AP_FTYPE_PROTOCOL);
3982     ap_core_output_filter_handle =
3983         ap_register_output_filter("CORE", ap_core_output_filter,
3984                                   NULL, AP_FTYPE_NETWORK);
3985     ap_subreq_core_filter_handle =
3986         ap_register_output_filter("SUBREQ_CORE", ap_sub_req_output_filter,
3987                                   NULL, AP_FTYPE_CONTENT_SET);
3988     ap_old_write_func =
3989         ap_register_output_filter("OLD_WRITE", ap_old_write_filter,
3990                                   NULL, AP_FTYPE_RESOURCE - 10);
3991 }
3992
3993 AP_DECLARE_DATA module core_module = {
3994     STANDARD20_MODULE_STUFF,
3995     create_core_dir_config,       /* create per-directory config structure */
3996     merge_core_dir_configs,       /* merge per-directory config structures */
3997     create_core_server_config,    /* create per-server config structure */
3998     merge_core_server_configs,    /* merge per-server config structures */
3999     core_cmds,                    /* command apr_table_t */
4000     register_hooks                /* register hooks */
4001 };
4002