Binary files apache_1.3.33/src/ap/.ap_strtoll.c.swp and apache_1.3.33-mod/src/ap/.ap_strtoll.c.swp differ
diff -udrN apache_1.3.33/src/ap/Makefile.tmpl apache_1.3.33-mod/src/ap/Makefile.tmpl
--- apache_1.3.33/src/ap/Makefile.tmpl	Mon Jun 17 17:34:35 2002
+++ apache_1.3.33-mod/src/ap/Makefile.tmpl	Fri Apr  1 10:06:37 2005
@@ -7,7 +7,7 @@
 
 OBJS=ap_cpystrn.o ap_execve.o ap_fnmatch.o ap_getpass.o ap_md5c.o ap_signal.o \
      ap_slack.o ap_snprintf.o ap_sha1.o ap_checkpass.o ap_base64.o ap_ebcdic.o \
-     ap_strtol.o
+     ap_strtol.o ap_strtoll.o
 
 .c.o:
 	$(CC) -c $(INCLUDES) $(CFLAGS) $<
diff -udrN apache_1.3.33/src/ap/ap_strtoll.c apache_1.3.33-mod/src/ap/ap_strtoll.c
--- apache_1.3.33/src/ap/ap_strtoll.c	Wed Dec 31 16:00:00 1969
+++ apache_1.3.33-mod/src/ap/ap_strtoll.c	Fri Apr  1 10:16:06 2005
@@ -0,0 +1,142 @@
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtoq.c	8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+#if 0
+__FBSDID("$FreeBSD: src/lib/libc/stdlib/strtoll.c,v 1.19 2002/09/06 11:23:59 tjr Exp $");
+#endif
+
+#include <limits.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to a long long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+long long ap_strtoll(const char * nptr, char ** endptr, int base)
+{
+	const char *s;
+	unsigned long long acc;
+	char c;
+	unsigned long long cutoff;
+	int neg, any, cutlim;
+
+	/*
+	 * Skip white space and pick up leading +/- sign if any.
+	 * If base is 0, allow 0x for hex and 0 for octal, else
+	 * assume decimal; if base is already 16, allow 0x.
+	 */
+	s = nptr;
+	do {
+		c = *s++;
+	} while (isspace((unsigned char)c));
+	if (c == '-') {
+		neg = 1;
+		c = *s++;
+	} else {
+		neg = 0;
+		if (c == '+')
+			c = *s++;
+	}
+	if ((base == 0 || base == 16) &&
+	    c == '0' && (*s == 'x' || *s == 'X')) {
+		c = s[1];
+		s += 2;
+		base = 16;
+	}
+	if (base == 0)
+		base = c == '0' ? 8 : 10;
+	acc = any = 0;
+	if (base < 2 || base > 36)
+		goto noconv;
+
+	/*
+	 * Compute the cutoff value between legal numbers and illegal
+	 * numbers.  That is the largest legal value, divided by the
+	 * base.  An input number that is greater than this value, if
+	 * followed by a legal input character, is too big.  One that
+	 * is equal to this value may be valid or not; the limit
+	 * between valid and invalid numbers is then based on the last
+	 * digit.  For instance, if the range for quads is
+	 * [-9223372036854775808..9223372036854775807] and the input base
+	 * is 10, cutoff will be set to 922337203685477580 and cutlim to
+	 * either 7 (neg==0) or 8 (neg==1), meaning that if we have
+	 * accumulated a value > 922337203685477580, or equal but the
+	 * next digit is > 7 (or 8), the number is too big, and we will
+	 * return a range error.
+	 *
+	 * Set 'any' if any `digits' consumed; make it negative to indicate
+	 * overflow.
+	 */
+	cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
+	    : LLONG_MAX;
+	cutlim = cutoff % base;
+	cutoff /= base;
+	for ( ; ; c = *s++) {
+		if (c >= '0' && c <= '9')
+			c -= '0';
+		else if (c >= 'A' && c <= 'Z')
+			c -= 'A' - 10;
+		else if (c >= 'a' && c <= 'z')
+			c -= 'a' - 10;
+		else
+			break;
+		if (c >= base)
+			break;
+		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+			any = -1;
+		else {
+			any = 1;
+			acc *= base;
+			acc += c;
+		}
+	}
+	if (any < 0) {
+		acc = neg ? LLONG_MIN : LLONG_MAX;
+		errno = ERANGE;
+	} else if (!any) {
+noconv:
+		errno = EINVAL;
+	} else if (neg)
+		acc = -acc;
+	if (endptr != NULL)
+		*endptr = (char *)(any ? s - 1 : nptr);
+	return (acc);
+}
diff -udrN apache_1.3.33/src/include/ap.h apache_1.3.33-mod/src/include/ap.h
--- apache_1.3.33/src/include/ap.h	Mon Feb 16 14:25:08 2004
+++ apache_1.3.33-mod/src/include/ap.h	Fri Apr  1 10:06:37 2005
@@ -34,6 +34,7 @@
 
 #ifndef ap_strtol
 API_EXPORT(long) ap_strtol(const char *nptr, char **endptr, int base);
+API_EXPORT(int64_t) ap_strtoll(const char *nptr, char **endptr, int base);
 #endif
 
 /* small utility macros to make things easier to read */
diff -udrN apache_1.3.33/src/include/ap.h.orig apache_1.3.33-mod/src/include/ap.h.orig
--- apache_1.3.33/src/include/ap.h.orig	Wed Dec 31 16:00:00 1969
+++ apache_1.3.33-mod/src/include/ap.h.orig	Mon Feb 16 14:25:08 2004
@@ -0,0 +1,159 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * The ap_vsnprintf/ap_snprintf functions are based on, and used with the
+ * permission of, the  SIO stdio-replacement strx_* functions by Panos
+ * Tsirigotis <panos@alumni.cs.colorado.edu> for xinetd.
+ */
+
+#ifndef APACHE_AP_H
+#define APACHE_AP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+API_EXPORT(char *) ap_cpystrn(char *, const char *, size_t);
+int ap_slack(int, int);
+int ap_execle(const char *, const char *, ...);
+int ap_execve(const char *, char * const argv[], char * const envp[]);
+API_EXPORT(int) ap_getpass(const char *prompt, char *pwbuf, size_t bufsiz);
+
+#ifndef ap_strtol
+API_EXPORT(long) ap_strtol(const char *nptr, char **endptr, int base);
+#endif
+
+/* small utility macros to make things easier to read */
+
+#ifdef WIN32
+#define ap_killpg(x, y)
+#else
+#ifdef NO_KILLPG
+#define ap_killpg(x, y)		(kill (-(x), (y)))
+#else
+#define ap_killpg(x, y)		(killpg ((x), (y)))
+#endif
+#endif /* WIN32 */
+
+/* ap_vformatter() is a generic printf-style formatting routine
+ * with some extensions.  The extensions are:
+ *
+ * %pA	takes a struct in_addr *, and prints it as a.b.c.d
+ * %pI	takes a struct sockaddr_in * and prints it as a.b.c.d:port
+ * %pp  takes a void * and outputs it in hex
+ *
+ * The %p hacks are to force gcc's printf warning code to skip
+ * over a pointer argument without complaining.  This does
+ * mean that the ANSI-style %p (output a void * in hex format) won't
+ * work as expected at all, but that seems to be a fair trade-off
+ * for the increased robustness of having printf-warnings work.
+ *
+ * Additionally, ap_vformatter allows for arbitrary output methods
+ * using the ap_vformatter_buff and flush_func.
+ *
+ * The ap_vformatter_buff has two elements curpos and endpos.
+ * curpos is where ap_vformatter will write the next byte of output.
+ * It proceeds writing output to curpos, and updating curpos, until
+ * either the end of output is reached, or curpos == endpos (i.e. the
+ * buffer is full).
+ *
+ * If the end of output is reached, ap_vformatter returns the
+ * number of bytes written.
+ *
+ * When the buffer is full, the flush_func is called.  The flush_func
+ * can return -1 to indicate that no further output should be attempted,
+ * and ap_vformatter will return immediately with -1.  Otherwise
+ * the flush_func should flush the buffer in whatever manner is
+ * appropriate, re-initialize curpos and endpos, and return 0.
+ *
+ * Note that flush_func is only invoked as a result of attempting to
+ * write another byte at curpos when curpos >= endpos.  So for
+ * example, it's possible when the output exactly matches the buffer
+ * space available that curpos == endpos will be true when
+ * ap_vformatter returns.
+ *
+ * ap_vformatter does not call out to any other code, it is entirely
+ * self-contained.  This allows the callers to do things which are
+ * otherwise "unsafe".  For example, ap_psprintf uses the "scratch"
+ * space at the unallocated end of a block, and doesn't actually
+ * complete the allocation until ap_vformatter returns.  ap_psprintf
+ * would be completely broken if ap_vformatter were to call anything
+ * that used a pool.  Similarly http_bprintf() uses the "scratch"
+ * space at the end of its output buffer, and doesn't actually note
+ * that the space is in use until it either has to flush the buffer
+ * or until ap_vformatter returns.
+ */
+
+typedef struct {
+    char *curpos;
+    char *endpos;
+} ap_vformatter_buff;
+
+API_EXPORT(int) ap_vformatter(int (*flush_func)(ap_vformatter_buff *),
+    ap_vformatter_buff *, const char *fmt, va_list ap);
+
+/* These are snprintf implementations based on ap_vformatter().
+ *
+ * Note that various standards and implementations disagree on the return
+ * value of snprintf, and side-effects due to %n in the formatting string.
+ * ap_snprintf behaves as follows:
+ *
+ * Process the format string until the entire string is exhausted, or
+ * the buffer fills.  If the buffer fills then stop processing immediately
+ * (so no further %n arguments are processed), and return the buffer
+ * length.  In all cases the buffer is NUL terminated. The return value
+ * is the number of characters placed in the buffer, excluding the
+ * terminating NUL. All this implies that, at most, (len-1) characters
+ * will be copied over; if the return value is >= len, then truncation
+ * occured.
+ *
+ * In no event does ap_snprintf return a negative number.
+ */
+API_EXPORT_NONSTD(int) ap_snprintf(char *buf, size_t len, const char *format,...)
+			    __attribute__((format(printf,3,4)));
+API_EXPORT(int) ap_vsnprintf(char *buf, size_t len, const char *format,
+			     va_list ap);
+/* Simple BASE64 encode/decode functions.
+ * 
+ * As we might encode binary strings, hence we require the length of
+ * the incoming plain source. And return the length of what we decoded.
+ *
+ * The decoding function takes any non valid char (i.e. whitespace, \0
+ * or anything non A-Z,0-9 etc as terminal.
+ * 
+ * plain strings/binary sequences are not assumed '\0' terminated. Encoded
+ * strings are neither. But propably should.
+ *
+ */
+API_EXPORT(int) ap_base64encode_len(int len);
+API_EXPORT(int) ap_base64encode(char * coded_dst, const char *plain_src,int len_plain_src);
+API_EXPORT(int) ap_base64encode_binary(char * coded_dst, const unsigned char *plain_src,int len_plain_src);
+
+API_EXPORT(int) ap_base64decode_len(const char * coded_src);
+API_EXPORT(int) ap_base64decode(char * plain_dst, const char *coded_src);
+API_EXPORT(int) ap_base64decode_binary(unsigned char * plain_dst, const char *coded_src);
+
+/* Password validation, as used in AuthType Basic which is able to cope
+ * (based on the prefix) with the SHA1, Apache's internal MD5 and (depending
+ * on your platform either plain or crypt(3) passwords.
+ */
+API_EXPORT(char *) ap_validate_password(const char *passwd, const char *hash);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* !APACHE_AP_H */
diff -udrN apache_1.3.33/src/include/http_protocol.h apache_1.3.33-mod/src/include/http_protocol.h
--- apache_1.3.33/src/include/http_protocol.h	Mon Feb 16 14:25:08 2004
+++ apache_1.3.33-mod/src/include/http_protocol.h	Fri Apr  1 10:06:37 2005
@@ -70,7 +70,7 @@
  * permit_cache argument is set to one).
  */
 
-API_EXPORT(int) ap_set_content_length(request_rec *r, long length);
+API_EXPORT(int64_t) ap_set_content_length(request_rec *r, int64_t length);
 API_EXPORT(int) ap_set_keepalive(request_rec *r);
 API_EXPORT(time_t) ap_rationalize_mtime(request_rec *r, time_t mtime);
 API_EXPORT(char *) ap_make_etag(request_rec *r, int force_weak);
@@ -89,14 +89,13 @@
  * (Ditto the send_header stuff).
  */
 
-API_EXPORT(long) ap_send_fd(FILE *f, request_rec *r);
-API_EXPORT(long) ap_send_fd_length(FILE *f, request_rec *r, long length);
+API_EXPORT(int64_t) ap_send_fd(FILE *f, request_rec *r);
+API_EXPORT(int64_t) ap_send_fd_length(FILE *f, request_rec *r, int64_t length);
 
-API_EXPORT(long) ap_send_fb(BUFF *f, request_rec *r);
-API_EXPORT(long) ap_send_fb_length(BUFF *f, request_rec *r, long length);
+API_EXPORT(int64_t) ap_send_fb(BUFF *f, request_rec *r);
+API_EXPORT(int64_t) ap_send_fb_length(BUFF *f, request_rec *r, int64_t length);
 
-API_EXPORT(size_t) ap_send_mmap(void *mm, request_rec *r, size_t offset,
-                             size_t length);
+API_EXPORT(int64_t) ap_send_mmap(void *mm, request_rec *r, off_t offset, int64_t length);
 
 /* Hmmm... could macrofy these for now, and maybe forever, though the
  * definitions of the macros would get a whole lot hairier.
@@ -128,7 +127,7 @@
 /* Sending a byterange */
 
 API_EXPORT(int) ap_set_byterange(request_rec *r);
-API_EXPORT(int) ap_each_byterange(request_rec *r, long *offset, long *length);
+API_EXPORT(int64_t) ap_each_byterange(request_rec *r, int64_t *offset, int64_t *length);
 
 /* Support for the Basic authentication protocol.  Note that there's
  * nothing that prevents these from being in mod_auth.c, except that other
diff -udrN apache_1.3.33/src/include/http_protocol.h.orig apache_1.3.33-mod/src/include/http_protocol.h.orig
--- apache_1.3.33/src/include/http_protocol.h.orig	Wed Dec 31 16:00:00 1969
+++ apache_1.3.33-mod/src/include/http_protocol.h.orig	Mon Feb 16 14:25:08 2004
@@ -0,0 +1,186 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef APACHE_HTTP_PROTOCOL_H
+#define APACHE_HTTP_PROTOCOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Prototypes for routines which either talk directly back to the user,
+ * or control the ones that eventually do.
+ */
+
+/* Read a request and fill in the fields. */
+
+API_EXPORT(request_rec *) ap_read_request(conn_rec *c);
+
+/* Send a single HTTP header field */
+
+API_EXPORT_NONSTD(int) ap_send_header_field(request_rec *r, const char *fieldname,
+                      const char *fieldval);
+
+/* Send the minimal part of an HTTP response header... but modules should be
+ * very careful about using this, and should prefer ap_send_http_header().
+ * Much of the HTTP/1.1 implementation correctness depends on code in
+ * ap_send_http_header().
+ */
+API_EXPORT(void) ap_basic_http_header(request_rec *r);
+
+/* Send the Status-Line and header fields for HTTP response */
+
+API_EXPORT(void) ap_send_http_header(request_rec *l);
+
+/* Send the response to special method requests */
+
+API_EXPORT(int) ap_send_http_trace(request_rec *r);
+API_EXPORT(int) ap_send_http_options(request_rec *r);
+
+/* Finish up stuff after a request */
+
+API_EXPORT(void) ap_finalize_request_protocol(request_rec *r);
+
+/* Send error back to client... last arg indicates error status in case
+ * we get an error in the process of trying to deal with an ErrorDocument
+ * to handle some other error.  In that case, we print the default report
+ * for the first thing that went wrong, and more briefly report on the
+ * problem with the ErrorDocument.
+ */
+
+API_EXPORT(void) ap_send_error_response(request_rec *r, int recursive_error);
+
+/* Set last modified header line from the lastmod date of the associated file.
+ * Also, set content length.
+ *
+ * May return an error status, typically USE_LOCAL_COPY (that when the
+ * permit_cache argument is set to one).
+ */
+
+API_EXPORT(int) ap_set_content_length(request_rec *r, long length);
+API_EXPORT(int) ap_set_keepalive(request_rec *r);
+API_EXPORT(time_t) ap_rationalize_mtime(request_rec *r, time_t mtime);
+API_EXPORT(char *) ap_make_etag(request_rec *r, int force_weak);
+API_EXPORT(void) ap_set_etag(request_rec *r);
+API_EXPORT(void) ap_set_last_modified(request_rec *r);
+API_EXPORT(int) ap_meets_conditions(request_rec *r);
+
+/* Other ways to send stuff at the client.  All of these keep track
+ * of bytes_sent automatically.  This indirection is intended to make
+ * it a little more painless to slide things like HTTP-NG packetization
+ * underneath the main body of the code later.  In the meantime, it lets
+ * us centralize a bit of accounting (bytes_sent).
+ *
+ * These also return the number of bytes written by the call.
+ * They should only be called with a timeout registered, for obvious reaasons.
+ * (Ditto the send_header stuff).
+ */
+
+API_EXPORT(long) ap_send_fd(FILE *f, request_rec *r);
+API_EXPORT(long) ap_send_fd_length(FILE *f, request_rec *r, long length);
+
+API_EXPORT(long) ap_send_fb(BUFF *f, request_rec *r);
+API_EXPORT(long) ap_send_fb_length(BUFF *f, request_rec *r, long length);
+
+API_EXPORT(size_t) ap_send_mmap(void *mm, request_rec *r, size_t offset,
+                             size_t length);
+
+/* Hmmm... could macrofy these for now, and maybe forever, though the
+ * definitions of the macros would get a whole lot hairier.
+ */
+
+API_EXPORT(int) ap_rputc(int c, request_rec *r);
+API_EXPORT(int) ap_rputs(const char *str, request_rec *r);
+API_EXPORT(int) ap_rwrite(const void *buf, int nbyte, request_rec *r);
+API_EXPORT_NONSTD(int) ap_rvputs(request_rec *r,...);
+API_EXPORT(int) ap_vrprintf(request_rec *r, const char *fmt, va_list vlist);
+API_EXPORT_NONSTD(int) ap_rprintf(request_rec *r, const char *fmt,...)
+				__attribute__((format(printf,2,3)));
+API_EXPORT(int) ap_rflush(request_rec *r);
+
+/*
+ * Index used in custom_responses array for a specific error code
+ * (only use outside protocol.c is in getting them configured).
+ */
+
+API_EXPORT(int) ap_index_of_response(int status);
+
+/* Reading a block of data from the client connection (e.g., POST arg) */
+
+API_EXPORT(int) ap_setup_client_block(request_rec *r, int read_policy);
+API_EXPORT(int) ap_should_client_block(request_rec *r);
+API_EXPORT(long) ap_get_client_block(request_rec *r, char *buffer, int bufsiz);
+API_EXPORT(int) ap_discard_request_body(request_rec *r);
+
+/* Sending a byterange */
+
+API_EXPORT(int) ap_set_byterange(request_rec *r);
+API_EXPORT(int) ap_each_byterange(request_rec *r, long *offset, long *length);
+
+/* Support for the Basic authentication protocol.  Note that there's
+ * nothing that prevents these from being in mod_auth.c, except that other
+ * modules which wanted to provide their own variants on finding users and
+ * passwords for Basic auth (a fairly common request) would then require
+ * mod_auth to be loaded or they wouldn't work.
+ *
+ * get_basic_auth_pw returns 0 (OK) if it set the 'pw' argument (and assured
+ * a correct value in r->connection->user); otherwise it returns an error
+ * code, either SERVER_ERROR if things are really confused, AUTH_REQUIRED
+ * if no authentication at all seemed to be in use, or DECLINED if there
+ * was authentication but it wasn't Basic (in which case, the caller should
+ * presumably decline as well).
+ *
+ * note_basic_auth_failure arranges for the right stuff to be scribbled on
+ * the HTTP return so that the client knows how to authenticate itself the
+ * next time. As does note_digest_auth_failure for Digest auth.
+ *
+ * note_auth_failure does the same thing, but will call the correct one
+ * based on the authentication type in use.
+ *
+ */
+
+API_EXPORT(void) ap_note_auth_failure(request_rec *r);
+API_EXPORT(void) ap_note_basic_auth_failure(request_rec *r);
+API_EXPORT(void) ap_note_digest_auth_failure(request_rec *r);
+API_EXPORT(int) ap_get_basic_auth_pw(request_rec *r, const char **pw);
+
+/*
+ * Setting up the protocol fields for subsidiary requests...
+ * Also, a wrapup function to keep the internal accounting straight.
+ */
+
+API_EXPORT(void) ap_set_sub_req_protocol(request_rec *rnew, const request_rec *r);
+API_EXPORT(void) ap_finalize_sub_req_protocol(request_rec *sub_r);
+
+/* This is also useful for putting sub_reqs and internal_redirects together */
+
+CORE_EXPORT(void) ap_parse_uri(request_rec *r, const char *uri);
+
+/* Get the method number associated with the given string, assumed to
+ * contain an HTTP method.  Returns M_INVALID if not recognized.
+ */
+API_EXPORT(int) ap_method_number_of(const char *method);
+
+API_EXPORT(int) ap_getline(char *s, int n, BUFF *in, int fold);
+
+API_EXPORT(long) ap_get_chunk_size(char *b);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* !APACHE_HTTP_PROTOCOL_H */
diff -udrN apache_1.3.33/src/include/httpd.h apache_1.3.33-mod/src/include/httpd.h
--- apache_1.3.33/src/include/httpd.h	Wed Oct 27 09:34:01 2004
+++ apache_1.3.33-mod/src/include/httpd.h	Fri Apr  1 10:06:37 2005
@@ -700,20 +700,20 @@
     */
     int allowed;		/* Allowed methods - for 405, OPTIONS, etc */
 
-    int sent_bodyct;		/* byte count in stream is for body */
-    long bytes_sent;		/* body byte count, for easy access */
+    int64_t sent_bodyct;		/* byte count in stream is for body */
+    int64_t bytes_sent;		/* body byte count, for easy access */
     time_t mtime;		/* Time the resource was last modified */
 
     /* HTTP/1.1 connection-level features */
 
     int chunked;		/* sending chunked transfer-coding */
-    int byterange;		/* number of byte ranges */
+    int64_t byterange;		/* number of byte ranges */
     char *boundary;		/* multipart/byteranges boundary */
     const char *range;		/* The Range: header */
-    long clength;		/* The "real" content length */
+    int64_t clength;		/* The "real" content length */
 
-    long remaining;		/* bytes left to read */
-    long read_length;		/* bytes that have been read */
+    int64_t remaining;		/* bytes left to read */
+    int64_t read_length;		/* bytes that have been read */
     int read_body;		/* how the request body should be read */
     int read_chunked;		/* reading chunked transfer-coding */
     unsigned expecting_100;	/* is client waiting for a 100 response? */
diff -udrN apache_1.3.33/src/include/httpd.h.orig apache_1.3.33-mod/src/include/httpd.h.orig
--- apache_1.3.33/src/include/httpd.h.orig	Wed Dec 31 16:00:00 1969
+++ apache_1.3.33-mod/src/include/httpd.h.orig	Wed Oct 27 09:34:01 2004
@@ -0,0 +1,1216 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef APACHE_HTTPD_H
+#define APACHE_HTTPD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * httpd.h: header for simple (ha! not anymore) http daemon
+ */
+
+/* Headers in which EVERYONE has an interest... */
+
+#include "ap_config.h"
+#include "ap_alloc.h"
+#include "buff.h"
+#include "ap.h"
+
+/* ----------------------------- config dir ------------------------------ */
+
+/* Define this to be the default server home dir. Most things later in this
+ * file with a relative pathname will have this added.
+ */
+#ifndef HTTPD_ROOT
+#ifdef OS2
+/* Set default for OS/2 file system */
+#define HTTPD_ROOT "/os2httpd"
+#elif defined(WIN32)
+/* Set default for Windows file system */
+#define HTTPD_ROOT "/apache"
+#elif defined(BEOS) || defined(BONE)
+#define HTTPD_ROOT "/boot/home/apache"
+#elif defined(NETWARE)
+#define HTTPD_ROOT "sys:/apache"
+#else
+#define HTTPD_ROOT "/usr/local/apache"
+#endif
+#endif /* HTTPD_ROOT */
+
+/* Default location of documents.  Can be overridden by the DocumentRoot
+ * directive.
+ */
+#ifndef DOCUMENT_LOCATION
+#ifdef OS2
+/* Set default for OS/2 file system */
+#define DOCUMENT_LOCATION  HTTPD_ROOT "/docs"
+#else
+#define DOCUMENT_LOCATION  HTTPD_ROOT "/htdocs"
+#endif
+#endif /* DOCUMENT_LOCATION */
+
+/* Max. number of dynamically loaded modules */
+#ifndef DYNAMIC_MODULE_LIMIT
+#define DYNAMIC_MODULE_LIMIT 64
+#endif
+
+/* Default administrator's address */
+#define DEFAULT_ADMIN "[no address given]"
+
+/* The target name of the installed Apache */
+#ifndef TARGET
+#define TARGET "httpd"
+#endif
+
+/* 
+ * --------- You shouldn't have to edit anything below this line ----------
+ *
+ * Any modifications to any defaults not defined above should be done in the 
+ * respective config. file. 
+ *
+ */
+
+
+/* -- Internal representation for a HTTP protocol number, e.g., HTTP/1.1 -- */
+
+#define HTTP_VERSION(major,minor) (1000*(major)+(minor))
+#define HTTP_VERSION_MAJOR(number) ((number)/1000)
+#define HTTP_VERSION_MINOR(number) ((number)%1000)
+
+
+/* -------------- Port number for server running standalone --------------- */
+
+#define DEFAULT_HTTP_PORT	80
+#define DEFAULT_HTTPS_PORT	443
+#define ap_is_default_port(port,r)	((port) == ap_default_port(r))
+#ifdef NETWARE
+#define ap_http_method(r) ap_os_http_method((void*)r)
+#define ap_default_port(r) ap_os_default_port((void*)r)
+#else
+#define ap_http_method(r)	"http"
+#define ap_default_port(r)	DEFAULT_HTTP_PORT
+#endif
+
+/* --------- Default user name and group name running standalone ---------- */
+/* --- These may be specified as numbers by placing a # before a number --- */
+
+#ifndef DEFAULT_USER
+#define DEFAULT_USER "#-1"
+#endif
+#ifndef DEFAULT_GROUP
+#define DEFAULT_GROUP "#-1"
+#endif
+
+#ifndef DEFAULT_ERRORLOG
+#if defined(OS2) || defined(WIN32)
+#define DEFAULT_ERRORLOG "logs/error.log"
+#else
+#define DEFAULT_ERRORLOG "logs/error_log"
+#endif
+#endif /* DEFAULT_ERRORLOG */
+
+#ifndef DEFAULT_PIDLOG
+#define DEFAULT_PIDLOG "logs/httpd.pid"
+#endif
+#ifndef DEFAULT_SCOREBOARD
+#define DEFAULT_SCOREBOARD "logs/apache_runtime_status"
+#endif
+#ifndef DEFAULT_LOCKFILE
+#define DEFAULT_LOCKFILE "logs/accept.lock"
+#endif
+
+/* Define this to be what your HTML directory content files are called */
+#ifndef DEFAULT_INDEX
+#define DEFAULT_INDEX "index.html"
+#endif
+
+/* Define this to 1 if you want fancy indexing, 0 otherwise */
+#ifndef DEFAULT_INDEXING
+#define DEFAULT_INDEXING 0
+#endif
+
+/* Define this to be what type you'd like returned for files with unknown */
+/* suffixes.  MUST be all lower case. */
+#ifndef DEFAULT_CONTENT_TYPE
+#define DEFAULT_CONTENT_TYPE "text/plain"
+#endif
+
+/* Define this to be what your per-directory security files are called */
+#ifndef DEFAULT_ACCESS_FNAME
+#ifdef OS2
+/* Set default for OS/2 file system */
+#define DEFAULT_ACCESS_FNAME "htaccess"
+#else
+#define DEFAULT_ACCESS_FNAME ".htaccess"
+#endif
+#endif /* DEFAULT_ACCESS_FNAME */
+
+/* The name of the server config file */
+#ifndef SERVER_CONFIG_FILE
+#define SERVER_CONFIG_FILE "conf/httpd.conf"
+#endif
+
+/* The name of the document config file */
+#ifndef RESOURCE_CONFIG_FILE
+#define RESOURCE_CONFIG_FILE "conf/srm.conf"
+#endif
+
+/* The name of the MIME types file */
+#ifndef TYPES_CONFIG_FILE
+#define TYPES_CONFIG_FILE "conf/mime.types"
+#endif
+
+/* The name of the access file */
+#ifndef ACCESS_CONFIG_FILE
+#define ACCESS_CONFIG_FILE "conf/access.conf"
+#endif
+
+/* Whether we should enable rfc1413 identity checking */
+#ifndef DEFAULT_RFC1413
+#define DEFAULT_RFC1413 0
+#endif
+/* The default directory in user's home dir */
+#ifndef DEFAULT_USER_DIR
+#define DEFAULT_USER_DIR "public_html"
+#endif
+
+/* The default path for CGI scripts if none is currently set */
+#ifndef DEFAULT_PATH
+#define DEFAULT_PATH "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin"
+#endif
+
+/* The path to the shell interpreter, for parsed docs */
+#ifndef SHELL_PATH
+#if defined(OS2) || defined(WIN32)
+/* Set default for OS/2 and Windows file system */
+#define SHELL_PATH "CMD.EXE"
+#else
+#define SHELL_PATH "/bin/sh"
+#endif
+#endif /* SHELL_PATH */
+
+/* The path to the suExec wrapper, can be overridden in Configuration */
+#ifndef SUEXEC_BIN
+#define SUEXEC_BIN  HTTPD_ROOT "/bin/suexec"
+#endif
+
+/* The default string lengths */
+#define MAX_STRING_LEN HUGE_STRING_LEN
+#define HUGE_STRING_LEN 8192
+
+/* The timeout for waiting for messages */
+#ifndef DEFAULT_TIMEOUT
+#define DEFAULT_TIMEOUT 300
+#endif
+
+/* The timeout for waiting for keepalive timeout until next request */
+#ifndef DEFAULT_KEEPALIVE_TIMEOUT
+#define DEFAULT_KEEPALIVE_TIMEOUT 15
+#endif
+
+/* The number of requests to entertain per connection */
+#ifndef DEFAULT_KEEPALIVE
+#define DEFAULT_KEEPALIVE 100
+#endif
+
+/* The size of the server's internal read-write buffers */
+#define IOBUFSIZE 8192
+
+/* The max number of regex captures that can be expanded by ap_pregsub */
+#define AP_MAX_REG_MATCH 10
+
+/* Number of servers to spawn off by default --- also, if fewer than
+ * this free when the caretaker checks, it will spawn more.
+ */
+#ifndef DEFAULT_START_DAEMON
+#define DEFAULT_START_DAEMON 5
+#endif
+
+/* Maximum number of *free* server processes --- more than this, and
+ * they will die off.
+ */
+
+#ifndef DEFAULT_MAX_FREE_DAEMON
+#define DEFAULT_MAX_FREE_DAEMON 10
+#endif
+
+/* Minimum --- fewer than this, and more will be created */
+
+#ifndef DEFAULT_MIN_FREE_DAEMON
+#define DEFAULT_MIN_FREE_DAEMON 5
+#endif
+
+/* Limit on the total --- clients will be locked out if more servers than
+ * this are needed.  It is intended solely to keep the server from crashing
+ * when things get out of hand.
+ *
+ * We keep a hard maximum number of servers, for two reasons --- first off,
+ * in case something goes seriously wrong, we want to stop the fork bomb
+ * short of actually crashing the machine we're running on by filling some
+ * kernel table.  Secondly, it keeps the size of the scoreboard file small
+ * enough that we can read the whole thing without worrying too much about
+ * the overhead.
+ */
+#ifndef HARD_SERVER_LIMIT
+#ifdef WIN32
+#define HARD_SERVER_LIMIT 1024
+#elif defined(NETWARE)
+#define HARD_SERVER_LIMIT 2048
+#else
+#define HARD_SERVER_LIMIT 256
+#endif
+#endif
+
+/*
+ * Special Apache error codes. These are basically used
+ *  in http_main.c so we can keep track of various errors.
+ *
+ *   APEXIT_OK:
+ *     A normal exit
+ *   APEXIT_INIT:
+ *     A fatal error arising during the server's init sequence
+ *   APEXIT_CHILDINIT:
+ *     The child died during it's init sequence
+ *   APEXIT_CHILDFATAL:
+ *     A fatal error, resulting in the whole server aborting.
+ *     If a child exits with this error, the parent process
+ *     considers this a server-wide fatal error and aborts.
+ *                 
+ */
+#define APEXIT_OK		0x0
+#define APEXIT_INIT		0x2
+#define APEXIT_CHILDINIT	0x3
+#define APEXIT_CHILDFATAL	0xf
+
+/*
+ * (Unix, OS/2 only)
+ * Interval, in microseconds, between scoreboard maintenance.  During
+ * each scoreboard maintenance cycle the parent decides if it needs to
+ * spawn a new child (to meet MinSpareServers requirements), or kill off
+ * a child (to meet MaxSpareServers requirements).  It will only spawn or
+ * kill one child per cycle.  Setting this too low will chew cpu.  The
+ * default is probably sufficient for everyone.  But some people may want
+ * to raise this on servers which aren't dedicated to httpd and where they
+ * don't like the httpd waking up each second to see what's going on.
+ */
+#ifndef SCOREBOARD_MAINTENANCE_INTERVAL
+#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000
+#endif
+
+/* Number of requests to try to handle in a single process.  If <= 0,
+ * the children don't die off.  That's the default here, since I'm still
+ * interested in finding and stanching leaks.
+ */
+
+#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD
+#define DEFAULT_MAX_REQUESTS_PER_CHILD 0
+#endif
+
+#ifndef DEFAULT_THREADS_PER_CHILD
+#define DEFAULT_THREADS_PER_CHILD 50
+#endif
+#ifndef DEFAULT_EXCESS_REQUESTS_PER_CHILD
+#define DEFAULT_EXCESS_REQUESTS_PER_CHILD 0
+#endif
+
+/* The maximum length of the queue of pending connections, as defined
+ * by listen(2).  Under some systems, it should be increased if you
+ * are experiencing a heavy TCP SYN flood attack.
+ *
+ * It defaults to 511 instead of 512 because some systems store it 
+ * as an 8-bit datatype; 512 truncated to 8-bits is 0, while 511 is 
+ * 255 when truncated.
+ */
+
+#ifndef DEFAULT_LISTENBACKLOG
+#define DEFAULT_LISTENBACKLOG 511
+#endif
+
+/* Limits on the size of various request items.  These limits primarily
+ * exist to prevent simple denial-of-service attacks on a server based
+ * on misuse of the protocol.  The recommended values will depend on the
+ * nature of the server resources -- CGI scripts and database backends
+ * might require large values, but most servers could get by with much
+ * smaller limits than we use below.  The request message body size can
+ * be limited by the per-dir config directive LimitRequestBody.
+ *
+ * Internal buffer sizes are two bytes more than the DEFAULT_LIMIT_REQUEST_LINE
+ * and DEFAULT_LIMIT_REQUEST_FIELDSIZE below, which explains the 8190.
+ * These two limits can be lowered (but not raised) by the server config
+ * directives LimitRequestLine and LimitRequestFieldsize, respectively.
+ *
+ * DEFAULT_LIMIT_REQUEST_FIELDS can be modified or disabled (set = 0) by
+ * the server config directive LimitRequestFields.
+ */
+#ifndef DEFAULT_LIMIT_REQUEST_LINE
+#define DEFAULT_LIMIT_REQUEST_LINE 8190
+#endif /* default limit on bytes in Request-Line (Method+URI+HTTP-version) */
+#ifndef DEFAULT_LIMIT_REQUEST_FIELDSIZE
+#define DEFAULT_LIMIT_REQUEST_FIELDSIZE 8190
+#endif /* default limit on bytes in any one header field  */
+#ifndef DEFAULT_LIMIT_REQUEST_FIELDS
+#define DEFAULT_LIMIT_REQUEST_FIELDS 100
+#endif /* default limit on number of request header fields */
+
+/*
+ * The default default character set name to add if AddDefaultCharset is 
+ * enabled.  Overridden with AddDefaultCharsetName.
+ */
+#define DEFAULT_ADD_DEFAULT_CHARSET_NAME "iso-8859-1"
+
+/*
+ * The below defines the base string of the Server: header. Additional
+ * tokens can be added via the ap_add_version_component() API call.
+ *
+ * The tokens are listed in order of their significance for identifying the
+ * application.
+ *
+ * "Product tokens should be short and to the point -- use of them for 
+ * advertizing or other non-essential information is explicitly forbidden."
+ *
+ * Example: "Apache/1.1.0 MrWidget/0.1-alpha" 
+ */
+
+#define SERVER_BASEVENDOR   "Apache Group"
+#define SERVER_BASEPRODUCT  "Apache"
+#define SERVER_BASEREVISION "1.3.33"
+#define SERVER_BASEVERSION  SERVER_BASEPRODUCT "/" SERVER_BASEREVISION
+
+#define SERVER_PRODUCT  SERVER_BASEPRODUCT
+#define SERVER_REVISION SERVER_BASEREVISION
+#define SERVER_VERSION  SERVER_PRODUCT "/" SERVER_REVISION
+enum server_token_type {
+    SrvTk_MIN,		/* eg: Apache/1.3.0 */
+    SrvTk_OS,		/* eg: Apache/1.3.0 (UNIX) */
+    SrvTk_FULL,		/* eg: Apache/1.3.0 (UNIX) PHP/3.0 FooBar/1.2b */
+    SrvTk_PRODUCT_ONLY	/* eg: Apache */
+};
+
+API_EXPORT(const char *) ap_get_server_version(void);
+API_EXPORT(void) ap_add_version_component(const char *component);
+API_EXPORT(const char *) ap_get_server_built(void);
+
+/* Numeric release version identifier: MMNNFFRBB: major minor fix final beta
+ * Always increases along the same track as the source branch.
+ * For example, Apache 1.4.2 would be '10402100', 2.5b7 would be '20500007'.
+ */
+#define APACHE_RELEASE 10333100
+
+#define SERVER_PROTOCOL "HTTP/1.1"
+#ifndef SERVER_SUPPORT
+#define SERVER_SUPPORT "http://www.apache.org/"
+#endif
+
+#define DECLINED -1		/* Module declines to handle */
+#define DONE -2			/* Module has served the response completely 
+				 *  - it's safe to die() with no more output
+				 */
+#define OK 0			/* Module has handled this stage. */
+
+
+/* ----------------------- HTTP Status Codes  ------------------------- */
+
+/* The size of the static array in http_protocol.c for storing
+ * all of the potential response status-lines (a sparse table).
+ * A future version should dynamically generate the table at startup.
+ */
+#define RESPONSE_CODES 55
+
+#define HTTP_CONTINUE                      100
+#define HTTP_SWITCHING_PROTOCOLS           101
+#define HTTP_PROCESSING                    102
+#define HTTP_OK                            200
+#define HTTP_CREATED                       201
+#define HTTP_ACCEPTED                      202
+#define HTTP_NON_AUTHORITATIVE             203
+#define HTTP_NO_CONTENT                    204
+#define HTTP_RESET_CONTENT                 205
+#define HTTP_PARTIAL_CONTENT               206
+#define HTTP_MULTI_STATUS                  207
+#define HTTP_MULTIPLE_CHOICES              300
+#define HTTP_MOVED_PERMANENTLY             301
+#define HTTP_MOVED_TEMPORARILY             302
+#define HTTP_SEE_OTHER                     303
+#define HTTP_NOT_MODIFIED                  304
+#define HTTP_USE_PROXY                     305
+#define HTTP_TEMPORARY_REDIRECT            307
+#define HTTP_BAD_REQUEST                   400
+#define HTTP_UNAUTHORIZED                  401
+#define HTTP_PAYMENT_REQUIRED              402
+#define HTTP_FORBIDDEN                     403
+#define HTTP_NOT_FOUND                     404
+#define HTTP_METHOD_NOT_ALLOWED            405
+#define HTTP_NOT_ACCEPTABLE                406
+#define HTTP_PROXY_AUTHENTICATION_REQUIRED 407
+#define HTTP_REQUEST_TIME_OUT              408
+#define HTTP_CONFLICT                      409
+#define HTTP_GONE                          410
+#define HTTP_LENGTH_REQUIRED               411
+#define HTTP_PRECONDITION_FAILED           412
+#define HTTP_REQUEST_ENTITY_TOO_LARGE      413
+#define HTTP_REQUEST_URI_TOO_LARGE         414
+#define HTTP_UNSUPPORTED_MEDIA_TYPE        415
+#define HTTP_RANGE_NOT_SATISFIABLE         416
+#define HTTP_EXPECTATION_FAILED            417
+#define HTTP_UNPROCESSABLE_ENTITY          422
+#define HTTP_LOCKED                        423
+#define HTTP_FAILED_DEPENDENCY             424
+#define HTTP_INTERNAL_SERVER_ERROR         500
+#define HTTP_NOT_IMPLEMENTED               501
+#define HTTP_BAD_GATEWAY                   502
+#define HTTP_SERVICE_UNAVAILABLE           503
+#define HTTP_GATEWAY_TIME_OUT              504
+#define HTTP_VERSION_NOT_SUPPORTED         505
+#define HTTP_VARIANT_ALSO_VARIES           506
+#define HTTP_INSUFFICIENT_STORAGE          507
+#define HTTP_NOT_EXTENDED                  510
+
+#define DOCUMENT_FOLLOWS    HTTP_OK
+#define PARTIAL_CONTENT     HTTP_PARTIAL_CONTENT
+#define MULTIPLE_CHOICES    HTTP_MULTIPLE_CHOICES
+#define MOVED               HTTP_MOVED_PERMANENTLY
+#define REDIRECT            HTTP_MOVED_TEMPORARILY
+#define USE_LOCAL_COPY      HTTP_NOT_MODIFIED
+#define BAD_REQUEST         HTTP_BAD_REQUEST
+#define AUTH_REQUIRED       HTTP_UNAUTHORIZED
+#define FORBIDDEN           HTTP_FORBIDDEN
+#define NOT_FOUND           HTTP_NOT_FOUND
+#define METHOD_NOT_ALLOWED  HTTP_METHOD_NOT_ALLOWED
+#define NOT_ACCEPTABLE      HTTP_NOT_ACCEPTABLE
+#define LENGTH_REQUIRED     HTTP_LENGTH_REQUIRED
+#define PRECONDITION_FAILED HTTP_PRECONDITION_FAILED
+#define SERVER_ERROR        HTTP_INTERNAL_SERVER_ERROR
+#define NOT_IMPLEMENTED     HTTP_NOT_IMPLEMENTED
+#define BAD_GATEWAY         HTTP_BAD_GATEWAY
+#define VARIANT_ALSO_VARIES HTTP_VARIANT_ALSO_VARIES
+
+#define ap_is_HTTP_INFO(x)         (((x) >= 100)&&((x) < 200))
+#define ap_is_HTTP_SUCCESS(x)      (((x) >= 200)&&((x) < 300))
+#define ap_is_HTTP_REDIRECT(x)     (((x) >= 300)&&((x) < 400))
+#define ap_is_HTTP_ERROR(x)        (((x) >= 400)&&((x) < 600))
+#define ap_is_HTTP_CLIENT_ERROR(x) (((x) >= 400)&&((x) < 500))
+#define ap_is_HTTP_SERVER_ERROR(x) (((x) >= 500)&&((x) < 600))
+
+#define ap_status_drops_connection(x) \
+                                   (((x) == HTTP_BAD_REQUEST)           || \
+                                    ((x) == HTTP_REQUEST_TIME_OUT)      || \
+                                    ((x) == HTTP_LENGTH_REQUIRED)       || \
+                                    ((x) == HTTP_REQUEST_ENTITY_TOO_LARGE) || \
+                                    ((x) == HTTP_REQUEST_URI_TOO_LARGE) || \
+                                    ((x) == HTTP_INTERNAL_SERVER_ERROR) || \
+                                    ((x) == HTTP_SERVICE_UNAVAILABLE) || \
+				    ((x) == HTTP_NOT_IMPLEMENTED))
+
+/* Methods recognized (but not necessarily handled) by the server.
+ * These constants are used in bit shifting masks of size int, so it is
+ * unsafe to have more methods than bits in an int.  HEAD == M_GET.
+ */
+#define M_GET        0
+#define M_PUT        1
+#define M_POST       2
+#define M_DELETE     3
+#define M_CONNECT    4
+#define M_OPTIONS    5
+#define M_TRACE      6
+#define M_PATCH      7
+#define M_PROPFIND   8
+#define M_PROPPATCH  9
+#define M_MKCOL     10
+#define M_COPY      11
+#define M_MOVE      12
+#define M_LOCK      13
+#define M_UNLOCK    14
+#define M_INVALID   15
+
+#define METHODS     16
+
+#define CGI_MAGIC_TYPE "application/x-httpd-cgi"
+#define INCLUDES_MAGIC_TYPE "text/x-server-parsed-html"
+#define INCLUDES_MAGIC_TYPE3 "text/x-server-parsed-html3"
+#ifdef CHARSET_EBCDIC
+#define ASCIITEXT_MAGIC_TYPE_PREFIX "text/x-ascii-" /* Text files whose content-type starts with this are passed thru unconverted */
+#endif /*CHARSET_EBCDIC*/
+#define MAP_FILE_MAGIC_TYPE "application/x-type-map"
+#define ASIS_MAGIC_TYPE "httpd/send-as-is"
+#define DIR_MAGIC_TYPE "httpd/unix-directory"
+#define STATUS_MAGIC_TYPE "application/x-httpd-status"
+
+/*
+ * Define the HTML doctype strings centrally.
+ */
+#define DOCTYPE_HTML_2_0  "<!DOCTYPE HTML PUBLIC \"-//IETF//" \
+                          "DTD HTML 2.0//EN\">\n"
+#define DOCTYPE_HTML_3_2  "<!DOCTYPE HTML PUBLIC \"-//W3C//" \
+                          "DTD HTML 3.2 Final//EN\">\n"
+#define DOCTYPE_HTML_4_0S "<!DOCTYPE HTML PUBLIC \"-//W3C//" \
+                          "DTD HTML 4.0//EN\"\n" \
+                          "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
+#define DOCTYPE_HTML_4_0T "<!DOCTYPE HTML PUBLIC \"-//W3C//" \
+                          "DTD HTML 4.0 Transitional//EN\"\n" \
+                          "\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n"
+#define DOCTYPE_HTML_4_0F "<!DOCTYPE HTML PUBLIC \"-//W3C//" \
+                          "DTD HTML 4.0 Frameset//EN\"\n" \
+                          "\"http://www.w3.org/TR/REC-html40/frameset.dtd\">\n"
+
+/* Just in case your linefeed isn't the one the other end is expecting. */
+#ifndef CHARSET_EBCDIC
+#define LF 10
+#define CR 13
+#define CRLF "\015\012"
+#define OS_ASC(c) (c)
+#else /* CHARSET_EBCDIC */
+#include "ap_ebcdic.h"
+/* OSD_POSIX uses the EBCDIC charset. The transition ASCII->EBCDIC is done in
+ * the buff package (bread/bputs/bwrite), so everywhere else, we use
+ * "native EBCDIC" CR and NL characters. These are therefore defined as
+ * '\r' and '\n'.
+ * NB: this is not the whole truth - sometimes \015 and \012 are contained
+ * in literal (EBCDIC!) strings, so these are not converted but passed.
+ */
+#define CR '\r'
+#define LF '\n'
+#define CRLF "\r\n"
+#define OS_ASC(c) (os_toascii[c])
+#endif /* CHARSET_EBCDIC */
+
+/* Possible values for request_rec.read_body (set by handling module):
+ *    REQUEST_NO_BODY          Send 413 error if message has any body
+ *    REQUEST_CHUNKED_ERROR    Send 411 error if body without Content-Length
+ *    REQUEST_CHUNKED_DECHUNK  If chunked, remove the chunks for me.
+ *    REQUEST_CHUNKED_PASS     Pass the chunks to me without removal.
+ */
+#define REQUEST_NO_BODY          0
+#define REQUEST_CHUNKED_ERROR    1
+#define REQUEST_CHUNKED_DECHUNK  2
+#define REQUEST_CHUNKED_PASS     3
+
+/* Things which may vary per file-lookup WITHIN a request ---
+ * e.g., state of MIME config.  Basically, the name of an object, info
+ * about the object, and any other info we may ahve which may need to
+ * change as we go poking around looking for it (e.g., overridden by
+ * .htaccess files).
+ *
+ * Note how the default state of almost all these things is properly
+ * zero, so that allocating it with pcalloc does the right thing without
+ * a whole lot of hairy initialization... so long as we are willing to
+ * make the (fairly) portable assumption that the bit pattern of a NULL
+ * pointer is, in fact, zero.
+ */
+
+/* This represents the result of calling htaccess; these are cached for
+ * each request.
+ */
+struct htaccess_result {
+    char *dir;			/* the directory to which this applies */
+    int override;		/* the overrides allowed for the .htaccess file */
+    void *htaccess;		/* the configuration directives */
+/* the next one, or NULL if no more; N.B. never change this */
+    const struct htaccess_result *next;
+};
+
+typedef struct conn_rec conn_rec;
+typedef struct server_rec server_rec;
+typedef struct request_rec request_rec;
+typedef struct listen_rec listen_rec;
+
+#include "util_uri.h"
+
+enum proxyreqtype {
+    NOT_PROXY=0,
+    STD_PROXY,
+    PROXY_PASS
+};
+
+struct request_rec {
+
+    ap_pool *pool;
+    conn_rec *connection;
+    server_rec *server;
+
+    request_rec *next;		/* If we wind up getting redirected,
+				 * pointer to the request we redirected to.
+				 */
+    request_rec *prev;		/* If this is an internal redirect,
+				 * pointer to where we redirected *from*.
+				 */
+
+    request_rec *main;		/* If this is a sub_request (see request.h) 
+				 * pointer back to the main request.
+				 */
+
+    /* Info about the request itself... we begin with stuff that only
+     * protocol.c should ever touch...
+     */
+
+    char *the_request;		/* First line of request, so we can log it */
+    int assbackwards;		/* HTTP/0.9, "simple" request */
+    enum proxyreqtype proxyreq;/* A proxy request (calculated during
+				 * post_read_request or translate_name) */
+    int header_only;		/* HEAD request, as opposed to GET */
+    char *protocol;		/* Protocol, as given to us, or HTTP/0.9 */
+    int proto_num;		/* Number version of protocol; 1.1 = 1001 */
+    const char *hostname;	/* Host, as set by full URI or Host: */
+
+    time_t request_time;	/* When the request started */
+
+    const char *status_line;	/* Status line, if set by script */
+    int status;			/* In any case */
+
+    /* Request method, two ways; also, protocol, etc..  Outside of protocol.c,
+     * look, but don't touch.
+     */
+
+    const char *method;		/* GET, HEAD, POST, etc. */
+    int method_number;		/* M_GET, M_POST, etc. */
+
+    /*
+	allowed is a bitvector of the allowed methods.
+
+	A handler must ensure that the request method is one that
+	it is capable of handling.  Generally modules should DECLINE
+	any request methods they do not handle.  Prior to aborting the
+	handler like this the handler should set r->allowed to the list
+	of methods that it is willing to handle.  This bitvector is used
+	to construct the "Allow:" header required for OPTIONS requests,
+	and METHOD_NOT_ALLOWED and NOT_IMPLEMENTED status codes.
+
+	Since the default_handler deals with OPTIONS, all modules can
+	usually decline to deal with OPTIONS.  TRACE is always allowed,
+	modules don't need to set it explicitly.
+
+	Since the default_handler will always handle a GET, a
+	module which does *not* implement GET should probably return
+	METHOD_NOT_ALLOWED.  Unfortunately this means that a Script GET
+	handler can't be installed by mod_actions.
+    */
+    int allowed;		/* Allowed methods - for 405, OPTIONS, etc */
+
+    int sent_bodyct;		/* byte count in stream is for body */
+    long bytes_sent;		/* body byte count, for easy access */
+    time_t mtime;		/* Time the resource was last modified */
+
+    /* HTTP/1.1 connection-level features */
+
+    int chunked;		/* sending chunked transfer-coding */
+    int byterange;		/* number of byte ranges */
+    char *boundary;		/* multipart/byteranges boundary */
+    const char *range;		/* The Range: header */
+    long clength;		/* The "real" content length */
+
+    long remaining;		/* bytes left to read */
+    long read_length;		/* bytes that have been read */
+    int read_body;		/* how the request body should be read */
+    int read_chunked;		/* reading chunked transfer-coding */
+    unsigned expecting_100;	/* is client waiting for a 100 response? */
+
+    /* MIME header environments, in and out.  Also, an array containing
+     * environment variables to be passed to subprocesses, so people can
+     * write modules to add to that environment.
+     *
+     * The difference between headers_out and err_headers_out is that the
+     * latter are printed even on error, and persist across internal redirects
+     * (so the headers printed for ErrorDocument handlers will have them).
+     *
+     * The 'notes' table is for notes from one module to another, with no
+     * other set purpose in mind...
+     */
+
+    table *headers_in;
+    table *headers_out;
+    table *err_headers_out;
+    table *subprocess_env;
+    table *notes;
+
+    /* content_type, handler, content_encoding, content_language, and all
+     * content_languages MUST be lowercased strings.  They may be pointers
+     * to static strings; they should not be modified in place.
+     */
+    const char *content_type;	/* Break these out --- we dispatch on 'em */
+    const char *handler;	/* What we *really* dispatch on           */
+
+    const char *content_encoding;
+    const char *content_language;	/* for back-compat. only -- do not use */
+    array_header *content_languages;	/* array of (char*) */
+
+    char *vlist_validator;      /* variant list validator (if negotiated) */
+
+    int no_cache;
+    int no_local_copy;
+
+    /* What object is being requested (either directly, or via include
+     * or content-negotiation mapping).
+     */
+
+    char *unparsed_uri;		/* the uri without any parsing performed */
+    char *uri;			/* the path portion of the URI */
+    char *filename;		/* filename if found, otherwise NULL */
+    char *path_info;
+    char *args;			/* QUERY_ARGS, if any */
+    struct stat finfo;		/* ST_MODE set to zero if no such file */
+    uri_components parsed_uri;	/* components of uri, dismantled */
+
+    /* Various other config info which may change with .htaccess files
+     * These are config vectors, with one void* pointer for each module
+     * (the thing pointed to being the module's business).
+     */
+
+    void *per_dir_config;	/* Options set in config files, etc. */
+    void *request_config;	/* Notes on *this* request */
+
+/*
+ * a linked list of the configuration directives in the .htaccess files
+ * accessed by this request.
+ * N.B. always add to the head of the list, _never_ to the end.
+ * that way, a sub request's list can (temporarily) point to a parent's list
+ */
+    const struct htaccess_result *htaccess;
+
+    /* On systems with case insensitive file systems (Windows, OS/2, etc.), 
+     * r->filename is case canonicalized (folded to either lower or upper 
+     * case, depending on the specific system) to accomodate file access
+     * checking. case_preserved_filename is the same as r->filename 
+     * except case is preserved. There is at least one instance where Apache 
+     * needs access to the case preserved filename: Java class files published 
+     * with WebDAV need to preserve filename case to make the Java compiler 
+     * happy.
+     */
+    char *case_preserved_filename;
+
+#ifdef CHARSET_EBCDIC
+    /* We don't want subrequests to modify our current conversion flags.
+     * These flags save the state of the conversion flags when subrequests
+     * are run.
+     */
+    struct {
+        unsigned conv_in:1;    /* convert ASCII->EBCDIC when read()ing? */
+        unsigned conv_out:1;   /* convert EBCDIC->ASCII when write()ing? */
+    } ebcdic;
+#endif
+
+/* Things placed at the end of the record to avoid breaking binary
+ * compatibility.  It would be nice to remember to reorder the entire
+ * record to improve 64bit alignment the next time we need to break
+ * binary compatibility for some other reason.
+ */
+};
+
+
+/* Things which are per connection
+ */
+
+struct conn_rec {
+
+    ap_pool *pool;
+    server_rec *server;
+    server_rec *base_server;	/* Physical vhost this conn come in on */
+    void *vhost_lookup_data;	/* used by http_vhost.c */
+
+    /* Information about the connection itself */
+
+    int child_num;		/* The number of the child handling conn_rec */
+    BUFF *client;		/* Connection to the guy */
+
+    /* Who is the client? */
+
+    struct sockaddr_in local_addr;	/* local address */
+    struct sockaddr_in remote_addr;	/* remote address */
+    char *remote_ip;		/* Client's IP address */
+    char *remote_host;		/* Client's DNS name, if known.
+				 * NULL if DNS hasn't been checked,
+				 * "" if it has and no address was found.
+				 * N.B. Only access this though
+				 * get_remote_host() */
+    char *remote_logname;	/* Only ever set if doing rfc1413 lookups.
+				 * N.B. Only access this through
+				 * get_remote_logname() */
+    char *user;			/* If an authentication check was made,
+				 * this gets set to the user name.  We assume
+				 * that there's only one user per connection(!)
+				 */
+    char *ap_auth_type;		/* Ditto. */
+
+    unsigned aborted:1;		/* Are we still talking? */
+    signed int keepalive:2;	/* Are we using HTTP Keep-Alive?
+				 * -1 fatal error, 0 undecided, 1 yes */
+    unsigned keptalive:1;	/* Did we use HTTP Keep-Alive? */
+    signed int double_reverse:2;/* have we done double-reverse DNS?
+				 * -1 yes/failure, 0 not yet, 1 yes/success */
+    int keepalives;		/* How many times have we used it? */
+    char *local_ip;		/* server IP address */
+    char *local_host;		/* used for ap_get_server_name when
+				 * UseCanonicalName is set to DNS
+				 * (ignores setting of HostnameLookups) */
+};
+
+/* Per-vhost config... */
+
+/* The address 255.255.255.255, when used as a virtualhost address,
+ * will become the "default" server when the ip doesn't match other vhosts.
+ */
+#define DEFAULT_VHOST_ADDR 0xfffffffful
+
+typedef struct server_addr_rec server_addr_rec;
+struct server_addr_rec {
+    server_addr_rec *next;
+    struct in_addr host_addr;	/* The bound address, for this server */
+    unsigned short host_port;	/* The bound port, for this server */
+    char *virthost;		/* The name given in <VirtualHost> */
+};
+
+struct server_rec {
+
+    server_rec *next;
+
+    /* description of where the definition came from */
+    const char *defn_name;
+    unsigned defn_line_number;
+
+    /* Full locations of server config info */
+
+    char *srm_confname;
+    char *access_confname;
+
+    /* Contact information */
+
+    char *server_admin;
+    char *server_hostname;
+    unsigned short port;	/* for redirects, etc. */
+
+    /* Log files --- note that transfer log is now in the modules... */
+
+    char *error_fname;
+    FILE *error_log;
+    int loglevel;
+
+    /* Module-specific configuration for server, and defaults... */
+
+    int is_virtual;		/* true if this is the virtual server */
+    void *module_config;	/* Config vector containing pointers to
+				 * modules' per-server config structures.
+				 */
+    void *lookup_defaults;	/* MIME type info, etc., before we start
+				 * checking per-directory info.
+				 */
+    /* Transaction handling */
+
+    server_addr_rec *addrs;
+    int timeout;		/* Timeout, in seconds, before we give up */
+    int keep_alive_timeout;	/* Seconds we'll wait for another request */
+    int keep_alive_max;		/* Maximum requests per connection */
+    int keep_alive;		/* Use persistent connections? */
+    int send_buffer_size;	/* size of TCP send buffer (in bytes) */
+
+    char *path;			/* Pathname for ServerPath */
+    int pathlen;		/* Length of path */
+
+    array_header *names;	/* Normal names for ServerAlias servers */
+    array_header *wild_names;	/* Wildcarded names for ServerAlias servers */
+
+    uid_t server_uid;        /* effective user id when calling exec wrapper */
+    gid_t server_gid;        /* effective group id when calling exec wrapper */
+
+    int limit_req_line;      /* limit on size of the HTTP request line    */
+    int limit_req_fieldsize; /* limit on size of any request header field */
+    int limit_req_fields;    /* limit on number of request header fields  */
+};
+
+/* These are more like real hosts than virtual hosts */
+struct listen_rec {
+    listen_rec *next;
+    struct sockaddr_in local_addr;	/* local IP address and port */
+    int fd;
+    int used;			/* Only used during restart */        
+/* more stuff here, like which protocol is bound to the port */
+};
+
+/* Prototypes for utilities... util.c.
+ */
+
+extern void ap_util_init(void);
+
+/* Time */
+extern API_VAR_EXPORT const char ap_month_snames[12][4];
+extern API_VAR_EXPORT const char ap_day_snames[7][4];
+
+API_EXPORT(struct tm *) ap_get_gmtoff(int *tz);
+API_EXPORT(char *) ap_get_time(void);
+API_EXPORT(char *) ap_field_noparam(pool *p, const char *intype);
+API_EXPORT(char *) ap_ht_time(pool *p, time_t t, const char *fmt, int gmt);
+API_EXPORT(char *) ap_gm_timestr_822(pool *p, time_t t);
+
+/* String handling. The *_nc variants allow you to use non-const char **s as
+   arguments (unfortunately C won't automatically convert a char ** to a const
+   char **) */
+
+API_EXPORT(char *) ap_getword(pool *p, const char **line, char stop);
+API_EXPORT(char *) ap_getword_nc(pool *p, char **line, char stop);
+API_EXPORT(char *) ap_getword_white(pool *p, const char **line);
+API_EXPORT(char *) ap_getword_white_nc(pool *p, char **line);
+API_EXPORT(char *) ap_getword_nulls(pool *p, const char **line, char stop);
+API_EXPORT(char *) ap_getword_nulls_nc(pool *p, char **line, char stop);
+API_EXPORT(char *) ap_getword_conf(pool *p, const char **line);
+API_EXPORT(char *) ap_getword_conf_nc(pool *p, char **line);
+
+API_EXPORT(const char *) ap_size_list_item(const char **field, int *len);
+API_EXPORT(char *) ap_get_list_item(pool *p, const char **field);
+API_EXPORT(int) ap_find_list_item(pool *p, const char *line, const char *tok);
+
+API_EXPORT(char *) ap_get_token(pool *p, const char **accept_line, int accept_white);
+API_EXPORT(int) ap_find_token(pool *p, const char *line, const char *tok);
+API_EXPORT(int) ap_find_last_token(pool *p, const char *line, const char *tok);
+
+API_EXPORT(int) ap_is_url(const char *u);
+API_EXPORT(int) ap_unescape_url(char *url);
+API_EXPORT(void) ap_no2slash(char *name);
+API_EXPORT(void) ap_getparents(char *name);
+API_EXPORT(char *) ap_escape_path_segment(pool *p, const char *s);
+API_EXPORT(char *) ap_os_escape_path(pool *p, const char *path, int partial);
+#define ap_escape_uri(ppool,path) ap_os_escape_path(ppool,path,1)
+API_EXPORT(char *) ap_escape_html(pool *p, const char *s);
+API_EXPORT(char *) ap_construct_server(pool *p, const char *hostname,
+				    unsigned port, const request_rec *r);
+API_EXPORT(char *) ap_escape_logitem(pool *p, const char *str);
+API_EXPORT(size_t) ap_escape_errorlog_item(char *dest, const char *source,
+                                           size_t buflen);
+API_EXPORT(char *) ap_escape_shell_cmd(pool *p, const char *s);
+
+API_EXPORT(int) ap_count_dirs(const char *path);
+API_EXPORT(char *) ap_make_dirstr_prefix(char *d, const char *s, int n);
+API_EXPORT(char *) ap_make_dirstr_parent(pool *p, const char *s);
+/* deprecated.  The previous two routines are preferred. */
+API_EXPORT(char *) ap_make_dirstr(pool *a, const char *s, int n);
+API_EXPORT(char *) ap_make_full_path(pool *a, const char *dir, const char *f);
+
+API_EXPORT(int) ap_is_matchexp(const char *str);
+API_EXPORT(int) ap_strcmp_match(const char *str, const char *exp);
+API_EXPORT(int) ap_strcasecmp_match(const char *str, const char *exp);
+API_EXPORT(char *) ap_stripprefix(const char *bigstring, const char *prefix);
+API_EXPORT(char *) ap_strcasestr(const char *s1, const char *s2);
+API_EXPORT(char *) ap_pbase64decode(pool *p, const char *bufcoded);
+API_EXPORT(char *) ap_pbase64encode(pool *p, char *string); 
+API_EXPORT(char *) ap_uudecode(pool *p, const char *bufcoded);
+API_EXPORT(char *) ap_uuencode(pool *p, char *string); 
+
+#if defined(OS2) || defined(WIN32)
+API_EXPORT(char *) ap_double_quotes(pool *p, const char *str);
+API_EXPORT(char *) ap_caret_escape_args(pool *p, const char *str);
+#endif
+
+#ifdef OS2
+void os2pathname(char *path);
+#endif
+
+API_EXPORT(int)    ap_regexec(const regex_t *preg, const char *string,
+                              size_t nmatch, regmatch_t pmatch[], int eflags);
+API_EXPORT(size_t) ap_regerror(int errcode, const regex_t *preg, 
+                               char *errbuf, size_t errbuf_size);
+API_EXPORT(char *) ap_pregsub(pool *p, const char *input, const char *source,
+                              size_t nmatch, regmatch_t pmatch[]);
+
+API_EXPORT(void) ap_content_type_tolower(char *);
+API_EXPORT(void) ap_str_tolower(char *);
+API_EXPORT(int) ap_ind(const char *, char);	/* Sigh... */
+API_EXPORT(int) ap_rind(const char *, char);
+
+API_EXPORT(char *) ap_escape_quotes (pool *p, const char *instring);
+API_EXPORT(void) ap_remove_spaces(char *dest, char *src);
+
+/* Common structure for reading of config files / passwd files etc. */
+typedef struct {
+    int (*getch) (void *param);	/* a getc()-like function */
+    void *(*getstr) (void *buf, size_t bufsiz, void *param); /* a fgets()-like function */
+    int (*close) (void *param);	/* a close hander function */
+    void *param;		/* the argument passed to getch/getstr/close */
+    const char *name;		/* the filename / description */
+    unsigned line_number;	/* current line number, starting at 1 */
+} configfile_t;
+
+/* Open a configfile_t as FILE, return open configfile_t struct pointer */
+API_EXPORT(configfile_t *) ap_pcfg_openfile(pool *p, const char *name);
+
+/* Allocate a configfile_t handle with user defined functions and params */
+API_EXPORT(configfile_t *) ap_pcfg_open_custom(pool *p, const char *descr,
+    void *param,
+    int(*getc_func)(void*),
+    void *(*gets_func) (void *buf, size_t bufsiz, void *param),
+    int(*close_func)(void *param));
+
+/* Read one line from open configfile_t, strip LF, increase line number */
+API_EXPORT(int) ap_cfg_getline(char *buf, size_t bufsize, configfile_t *cfp);
+
+/* Read one char from open configfile_t, increase line number upon LF */
+API_EXPORT(int) ap_cfg_getc(configfile_t *cfp);
+
+/* Detach from open configfile_t, calling the close handler */
+API_EXPORT(int) ap_cfg_closefile(configfile_t *cfp);
+
+#ifdef NEED_STRERROR
+char *strerror(int err);
+#endif
+
+/* Misc system hackery */
+
+API_EXPORT(uid_t) ap_uname2id(const char *name);
+API_EXPORT(gid_t) ap_gname2id(const char *name);
+API_EXPORT(int) ap_is_directory(const char *name);
+API_EXPORT(int) ap_is_rdirectory(const char *name);
+API_EXPORT(int) ap_can_exec(const struct stat *);
+API_EXPORT(void) ap_chdir_file(const char *file);
+
+#ifndef HAVE_CANONICAL_FILENAME
+/*
+ *  We can't define these in os.h because of dependence on pool pointer.
+ */
+#define ap_os_canonical_filename(p,f)  (f)
+#define ap_os_case_canonical_filename(p,f)  (f)
+#define ap_os_systemcase_filename(p,f)  (f)
+#else
+API_EXPORT(char *) ap_os_canonical_filename(pool *p, const char *file);
+#ifdef WIN32
+API_EXPORT(char *) ap_os_case_canonical_filename(pool *pPool, const char *szFile);
+API_EXPORT(char *) ap_os_systemcase_filename(pool *pPool, const char *szFile);
+#elif defined(OS2)
+API_EXPORT(char *) ap_os_case_canonical_filename(pool *pPool, const char *szFile);
+API_EXPORT(char *) ap_os_systemcase_filename(pool *pPool, const char *szFile);
+#elif defined(NETWARE)
+API_EXPORT(char *) ap_os_case_canonical_filename(pool *pPool, const char *szFile);
+#define ap_os_systemcase_filename(p,f) ap_os_case_canonical_filename(p,f)
+#else
+#define ap_os_case_canonical_filename(p,f) ap_os_canonical_filename(p,f)
+#define ap_os_systemcase_filename(p,f) ap_os_canonical_filename(p,f)
+#endif
+#endif
+
+#ifdef CHARSET_EBCDIC
+API_EXPORT(int)    ap_checkconv(struct request_rec *r);    /* for downloads */
+API_EXPORT(int)    ap_checkconv_in(struct request_rec *r); /* for uploads */
+#endif /*#ifdef CHARSET_EBCDIC*/
+
+API_EXPORT(char *) ap_get_local_host(pool *);
+API_EXPORT(unsigned long) ap_get_virthost_addr(char *hostname, unsigned short *port);
+
+extern API_VAR_EXPORT time_t ap_restart_time;
+
+/*
+ * Apache tries to keep all of its long term filehandles (such as log files,
+ * and sockets) above this number.  This is to workaround problems in many
+ * third party libraries that are compiled with a small FD_SETSIZE.  There
+ * should be no reason to lower this, because it's only advisory.  If a file
+ * can't be allocated above this number then it will remain in the "slack"
+ * area.
+ *
+ * Only the low slack line is used by default.  If HIGH_SLACK_LINE is defined
+ * then an attempt is also made to keep all non-FILE * files above the high
+ * slack line.  This is to work around a Solaris C library limitation, where it
+ * uses an unsigned char to store the file descriptor.
+ */
+#ifndef LOW_SLACK_LINE
+#define LOW_SLACK_LINE	15
+#endif
+/* #define HIGH_SLACK_LINE      255 */
+
+/*
+ * The ap_slack() function takes a fd, and tries to move it above the indicated
+ * line.  It returns an fd which may or may not have moved above the line, and
+ * never fails.  If the high line was requested and it fails it will also try
+ * the low line.
+ */
+#ifdef NO_SLACK
+#define ap_slack(fd,line)   (fd)
+#else
+int ap_slack(int fd, int line);
+#define AP_SLACK_LOW	1
+#define AP_SLACK_HIGH	2
+#endif
+
+API_EXPORT(char *) ap_escape_quotes(pool *p, const char *instr);
+
+/*
+ * Redefine assert() to something more useful for an Apache...
+ */
+API_EXPORT(void) ap_log_assert(const char *szExp, const char *szFile, int nLine)
+			    __attribute__((noreturn));
+#define ap_assert(exp) ((exp) ? (void)0 : ap_log_assert(#exp,__FILE__,__LINE__))
+
+/* The optimized timeout code only works if we're not MULTITHREAD and we're
+ * also not using a scoreboard file
+ */
+#if !defined (MULTITHREAD) && \
+    (defined (USE_MMAP_SCOREBOARD) || defined (USE_SHMGET_SCOREBOARD))
+#define OPTIMIZE_TIMEOUTS
+#endif
+
+/* A set of flags which indicate places where the server should raise(SIGSTOP).
+ * This is useful for debugging, because you can then attach to that process
+ * with gdb and continue.  This is important in cases where one_process
+ * debugging isn't possible.
+ */
+#define SIGSTOP_DETACH			1
+#define SIGSTOP_MAKE_CHILD		2
+#define SIGSTOP_SPAWN_CHILD		4
+#define SIGSTOP_PIPED_LOG_SPAWN		8
+#define SIGSTOP_CGI_CHILD		16
+
+#ifdef DEBUG_SIGSTOP
+extern int raise_sigstop_flags;
+#define RAISE_SIGSTOP(x)	do { \
+	if (raise_sigstop_flags & SIGSTOP_##x) raise(SIGSTOP);\
+    } while (0)
+#else
+#define RAISE_SIGSTOP(x)
+#endif
+
+API_EXPORT(extern const char *) ap_psignature(const char *prefix, request_rec *r);
+
+/* strtoul does not exist on sunos4. */
+#ifdef strtoul
+#undef strtoul
+#endif
+#define strtoul strtoul_is_not_a_portable_function_use_strtol_instead
+
+#ifdef AP_ENABLE_EXCEPTION_HOOK
+/* The exception hook allows a module to run from the server's signal
+ * handler, and perform tasks such as logging the current request or
+ * getting a backtrace or performing other diagnostic functions.  All
+ * operating system requirements for running in a signal handler must
+ * be respected, or the process may not exit properly.
+ *
+ * AP_ENABLE_EXCEPTION_HOOK is already defined for platforms that have
+ * been tested.  It likely will work on other platforms.  In order to
+ * test, define AP_ENABLE_EXCEPTION_HOOK at configure time.
+ */
+typedef struct ap_exception_info_t {
+    int sig;
+    pid_t pid;
+} ap_exception_info_t;
+
+/* Register a function to be called after a fatal exception (on *X systems, a
+ * "synchronous signal" such as SIGSEGV, SIGILL, etc.).
+ *
+ * Returns 0 on success, non-zero on failure.
+ * If EnableExceptionHook directive is not set to "on", this function will
+ * report failure and no such hooks will be called.
+ */
+API_EXPORT(extern int) ap_add_fatal_exception_hook(void (*fn)(ap_exception_info_t *));
+#endif /* AP_ENABLE_EXCEPTION_HOOK */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* !APACHE_HTTPD_H */
diff -udrN apache_1.3.33/src/main/http_core.c apache_1.3.33-mod/src/main/http_core.c
--- apache_1.3.33/src/main/http_core.c	Thu Sep 30 03:23:35 2004
+++ apache_1.3.33-mod/src/main/http_core.c	Fri Apr  1 10:08:13 2005
@@ -4181,15 +4181,15 @@
 		ap_send_fd(f, r);
 	    }
 	    else {
-		long offset, length;
+		int64_t offset, length;
 		while (ap_each_byterange(r, &offset, &length)) {
 		    /*
 		     * Non zero returns are more portable than checking
 		     * for a return of -1.
 		     */
-		    if (fseek(f, offset, SEEK_SET)) {
+		    if (fseeko(f, offset, SEEK_SET)) {
 			ap_log_error(APLOG_MARK, APLOG_ERR, r->server,
-			      "Failed to fseek for byterange (%ld, %ld): %s",
+			      "Failed to fseeko for byterange (%qd, %qd): %s",
 			      offset, length, r->filename);
 		    }
 		    else {
@@ -4227,7 +4227,7 @@
 		ap_send_mmap(mm, r, 0, r->finfo.st_size);
 	    }
 	    else {
-		long offset, length;
+		int64_t offset, length;
 		while (ap_each_byterange(r, &offset, &length)) {
 		    ap_send_mmap(mm, r, offset, length);
 		}
diff -udrN apache_1.3.33/src/main/http_core.c.orig apache_1.3.33-mod/src/main/http_core.c.orig
--- apache_1.3.33/src/main/http_core.c.orig	Wed Dec 31 16:00:00 1969
+++ apache_1.3.33-mod/src/main/http_core.c.orig	Thu Sep 30 03:23:35 2004
@@ -0,0 +1,4269 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define CORE_PRIVATE
+#define ADD_EBCDICCONVERT_DEBUG_HEADER 0
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_protocol.h"	/* For index_of_response().  Grump. */
+#include "http_request.h"
+#include "http_conf_globals.h"
+#include "http_vhost.h"
+#include "http_main.h"		/* For the default_handler below... */
+#include "http_log.h"
+#include "rfc1413.h"
+#include "util_md5.h"
+#include "scoreboard.h"
+#include "fnmatch.h"
+
+#ifdef USE_MMAP_FILES
+#include <sys/mman.h>
+
+/* mmap support for static files based on ideas from John Heidemann's
+ * patch against 1.0.5.  See
+ * <http://www.isi.edu/~johnh/SOFTWARE/APACHE/index.html>.
+ */
+
+/* Files have to be at least this big before they're mmap()d.  This is to deal
+ * with systems where the expense of doing an mmap() and an munmap() outweighs
+ * the benefit for small files.  It shouldn't be set lower than 1.
+ */
+#ifndef MMAP_THRESHOLD
+#ifdef SUNOS4
+#define MMAP_THRESHOLD		(8*1024)
+#else
+#define MMAP_THRESHOLD		1
+#endif
+#endif
+#endif
+#ifndef MMAP_LIMIT
+#define MMAP_LIMIT              (4*1024*1024)
+#endif
+
+typedef struct {
+    /* Custom response strings registered via ap_custom_response(),
+     * or NULL; check per-dir config if nothing found here
+     */
+    char **response_code_strings; /* from ap_custom_response(), not from
+                                   * ErrorDocument
+                                   */
+} core_request_config;
+
+/* Server core module... This module provides support for really basic
+ * server operations, including options and commands which control the
+ * operation of other modules.  Consider this the bureaucracy module.
+ *
+ * The core module also defines handlers, etc., do handle just enough
+ * to allow a server with the core module ONLY to actually serve documents
+ * (though it slaps DefaultType on all of 'em); this was useful in testing,
+ * but may not be worth preserving.
+ *
+ * This file could almost be mod_core.c, except for the stuff which affects
+ * the http_conf_globals.
+ */
+
+static void *create_core_dir_config(pool *a, char *dir)
+{
+    core_dir_config *conf;
+
+    conf = (core_dir_config *)ap_pcalloc(a, sizeof(core_dir_config));
+    if (!dir || dir[strlen(dir) - 1] == '/') {
+        conf->d = dir;
+    }
+    else if (strncmp(dir, "proxy:", 6) == 0) {
+        conf->d = ap_pstrdup(a, dir);
+    }
+    else {
+        conf->d = ap_pstrcat(a, dir, "/", NULL);
+    }
+    conf->d_is_fnmatch = conf->d ? (ap_is_fnmatch(conf->d) != 0) : 0;
+    conf->d_components = conf->d ? ap_count_dirs(conf->d) : 0;
+
+    conf->opts = dir ? OPT_UNSET : OPT_UNSET|OPT_ALL;
+    conf->opts_add = conf->opts_remove = OPT_NONE;
+    conf->override = dir ? OR_UNSET : OR_UNSET|OR_ALL;
+
+    conf->content_md5 = 2;
+
+    conf->use_canonical_name = USE_CANONICAL_NAME_UNSET;
+
+    conf->hostname_lookups = HOSTNAME_LOOKUP_UNSET;
+    conf->do_rfc1413 = DEFAULT_RFC1413 | 2; /* set bit 1 to indicate default */
+    conf->satisfy = SATISFY_NOSPEC;
+
+#ifdef RLIMIT_CPU
+    conf->limit_cpu = NULL;
+#endif
+#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
+    conf->limit_mem = NULL;
+#endif
+#ifdef RLIMIT_NPROC
+    conf->limit_nproc = NULL;
+#endif
+
+    conf->limit_req_body = 0;
+    conf->sec = ap_make_array(a, 2, sizeof(void *));
+#ifdef WIN32
+    conf->script_interpreter_source = INTERPRETER_SOURCE_UNSET;
+#endif
+
+    conf->server_signature = srv_sig_unset;
+
+    conf->add_default_charset = ADD_DEFAULT_CHARSET_UNSET;
+    conf->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
+
+#ifdef CHARSET_EBCDIC
+    conf->ebcdicconversion_by_ext_in = ap_make_table(a, 4);
+    conf->ebcdicconversion_by_ext_out = ap_make_table(a, 4);
+    conf->ebcdicconversion_by_type_in = ap_make_table(a, 4);
+    conf->ebcdicconversion_by_type_out = ap_make_table(a, 4);
+    conf->x_ascii_magic_kludge = 0;
+#if ADD_EBCDICCONVERT_DEBUG_HEADER
+    conf->ebcdicconversion_debug_header = 0;
+#endif
+#endif /* CHARSET_EBCDIC */
+
+    /*
+     * Flag for use of inodes in ETags.
+     */
+    conf->etag_bits = ETAG_UNSET;
+    conf->etag_add = ETAG_UNSET;
+    conf->etag_remove = ETAG_UNSET;
+
+    return (void *)conf;
+}
+
+static void *merge_core_dir_configs(pool *a, void *basev, void *newv)
+{
+    core_dir_config *base = (core_dir_config *)basev;
+    core_dir_config *new = (core_dir_config *)newv;
+    core_dir_config *conf;
+    int i;
+  
+    conf = (core_dir_config *)ap_palloc(a, sizeof(core_dir_config));
+    memcpy((char *)conf, (const char *)base, sizeof(core_dir_config));
+    if (base->response_code_strings) {
+	conf->response_code_strings =
+	    ap_palloc(a, sizeof(*conf->response_code_strings)
+		      * RESPONSE_CODES);
+	memcpy(conf->response_code_strings, base->response_code_strings,
+	       sizeof(*conf->response_code_strings) * RESPONSE_CODES);
+    }
+    
+    conf->d = new->d;
+    conf->d_is_fnmatch = new->d_is_fnmatch;
+    conf->d_components = new->d_components;
+    conf->r = new->r;
+
+    if (new->opts & OPT_UNSET) {
+	/* there was no explicit setting of new->opts, so we merge
+	 * preserve the invariant (opts_add & opts_remove) == 0
+	 */
+	conf->opts_add = (conf->opts_add & ~new->opts_remove) | new->opts_add;
+	conf->opts_remove = (conf->opts_remove & ~new->opts_add)
+	                    | new->opts_remove;
+	conf->opts = (conf->opts & ~conf->opts_remove) | conf->opts_add;
+        if ((base->opts & OPT_INCNOEXEC) && (new->opts & OPT_INCLUDES)) {
+            conf->opts = (conf->opts & ~OPT_INCNOEXEC) | OPT_INCLUDES;
+	}
+    }
+    else {
+	/* otherwise we just copy, because an explicit opts setting
+	 * overrides all earlier +/- modifiers
+	 */
+	conf->opts = new->opts;
+	conf->opts_add = new->opts_add;
+	conf->opts_remove = new->opts_remove;
+    }
+
+    if (!(new->override & OR_UNSET)) {
+        conf->override = new->override;
+    }
+    if (new->ap_default_type) {
+        conf->ap_default_type = new->ap_default_type;
+    }
+    
+    if (new->ap_auth_type) {
+        conf->ap_auth_type = new->ap_auth_type;
+    }
+    if (new->ap_auth_name) {
+        conf->ap_auth_name = new->ap_auth_name;
+    }
+    if (new->ap_auth_nonce) {
+        conf->ap_auth_nonce = new->ap_auth_nonce;
+    }
+    if (new->ap_requires) {
+        conf->ap_requires = new->ap_requires;
+    }
+
+    if (new->response_code_strings) {
+	if (conf->response_code_strings == NULL) {
+	    conf->response_code_strings = ap_palloc(a,
+		sizeof(*conf->response_code_strings) * RESPONSE_CODES);
+	    memcpy(conf->response_code_strings, new->response_code_strings,
+		   sizeof(*conf->response_code_strings) * RESPONSE_CODES);
+	}
+	else {
+	    for (i = 0; i < RESPONSE_CODES; ++i) {
+	        if (new->response_code_strings[i] != NULL) {
+		    conf->response_code_strings[i]
+		        = new->response_code_strings[i];
+		}
+	    }
+	}
+    }
+    if (new->hostname_lookups != HOSTNAME_LOOKUP_UNSET) {
+	conf->hostname_lookups = new->hostname_lookups;
+    }
+    if ((new->do_rfc1413 & 2) == 0) {
+        conf->do_rfc1413 = new->do_rfc1413;
+    }
+    if ((new->content_md5 & 2) == 0) {
+        conf->content_md5 = new->content_md5;
+    }
+    if (new->use_canonical_name != USE_CANONICAL_NAME_UNSET) {
+	conf->use_canonical_name = new->use_canonical_name;
+    }
+
+#ifdef RLIMIT_CPU
+    if (new->limit_cpu) {
+        conf->limit_cpu = new->limit_cpu;
+    }
+#endif
+#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
+    if (new->limit_mem) {
+        conf->limit_mem = new->limit_mem;
+    }
+#endif
+#ifdef RLIMIT_NPROC    
+    if (new->limit_nproc) {
+        conf->limit_nproc = new->limit_nproc;
+    }
+#endif
+
+    if (new->limit_req_body) {
+        conf->limit_req_body = new->limit_req_body;
+    }
+    conf->sec = ap_append_arrays(a, base->sec, new->sec);
+
+    if (new->satisfy != SATISFY_NOSPEC) {
+        conf->satisfy = new->satisfy;
+    }
+
+#ifdef WIN32
+    if (new->script_interpreter_source != INTERPRETER_SOURCE_UNSET) {
+        conf->script_interpreter_source = new->script_interpreter_source;
+    }
+#endif
+
+    if (new->server_signature != srv_sig_unset) {
+	conf->server_signature = new->server_signature;
+    }
+
+    if (new->add_default_charset != ADD_DEFAULT_CHARSET_UNSET) {
+	conf->add_default_charset = new->add_default_charset;
+	if (new->add_default_charset_name) {
+	    conf->add_default_charset_name = new->add_default_charset_name;
+	}
+    }
+
+#ifdef CHARSET_EBCDIC
+    conf->ebcdicconversion_by_ext_in = ap_overlay_tables(a, new->ebcdicconversion_by_ext_in,
+                                               base->ebcdicconversion_by_ext_in);
+    conf->ebcdicconversion_by_ext_out = ap_overlay_tables(a, new->ebcdicconversion_by_ext_out,
+                                               base->ebcdicconversion_by_ext_out);
+    conf->ebcdicconversion_by_type_in = ap_overlay_tables(a, new->ebcdicconversion_by_type_in,
+                                                base->ebcdicconversion_by_type_in);
+    conf->ebcdicconversion_by_type_out = ap_overlay_tables(a, new->ebcdicconversion_by_type_out,
+                                                base->ebcdicconversion_by_type_out);
+    conf->x_ascii_magic_kludge = new->x_ascii_magic_kludge ? new->x_ascii_magic_kludge : base->x_ascii_magic_kludge;
+#if ADD_EBCDICCONVERT_DEBUG_HEADER
+    conf->ebcdicconversion_debug_header = new->ebcdicconversion_debug_header ? new->ebcdicconversion_debug_header : base->ebcdicconversion_debug_header;
+#endif
+#endif /* CHARSET_EBCDIC */
+
+    /*
+     * Now merge the setting of the FileETag directive.
+     */
+    if (new->etag_bits == ETAG_UNSET) {
+        conf->etag_add =
+            (conf->etag_add & (~ new->etag_remove)) | new->etag_add;
+        conf->etag_remove =
+            (conf->opts_remove & (~ new->etag_add)) | new->etag_remove;
+        conf->etag_bits =
+            (conf->etag_bits & (~ conf->etag_remove)) | conf->etag_add;
+    }
+    else {
+        conf->etag_bits = new->etag_bits;
+        conf->etag_add = new->etag_add;
+        conf->etag_remove = new->etag_remove;
+    }
+    if (conf->etag_bits != ETAG_NONE) {
+        conf->etag_bits &= (~ ETAG_NONE);
+    }
+
+    if (new->cgi_command_args != AP_FLAG_UNSET) {
+        conf->cgi_command_args = new->cgi_command_args;
+    }
+
+    return (void*)conf;
+}
+
+static void *create_core_server_config(pool *a, server_rec *s)
+{
+    core_server_config *conf;
+    int is_virtual = s->is_virtual;
+  
+    conf = (core_server_config *)ap_pcalloc(a, sizeof(core_server_config));
+#ifdef GPROF
+    conf->gprof_dir = NULL;
+#endif
+    conf->access_name = is_virtual ? NULL : DEFAULT_ACCESS_FNAME;
+    conf->ap_document_root = is_virtual ? NULL : DOCUMENT_LOCATION;
+    conf->sec = ap_make_array(a, 40, sizeof(void *));
+    conf->sec_url = ap_make_array(a, 40, sizeof(void *));
+
+    /* recursion stopper */
+    conf->redirect_limit = 0;
+    conf->subreq_limit = 0;
+    conf->recursion_limit_set = 0;
+
+    return (void *)conf;
+}
+
+static void *merge_core_server_configs(pool *p, void *basev, void *virtv)
+{
+    core_server_config *base = (core_server_config *)basev;
+    core_server_config *virt = (core_server_config *)virtv;
+    core_server_config *conf;
+
+    conf = (core_server_config *)ap_pcalloc(p, sizeof(core_server_config));
+    *conf = *virt;
+    if (!conf->access_name) {
+        conf->access_name = base->access_name;
+    }
+    if (!conf->ap_document_root) {
+        conf->ap_document_root = base->ap_document_root;
+    }
+    conf->sec = ap_append_arrays(p, base->sec, virt->sec);
+    conf->sec_url = ap_append_arrays(p, base->sec_url, virt->sec_url);
+
+    conf->redirect_limit = virt->recursion_limit_set
+                           ? virt->redirect_limit
+                           : base->redirect_limit;
+
+    conf->subreq_limit = virt->recursion_limit_set
+                         ? virt->subreq_limit
+                         : base->subreq_limit;
+
+    return conf;
+}
+
+/* Add per-directory configuration entry (for <directory> section);
+ * these are part of the core server config.
+ */
+
+CORE_EXPORT(void) ap_add_per_dir_conf(server_rec *s, void *dir_config)
+{
+    core_server_config *sconf = ap_get_module_config(s->module_config,
+						     &core_module);
+    void **new_space = (void **)ap_push_array(sconf->sec);
+    
+    *new_space = dir_config;
+}
+
+CORE_EXPORT(void) ap_add_per_url_conf(server_rec *s, void *url_config)
+{
+    core_server_config *sconf = ap_get_module_config(s->module_config,
+						     &core_module);
+    void **new_space = (void **)ap_push_array(sconf->sec_url);
+    
+    *new_space = url_config;
+}
+
+CORE_EXPORT(void) ap_add_file_conf(core_dir_config *conf, void *url_config)
+{
+    void **new_space = (void **)ap_push_array(conf->sec);
+    
+    *new_space = url_config;
+}
+
+/* core_reorder_directories reorders the directory sections such that the
+ * 1-component sections come first, then the 2-component, and so on, finally
+ * followed by the "special" sections.  A section is "special" if it's a regex,
+ * or if it doesn't start with / -- consider proxy: matching.  All movements
+ * are in-order to preserve the ordering of the sections from the config files.
+ * See directory_walk().
+ */
+
+#if defined(HAVE_DRIVE_LETTERS)
+#define IS_SPECIAL(entry_core)	\
+    ((entry_core)->r != NULL \
+	|| ((entry_core)->d[0] != '/' && (entry_core)->d[1] != ':'))
+#elif defined(NETWARE)
+/* XXX: Fairly certain this is correct... '/' must prefix the path
+ *      or else in the case xyz:/ or abc/xyz:/, '/' must follow the ':'.
+ *      If there is no leading '/' or embedded ':/', then we are special.
+ */
+#define IS_SPECIAL(entry_core)	\
+    ((entry_core)->r != NULL \
+	|| ((entry_core)->d[0] != '/' \
+            && strchr((entry_core)->d, ':') \
+            && *(strchr((entry_core)->d, ':') + 1) != '/'))
+#else
+#define IS_SPECIAL(entry_core)	\
+    ((entry_core)->r != NULL || (entry_core)->d[0] != '/')
+#endif
+
+/* We need to do a stable sort, qsort isn't stable.  So to make it stable
+ * we'll be maintaining the original index into the list, and using it
+ * as the minor key during sorting.  The major key is the number of
+ * components (where a "special" section has infinite components).
+ */
+struct reorder_sort_rec {
+    void *elt;
+    int orig_index;
+};
+
+static int reorder_sorter(const void *va, const void *vb)
+{
+    const struct reorder_sort_rec *a = va;
+    const struct reorder_sort_rec *b = vb;
+    core_dir_config *core_a;
+    core_dir_config *core_b;
+
+    core_a = (core_dir_config *)ap_get_module_config(a->elt, &core_module);
+    core_b = (core_dir_config *)ap_get_module_config(b->elt, &core_module);
+    if (IS_SPECIAL(core_a)) {
+	if (!IS_SPECIAL(core_b)) {
+	    return 1;
+	}
+    }
+    else if (IS_SPECIAL(core_b)) {
+	return -1;
+    }
+    else {
+	/* we know they're both not special */
+	if (core_a->d_components < core_b->d_components) {
+	    return -1;
+	}
+	else if (core_a->d_components > core_b->d_components) {
+	    return 1;
+	}
+    }
+    /* Either they're both special, or they're both not special and have the
+     * same number of components.  In any event, we now have to compare
+     * the minor key. */
+    return a->orig_index - b->orig_index;
+}
+
+CORE_EXPORT(void) ap_core_reorder_directories(pool *p, server_rec *s)
+{
+    core_server_config *sconf;
+    array_header *sec;
+    struct reorder_sort_rec *sortbin;
+    int nelts;
+    void **elts;
+    int i;
+    pool *tmp;
+
+    sconf = ap_get_module_config(s->module_config, &core_module);
+    sec = sconf->sec;
+    nelts = sec->nelts;
+    elts = (void **)sec->elts;
+
+    /* we have to allocate tmp space to do a stable sort */
+    tmp = ap_make_sub_pool(p);
+    sortbin = ap_palloc(tmp, sec->nelts * sizeof(*sortbin));
+    for (i = 0; i < nelts; ++i) {
+	sortbin[i].orig_index = i;
+	sortbin[i].elt = elts[i];
+    }
+
+    qsort(sortbin, nelts, sizeof(*sortbin), reorder_sorter);
+
+    /* and now copy back to the original array */
+    for (i = 0; i < nelts; ++i) {
+      elts[i] = sortbin[i].elt;
+    }
+
+    ap_destroy_pool(tmp);
+}
+
+/*****************************************************************
+ *
+ * There are some elements of the core config structures in which
+ * other modules have a legitimate interest (this is ugly, but necessary
+ * to preserve NCSA back-compatibility).  So, we have a bunch of accessors
+ * here...
+ */
+
+API_EXPORT(int) ap_allow_options(request_rec *r)
+{
+    core_dir_config *conf = 
+      (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module); 
+
+    return conf->opts; 
+} 
+
+API_EXPORT(int) ap_allow_overrides(request_rec *r) 
+{ 
+    core_dir_config *conf;
+    conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+						   &core_module); 
+
+    return conf->override; 
+} 
+
+API_EXPORT(const char *) ap_auth_type(request_rec *r)
+{
+    core_dir_config *conf;
+
+    conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+						   &core_module); 
+    return conf->ap_auth_type;
+}
+
+API_EXPORT(const char *) ap_auth_name(request_rec *r)
+{
+    core_dir_config *conf;
+
+    conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+						   &core_module); 
+    return conf->ap_auth_name;
+}
+
+API_EXPORT(const char *) ap_auth_nonce(request_rec *r)
+{
+    core_dir_config *conf;
+    conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+                                                   &core_module);
+    if (conf->ap_auth_nonce)
+       return conf->ap_auth_nonce;
+
+    /* Ideally we'd want to mix in some per-directory style
+     * information; as we are likely to want to detect replay
+     * across those boundaries and some randomness. But that
+     * is harder due to the adhoc nature of .htaccess memory
+     * structures, restarts and forks.
+     *
+     * But then again - you should use AuthDigestRealmSeed in your config
+     * file if you care. So the adhoc value should do.
+     */
+    return ap_psprintf(r->pool,"%pI%pp%pp%pp%pp",
+           &r->connection->local_addr.sin_addr,
+           (void *)ap_user_name,
+           (void *)ap_listeners,
+           (void *)ap_server_argv0,
+           (void *)ap_pid_fname);
+}
+
+API_EXPORT(const char *) ap_default_type(request_rec *r)
+{
+    core_dir_config *conf;
+
+    conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+						   &core_module); 
+    return conf->ap_default_type 
+               ? conf->ap_default_type 
+               : DEFAULT_CONTENT_TYPE;
+}
+
+API_EXPORT(const char *) ap_document_root(request_rec *r) /* Don't use this! */
+{
+    core_server_config *conf;
+
+    conf = (core_server_config *)ap_get_module_config(r->server->module_config,
+						      &core_module); 
+    return conf->ap_document_root;
+}
+
+API_EXPORT(const array_header *) ap_requires(request_rec *r)
+{
+    core_dir_config *conf;
+
+    conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+						   &core_module); 
+    return conf->ap_requires;
+}
+
+API_EXPORT(int) ap_satisfies(request_rec *r)
+{
+    core_dir_config *conf;
+
+    conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+						   &core_module);
+
+    return conf->satisfy;
+}
+
+/* Should probably just get rid of this... the only code that cares is
+ * part of the core anyway (and in fact, it isn't publicised to other
+ * modules).
+ */
+
+API_EXPORT(char *) ap_response_code_string(request_rec *r, int error_index)
+{
+    core_request_config *reqconf;
+    core_dir_config *dirconf;
+
+    /* prefer per-request settings, which are created by calls to
+     * ap_custom_response()
+     */
+    reqconf = (core_request_config *)ap_get_module_config(r->request_config,
+                                                          &core_module); 
+
+    if (reqconf != NULL &&
+        reqconf->response_code_strings != NULL &&
+        reqconf->response_code_strings[error_index] != NULL) {
+        return reqconf->response_code_strings[error_index];
+    }
+
+    /* check for string specified via ErrorDocument */
+    dirconf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+                                                      &core_module);
+
+    if (dirconf->response_code_strings == NULL) {
+	return NULL;
+    }
+
+    return dirconf->response_code_strings[error_index];
+}
+
+
+/* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
+/* Note: the function returns its result in conn->double_reverse:
+ *       +1: forward lookup of the previously reverse-looked-up
+ *           hostname in conn->remote_host succeeded, and at
+ *           least one of its IP addresses matches the client.
+ *       -1: forward lookup of conn->remote_host failed, or
+ *           none of the addresses found matches the client connection
+ *           (possible DNS spoof in the reverse zone!)
+ *       If do_double_reverse() returns -1, then it also invalidates
+ *       conn->remote_host to prevent an invalid name from appearing
+ *       in the log files. Conn->remote_host is set to "", because
+ *       a setting of NULL would allow another reverse lookup,
+ *       depending on the flags given to ap_get_remote_host().
+ */
+static ap_inline void do_double_reverse (conn_rec *conn)
+{
+    struct hostent *hptr;
+
+    if (conn->double_reverse) {
+	/* already done */
+	return;
+    }
+    if (conn->remote_host == NULL || conn->remote_host[0] == '\0') {
+	/* single reverse failed, so don't bother */
+	conn->double_reverse = -1;
+        conn->remote_host = ""; /* prevent another lookup */
+	return;
+    }
+    hptr = gethostbyname(conn->remote_host);
+    if (hptr) {
+	char **haddr;
+
+	for (haddr = hptr->h_addr_list; *haddr; haddr++) {
+	    if (((struct in_addr *)(*haddr))->s_addr
+		== conn->remote_addr.sin_addr.s_addr) {
+		conn->double_reverse = 1;
+		return;
+	    }
+	}
+    }
+    conn->double_reverse = -1;
+    /* invalidate possible reverse-resolved hostname if forward lookup fails */
+    conn->remote_host = "";
+}
+
+API_EXPORT(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config,
+					    int type)
+{
+    struct in_addr *iaddr;
+    struct hostent *hptr;
+    int hostname_lookups;
+    int old_stat = SERVER_DEAD;	/* we shouldn't ever be in this state */
+
+    /* If we haven't checked the host name, and we want to */
+    if (dir_config) {
+	hostname_lookups =
+	    ((core_dir_config *)ap_get_module_config(dir_config, &core_module))
+		->hostname_lookups;
+	if (hostname_lookups == HOSTNAME_LOOKUP_UNSET) {
+	    hostname_lookups = HOSTNAME_LOOKUP_OFF;
+	}
+    }
+    else {
+	/* the default */
+	hostname_lookups = HOSTNAME_LOOKUP_OFF;
+    }
+
+    if (type != REMOTE_NOLOOKUP
+	&& conn->remote_host == NULL
+	&& (type == REMOTE_DOUBLE_REV
+	    || hostname_lookups != HOSTNAME_LOOKUP_OFF)) {
+	old_stat = ap_update_child_status(conn->child_num, SERVER_BUSY_DNS,
+					  (request_rec*)NULL);
+	iaddr = &(conn->remote_addr.sin_addr);
+	hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET);
+	if (hptr != NULL) {
+	    conn->remote_host = ap_pstrdup(conn->pool, (void *)hptr->h_name);
+	    ap_str_tolower(conn->remote_host);
+	   
+	    if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) {
+		do_double_reverse(conn);
+	    }
+	}
+	/* if failed, set it to the NULL string to indicate error */
+	if (conn->remote_host == NULL) {
+	    conn->remote_host = "";
+	}
+    }
+    if (type == REMOTE_DOUBLE_REV) {
+	do_double_reverse(conn);
+	if (conn->double_reverse == -1) {
+	    return NULL;
+	}
+    }
+    if (old_stat != SERVER_DEAD) {
+	(void)ap_update_child_status(conn->child_num, old_stat,
+				     (request_rec*)NULL);
+    }
+
+/*
+ * Return the desired information; either the remote DNS name, if found,
+ * or either NULL (if the hostname was requested) or the IP address
+ * (if any identifier was requested).
+ */
+    if (conn->remote_host != NULL && conn->remote_host[0] != '\0') {
+	return conn->remote_host;
+    }
+    else {
+	if (type == REMOTE_HOST || type == REMOTE_DOUBLE_REV) {
+	    return NULL;
+	}
+	else {
+	    return conn->remote_ip;
+	}
+    }
+}
+
+API_EXPORT(const char *) ap_get_remote_logname(request_rec *r)
+{
+    core_dir_config *dir_conf;
+
+    if (r->connection->remote_logname != NULL) {
+	return r->connection->remote_logname;
+    }
+
+/* If we haven't checked the identity, and we want to */
+    dir_conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+						       &core_module);
+
+    if (dir_conf->do_rfc1413 & 1) {
+	return ap_rfc1413(r->connection, r->server);
+    }
+    else {
+	return NULL;
+    }
+}
+
+/* There are two options regarding what the "name" of a server is.  The
+ * "canonical" name as defined by ServerName and Port, or the "client's
+ * name" as supplied by a possible Host: header or full URI.  We never
+ * trust the port passed in the client's headers, we always use the
+ * port of the actual socket.
+ *
+ * The DNS option to UseCanonicalName causes this routine to do a
+ * reverse lookup on the local IP address of the connectiona and use
+ * that for the ServerName. This makes its value more reliable while
+ * at the same time allowing Demon's magic virtual hosting to work.
+ * The assumption is that DNS lookups are sufficiently quick...
+ * -- fanf 1998-10-03
+ */
+API_EXPORT(const char *) ap_get_server_name(request_rec *r)
+{
+    conn_rec *conn = r->connection;
+    core_dir_config *d;
+
+    d = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+						&core_module);
+
+    if (d->use_canonical_name == USE_CANONICAL_NAME_OFF) {
+        return r->hostname ? r->hostname : r->server->server_hostname;
+    }
+    if (d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
+        if (conn->local_host == NULL) {
+	    struct in_addr *iaddr;
+	    struct hostent *hptr;
+            int old_stat;
+	    old_stat = ap_update_child_status(conn->child_num,
+					      SERVER_BUSY_DNS, r);
+	    iaddr = &(conn->local_addr.sin_addr);
+	    hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr),
+				 AF_INET);
+	    if (hptr != NULL) {
+	        conn->local_host = ap_pstrdup(conn->pool,
+					      (void *)hptr->h_name);
+		ap_str_tolower(conn->local_host);
+	    }
+	    else {
+	        conn->local_host = ap_pstrdup(conn->pool,
+					      r->server->server_hostname);
+	    }
+	    (void) ap_update_child_status(conn->child_num, old_stat, r);
+	}
+	return conn->local_host;
+    }
+    /* default */
+    return r->server->server_hostname;
+}
+
+API_EXPORT(unsigned) ap_get_server_port(const request_rec *r)
+{
+    unsigned port;
+    unsigned cport = ntohs(r->connection->local_addr.sin_port);
+    core_dir_config *d =
+      (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
+    
+    if (d->use_canonical_name == USE_CANONICAL_NAME_OFF
+        || d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
+        
+        /* With UseCanonicalName Off Apache will form self-referential
+         * URLs using the hostname and port supplied by the client if
+         * any are supplied (otherwise it will use the canonical name).
+         */
+        port = r->parsed_uri.port_str ? r->parsed_uri.port : 
+#ifdef UCN_OFF_HONOR_PHYSICAL_PORT
+          cport ? cport :
+#endif
+            r->server->port ? r->server->port :
+              ap_default_port(r);
+    } else { /* d->use_canonical_name == USE_CANONICAL_NAME_ON */
+        port = r->server->port ? r->server->port : 
+          cport ? cport :
+            ap_default_port(r);
+    }
+
+    /* default */
+    return port;
+}
+
+API_EXPORT(char *) ap_construct_url(pool *p, const char *uri,
+				    request_rec *r)
+{
+    unsigned port = ap_get_server_port(r);
+    const char *host = ap_get_server_name(r);
+
+    if (ap_is_default_port(port, r)) {
+	return ap_pstrcat(p, ap_http_method(r), "://", host, uri, NULL);
+    }
+    return ap_psprintf(p, "%s://%s:%u%s", ap_http_method(r), host, port, uri);
+}
+
+API_EXPORT(unsigned long) ap_get_limit_req_body(const request_rec *r)
+{
+    core_dir_config *d =
+      (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
+    
+    return d->limit_req_body;
+}
+
+#ifdef WIN32
+static char* get_interpreter_from_win32_registry(pool *p, const char* ext) 
+{
+    char extension_path[] = "SOFTWARE\\Classes\\";
+    char executable_path[] = "\\SHELL\\OPEN\\COMMAND";
+
+    HKEY hkeyOpen;
+    DWORD type;
+    int size;
+    int result;
+    char *keyName;
+    char *buffer;
+    char *s;
+
+    if (!ext)
+        return NULL;
+    /* 
+     * Future optimization:
+     * When the registry is successfully searched, store the interpreter
+     * string in a table to make subsequent look-ups faster
+     */
+
+    /* Open the key associated with the script extension */
+    keyName = ap_pstrcat(p, extension_path, ext, NULL);
+
+    result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, 
+                          &hkeyOpen);
+
+    if (result != ERROR_SUCCESS) 
+        return NULL;
+
+    /* Read to NULL buffer to find value size */
+    size = 0;
+    result = RegQueryValueEx(hkeyOpen, "", NULL, &type, NULL, &size);
+
+    if (result == ERROR_SUCCESS) {
+        buffer = ap_palloc(p, size);
+        result = RegQueryValueEx(hkeyOpen, "", NULL, &type, buffer, &size);
+    }
+
+    RegCloseKey(hkeyOpen);
+
+    if (result != ERROR_SUCCESS)
+        return NULL;
+
+    /* Open the key associated with the interpreter path */
+    keyName = ap_pstrcat(p, extension_path, buffer, executable_path, NULL);
+
+    result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, 
+                          &hkeyOpen);
+
+    if (result != ERROR_SUCCESS)
+        return NULL;
+
+    /* Read to NULL buffer to find value size */
+    size = 0;
+    result = RegQueryValueEx(hkeyOpen, "", 0, &type, NULL, &size);
+
+    if (result == ERROR_SUCCESS) {
+        buffer = ap_palloc(p, size);
+        result = RegQueryValueEx(hkeyOpen, "", 0, &type, buffer, &size);
+    }
+
+    RegCloseKey(hkeyOpen);
+
+    if (result != ERROR_SUCCESS)
+        return NULL;
+
+    /*
+     * The command entry may contain embedded %envvar% entries,
+     * e.g. %winsysdir%\somecommand.exe %1
+     *
+     * Resolve them here
+     */
+    size = ExpandEnvironmentStrings(buffer, NULL, 0);
+    if (size) {
+        s = ap_palloc(p, size);
+        if (ExpandEnvironmentStrings(buffer, s, size))
+            buffer = s;
+    }
+
+    /*
+     * The canonical way shell command entries are entered in the Win32 
+     * registry is as follows:
+     *   shell [options] "%1" [options] [%*]
+     * where
+     *   shell - full path name to interpreter or shell to run.
+     *           E.g., c:\usr\local\ntreskit\perl\bin\perl.exe
+     *   options - optional switches
+     *              E.g., /C or -w
+     *   "%1" - Place holder for file to run the shell against. 
+     *          Quoted for if long path names are accepted.
+     *          Not quoted if only short paths are acceptd
+     *
+     *   %* - additional arguments
+     *
+     * Effective in v. 1.3.15, the responsibility is the consumer's
+     * to make these substitutions.
+     */
+
+    return buffer;
+}
+
+API_EXPORT (file_type_e) ap_get_win32_interpreter(const  request_rec *r, 
+                                                  char** interpreter )
+{
+    HANDLE hFile;
+    DWORD nBytesRead;
+    BOOLEAN bResult;
+    char buffer[1024];
+    core_dir_config *d;
+    int i;
+    file_type_e fileType = eFileTypeUNKNOWN;
+    char *ext = NULL;
+    char *exename = NULL;
+
+    d = (core_dir_config *)ap_get_module_config(r->per_dir_config, 
+                                                &core_module);
+
+    /* Find the file extension */
+    exename = strrchr(r->filename, '/');
+    if (!exename) {
+        exename = strrchr(r->filename, '\\');
+    }
+    if (!exename) {
+        exename = r->filename;
+    }
+    else {
+        exename++;
+    }
+    ext = strrchr(exename, '.');
+
+    if (ext && (!strcasecmp(ext,".bat") || !strcasecmp(ext,".cmd"))) 
+    {
+        char *p, *shellcmd = getenv("COMSPEC");
+        if (!shellcmd)
+            return eFileTypeUNKNOWN;
+        p = strchr(shellcmd, '\0');
+        if ((p - shellcmd >= 11) && !strcasecmp(p - 11, "command.com")) 
+        {
+            /* Command.com doesn't like long paths, doesn't do .cmd
+             */
+            if (!strcasecmp(ext,".cmd"))
+                return eFileTypeUNKNOWN;
+            *interpreter = ap_pstrcat(r->pool, "\"", shellcmd, "\" /C %1", NULL);
+            return eCommandShell16;
+        }
+        else {
+            /* Assume any other likes long paths, and knows .cmd,
+             * but the entire /c arg should be double quoted, e.g.
+             * "c:\path\cmd.exe" /c ""prog" "arg" "arg""
+             */
+            *interpreter = ap_pstrcat(r->pool, "\"", shellcmd, "\" /C \"\"%1\" %*\"", NULL);
+            return eCommandShell32;
+        }
+    }
+
+    /* If the file has an extension and it is not .com and not .exe and
+     * we've been instructed to search the registry, then do it!
+     */
+    if (ext && strcasecmp(ext,".exe") && strcasecmp(ext,".com") &&
+        d->script_interpreter_source == INTERPRETER_SOURCE_REGISTRY) {
+         /* Check the registry */
+        *interpreter = get_interpreter_from_win32_registry(r->pool, ext);
+        if (*interpreter)
+            return eFileTypeSCRIPT;
+        else {
+            ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, r->server,
+             "ScriptInterpreterSource config directive set to \"registry\".\n\t"
+             "Registry was searched but interpreter not found. Trying the shebang line.");
+        }
+    }        
+
+    /* Need to peek into the file figure out what it really is... */
+    hFile = CreateFile(r->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
+                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (hFile == INVALID_HANDLE_VALUE) {
+        return eFileTypeUNKNOWN;
+    }
+    bResult = ReadFile(hFile, (void*) &buffer, sizeof(buffer) - 1, 
+                       &nBytesRead, NULL);
+    if (!bResult || (nBytesRead == 0)) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
+                      "ReadFile(%s) failed", r->filename);
+        CloseHandle(hFile);
+        return eFileTypeUNKNOWN;
+    }
+    CloseHandle(hFile);
+    buffer[nBytesRead] = '\0';
+
+    /* Script or executable, that is the question... */
+    if ((buffer[0] == '#') && (buffer[1] == '!')) {
+        /* Assuming file is a script since it starts with a shebang */
+        fileType = eFileTypeSCRIPT;
+        for (i = 2; i < (sizeof(buffer) - 1); i++) {
+            if ((buffer[i] == '\r')
+                || (buffer[i] == '\n')) {
+                break;
+            }
+        }
+        buffer[i] = '\0';
+        for (i = 2; buffer[i] == ' ' ; ++i)
+            ;
+        *interpreter = ap_pstrdup(r->pool, buffer + i ); 
+    }
+    else {
+        /* Not a script, is it an executable? */
+        IMAGE_DOS_HEADER *hdr = (IMAGE_DOS_HEADER*)buffer;    
+        if ((nBytesRead >= sizeof(IMAGE_DOS_HEADER)) && (hdr->e_magic == IMAGE_DOS_SIGNATURE)) {
+            if (hdr->e_lfarlc < 0x40)
+                fileType = eFileTypeEXE16;
+            else
+                fileType = eFileTypeEXE32;
+        }
+        else
+            fileType = eFileTypeUNKNOWN;
+    }
+
+    return fileType;
+}
+#endif
+
+/*****************************************************************
+ *
+ * Commands... this module handles almost all of the NCSA httpd.conf
+ * commands, but most of the old srm.conf is in the the modules.
+ */
+
+static const char end_directory_section[] = "</Directory>";
+static const char end_directorymatch_section[] = "</DirectoryMatch>";
+static const char end_location_section[] = "</Location>";
+static const char end_locationmatch_section[] = "</LocationMatch>";
+static const char end_files_section[] = "</Files>";
+static const char end_filesmatch_section[] = "</FilesMatch>";
+static const char end_virtualhost_section[] = "</VirtualHost>";
+static const char end_ifmodule_section[] = "</IfModule>";
+static const char end_ifdefine_section[] = "</IfDefine>";
+
+
+API_EXPORT(const char *) ap_check_cmd_context(cmd_parms *cmd,
+					      unsigned forbidden)
+{
+    const char *gt = (cmd->cmd->name[0] == '<'
+		      && cmd->cmd->name[strlen(cmd->cmd->name)-1] != '>')
+                         ? ">" : "";
+
+    if ((forbidden & NOT_IN_VIRTUALHOST) && cmd->server->is_virtual) {
+	return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
+			  " cannot occur within <VirtualHost> section", NULL);
+    }
+
+    if ((forbidden & NOT_IN_LIMIT) && cmd->limited != -1) {
+	return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
+			  " cannot occur within <Limit> section", NULL);
+    }
+
+    if ((forbidden & NOT_IN_DIR_LOC_FILE) == NOT_IN_DIR_LOC_FILE
+	&& cmd->path != NULL) {
+	return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
+			  " cannot occur within <Directory/Location/Files> "
+			  "section", NULL);
+    }
+    
+    if (((forbidden & NOT_IN_DIRECTORY)
+	 && (cmd->end_token == end_directory_section
+	     || cmd->end_token == end_directorymatch_section)) 
+	|| ((forbidden & NOT_IN_LOCATION)
+	    && (cmd->end_token == end_location_section
+		|| cmd->end_token == end_locationmatch_section)) 
+	|| ((forbidden & NOT_IN_FILES)
+	    && (cmd->end_token == end_files_section
+		|| cmd->end_token == end_filesmatch_section))) {
+	return ap_pstrcat(cmd->pool, cmd->cmd->name, gt,
+			  " cannot occur within <", cmd->end_token+2,
+			  " section", NULL);
+    }
+
+    return NULL;
+}
+
+static const char *set_access_name(cmd_parms *cmd, void *dummy, char *arg)
+{
+    void *sconf = cmd->server->module_config;
+    core_server_config *conf = ap_get_module_config(sconf, &core_module);
+
+    const char *err = ap_check_cmd_context(cmd,
+					   NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    conf->access_name = ap_pstrdup(cmd->pool, arg);
+    return NULL;
+}
+
+#ifdef GPROF
+static const char *set_gprof_dir(cmd_parms *cmd, void *dummy, char *arg)
+{
+    void *sconf = cmd->server->module_config;
+    core_server_config *conf = ap_get_module_config(sconf, &core_module);
+
+    const char *err = ap_check_cmd_context(cmd,
+					   NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    conf->gprof_dir = ap_pstrdup(cmd->pool, arg);
+    return NULL;
+}
+#endif /*GPROF*/
+
+static const char *set_add_default_charset(cmd_parms *cmd, 
+	core_dir_config *d, char *arg)
+{
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+    if (!strcasecmp(arg, "Off")) {
+       d->add_default_charset = ADD_DEFAULT_CHARSET_OFF;
+    }
+    else if (!strcasecmp(arg, "On")) {
+       d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
+       d->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
+    }
+    else {
+       d->add_default_charset = ADD_DEFAULT_CHARSET_ON;
+       d->add_default_charset_name = arg;
+    }
+    return NULL;
+}
+static const char *set_accept_mutex(cmd_parms *cmd, void *dummy, char *arg)
+{
+	return ap_init_mutex_method(arg);
+}
+
+static const char *set_document_root(cmd_parms *cmd, void *dummy, char *arg)
+{
+    void *sconf = cmd->server->module_config;
+    core_server_config *conf = ap_get_module_config(sconf, &core_module);
+  
+    const char *err = ap_check_cmd_context(cmd,
+					   NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    arg = ap_os_canonical_filename(cmd->pool, arg);
+    if (ap_configtestonly && ap_docrootcheck && !ap_is_directory(arg)) {
+	if (cmd->server->is_virtual) {
+	    fprintf(stderr, "Warning: DocumentRoot [%s] does not exist\n",
+		    arg);
+	}
+	else {
+	    return "DocumentRoot must be a directory";
+	}
+    }
+    
+    conf->ap_document_root = arg;
+    return NULL;
+}
+
+API_EXPORT(void) ap_custom_response(request_rec *r, int status, char *string)
+{
+    core_request_config *reqconf =
+	ap_get_module_config(r->request_config, &core_module);
+    int idx;
+
+    if (reqconf == NULL) {
+        reqconf = (core_request_config *)ap_pcalloc(r->pool,
+                                                    sizeof(core_request_config));
+        ap_set_module_config(r->request_config, &core_module, reqconf);
+    }
+    
+    if (reqconf->response_code_strings == NULL) {
+        reqconf->response_code_strings = 
+	    ap_pcalloc(r->pool,
+                       sizeof(reqconf->response_code_strings) * 
+                       RESPONSE_CODES);
+    }
+
+    idx = ap_index_of_response(status);
+
+    reqconf->response_code_strings[idx] = 
+       ((ap_is_url(string) || (*string == '/')) && (*string != '"')) ? 
+       ap_pstrdup(r->pool, string) : ap_pstrcat(r->pool, "\"", string, NULL);
+}
+
+static const char *set_error_document(cmd_parms *cmd, core_dir_config *conf,
+				      char *line)
+{
+    int error_number, index_number, idx500;
+    char *w;
+                
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    /* 1st parameter should be a 3 digit number, which we recognize;
+     * convert it into an array index
+     */
+  
+    w = ap_getword_conf_nc(cmd->pool, &line);
+    error_number = atoi(w);
+
+    idx500 = ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR);
+
+    if (error_number == HTTP_INTERNAL_SERVER_ERROR) {
+        index_number = idx500;
+    }
+    else if ((index_number = ap_index_of_response(error_number)) == idx500) {
+        return ap_pstrcat(cmd->pool, "Unsupported HTTP response code ",
+			  w, NULL);
+    }
+
+    /* The entry should be ignored if it is a full URL for a 401 error */
+
+    if (error_number == 401 &&
+	line[0] != '/' && line[0] != '"') { /* Ignore it... */
+	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, cmd->server,
+		     "cannot use a full URL in a 401 ErrorDocument "
+		     "directive --- ignoring!");
+    }
+    else { /* Store it... */
+    	if (conf->response_code_strings == NULL) {
+	    conf->response_code_strings =
+		ap_pcalloc(cmd->pool,
+			   sizeof(*conf->response_code_strings) * RESPONSE_CODES);
+        }
+        conf->response_code_strings[index_number] = ap_pstrdup(cmd->pool, line);
+    }   
+
+    return NULL;
+}
+
+/* access.conf commands...
+ *
+ * The *only* thing that can appear in access.conf at top level is a
+ * <Directory> section.  NB we need to have a way to cut the srm_command_loop
+ * invoked by dirsection (i.e., <Directory>) short when </Directory> is seen.
+ * We do that by returning an error, which dirsection itself recognizes and
+ * discards as harmless.  Cheesy, but it works.
+ */
+
+static const char *set_override(cmd_parms *cmd, core_dir_config *d,
+				const char *l)
+{
+    char *w;
+  
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    d->override = OR_NONE;
+    while (l[0]) {
+        w = ap_getword_conf(cmd->pool, &l);
+	if (!strcasecmp(w, "Limit")) {
+	    d->override |= OR_LIMIT;
+	}
+	else if (!strcasecmp(w, "Options")) {
+	    d->override |= OR_OPTIONS;
+	}
+	else if (!strcasecmp(w, "FileInfo")) {
+            d->override |= OR_FILEINFO;
+	}
+	else if (!strcasecmp(w, "AuthConfig")) {
+	    d->override |= OR_AUTHCFG;
+	}
+	else if (!strcasecmp(w, "Indexes")) {
+            d->override |= OR_INDEXES;
+	}
+	else if (!strcasecmp(w, "None")) {
+	    d->override = OR_NONE;
+	}
+	else if (!strcasecmp(w, "All")) {
+	    d->override = OR_ALL;
+	}
+	else {
+	    return ap_pstrcat(cmd->pool, "Illegal override option ", w, NULL);
+	}
+	d->override &= ~OR_UNSET;
+    }
+
+    return NULL;
+}
+
+static const char *set_options(cmd_parms *cmd, core_dir_config *d,
+			       const char *l)
+{
+    allow_options_t opt;
+    int first = 1;
+    char action;
+
+    while (l[0]) {
+        char *w = ap_getword_conf(cmd->pool, &l);
+	action = '\0';
+
+	if (*w == '+' || *w == '-') {
+	    action = *(w++);
+	}
+	else if (first) {
+  	    d->opts = OPT_NONE;
+            first = 0;
+        }
+	    
+	if (!strcasecmp(w, "Indexes")) {
+	    opt = OPT_INDEXES;
+	}
+	else if (!strcasecmp(w, "Includes")) {
+	    opt = OPT_INCLUDES;
+	}
+	else if (!strcasecmp(w, "IncludesNOEXEC")) {
+	    opt = (OPT_INCLUDES | OPT_INCNOEXEC);
+	}
+	else if (!strcasecmp(w, "FollowSymLinks")) {
+	    opt = OPT_SYM_LINKS;
+	}
+	else if (!strcasecmp(w, "SymLinksIfOwnerMatch")) {
+	    opt = OPT_SYM_OWNER;
+	}
+	else if (!strcasecmp(w, "execCGI")) {
+	    opt = OPT_EXECCGI;
+	}
+	else if (!strcasecmp(w, "MultiViews")) {
+	    opt = OPT_MULTI;
+	}
+	else if (!strcasecmp(w, "RunScripts")) { /* AI backcompat. Yuck */
+	    opt = OPT_MULTI|OPT_EXECCGI;
+	}
+	else if (!strcasecmp(w, "None")) {
+	    opt = OPT_NONE;
+	}
+	else if (!strcasecmp(w, "All")) {
+	    opt = OPT_ALL;
+	}
+	else {
+	    return ap_pstrcat(cmd->pool, "Illegal option ", w, NULL);
+	}
+
+	/* we ensure the invariant (d->opts_add & d->opts_remove) == 0 */
+	if (action == '-') {
+	    d->opts_remove |= opt;
+	    d->opts_add &= ~opt;
+	    d->opts &= ~opt;
+	}
+	else if (action == '+') {
+	    d->opts_add |= opt;
+	    d->opts_remove &= ~opt;
+	    d->opts |= opt;
+	}
+	else {
+	    d->opts |= opt;
+	}
+    }
+
+    return NULL;
+}
+
+static const char *satisfy(cmd_parms *cmd, core_dir_config *c, char *arg)
+{
+    if (!strcasecmp(arg, "all")) {
+        c->satisfy = SATISFY_ALL;
+    }
+    else if (!strcasecmp(arg, "any")) {
+        c->satisfy = SATISFY_ANY;
+    }
+    else {
+        return "Satisfy either 'any' or 'all'.";
+    }
+    return NULL;
+}
+
+static const char *require(cmd_parms *cmd, core_dir_config *c, char *arg)
+{
+    require_line *r;
+  
+    if (!c->ap_requires) {
+        c->ap_requires = ap_make_array(cmd->pool, 2, sizeof(require_line));
+    }
+    r = (require_line *)ap_push_array(c->ap_requires);
+    r->requirement = ap_pstrdup(cmd->pool, arg);
+    r->method_mask = cmd->limited;
+    return NULL;
+}
+
+CORE_EXPORT_NONSTD(const char *) ap_limit_section(cmd_parms *cmd, void *dummy,
+						  const char *arg)
+{
+    const char *limited_methods = ap_getword(cmd->pool, &arg, '>');
+    void *tog = cmd->cmd->cmd_data;
+    int limited = 0;
+  
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    /* XXX: NB: Currently, we have no way of checking
+     * whether <Limit> or <LimitExcept> sections are closed properly.
+     * (If we would add a srm_command_loop() here we might...)
+     */
+    
+    while (limited_methods[0]) {
+        char *method = ap_getword_conf(cmd->pool, &limited_methods);
+        int  methnum = ap_method_number_of(method);
+
+        if (methnum == M_TRACE && !tog) {
+            return "TRACE cannot be controlled by <Limit>";
+        }
+        else if (methnum == M_INVALID) {
+            return ap_pstrcat(cmd->pool, "unknown method \"", method,
+                              "\" in <Limit", tog ? "Except>" : ">", NULL);
+        }
+        else {
+            limited |= (1 << methnum);
+        }
+    }
+
+    /* Killing two features with one function,
+     * if (tog == NULL) <Limit>, else <LimitExcept>
+     */
+    cmd->limited = tog ? ~limited : limited;
+    return NULL;
+}
+
+static const char *endlimit_section(cmd_parms *cmd, void *dummy, void *dummy2)
+{
+    void *tog = cmd->cmd->cmd_data;
+
+    if (cmd->limited == -1) {
+        return tog ? "</LimitExcept> unexpected" : "</Limit> unexpected";
+    }
+    
+    cmd->limited = -1;
+    return NULL;
+}
+
+/*
+ * When a section is not closed properly when end-of-file is reached,
+ * then an error message should be printed:
+ */
+static const char *missing_endsection(cmd_parms *cmd, int nest)
+{
+    if (nest < 2) {
+	return ap_psprintf(cmd->pool, "Missing %s directive at end-of-file",
+			   cmd->end_token);
+    }
+    return ap_psprintf(cmd->pool, "%d missing %s directives at end-of-file",
+		       nest, cmd->end_token);
+}
+
+/* We use this in <DirectoryMatch> and <FilesMatch>, to ensure that 
+ * people don't get bitten by wrong-cased regex matches
+ */
+
+#ifdef WIN32
+#define USE_ICASE REG_ICASE
+#else
+#define USE_ICASE 0
+#endif
+
+static const char *end_nested_section(cmd_parms *cmd, void *dummy)
+{
+    if (cmd->end_token == NULL) {
+        return ap_pstrcat(cmd->pool, cmd->cmd->name,
+			  " without matching <", cmd->cmd->name + 2, 
+			  " section", NULL);
+    }
+    /*
+     * This '!=' may look weird on a string comparison, but it's correct --
+     * it's been set up so that checking for two pointers to the same datum
+     * is valid here.  And faster.
+     */
+    if (cmd->cmd->name != cmd->end_token) {
+	return ap_pstrcat(cmd->pool, "Expected ", cmd->end_token, " but saw ",
+			  cmd->cmd->name, NULL);
+    }
+    return cmd->end_token;
+}
+
+/*
+ * Report a missing-'>' syntax error.
+ */
+static char *unclosed_directive(cmd_parms *cmd)
+{
+    return ap_pstrcat(cmd->pool, cmd->cmd->name,
+		      "> directive missing closing '>'", NULL);
+}
+
+static const char *dirsection(cmd_parms *cmd, void *dummy, const char *arg)
+{
+    const char *errmsg;
+    char *endp = strrchr(arg, '>');
+    int old_overrides = cmd->override;
+    char *old_path = cmd->path;
+    core_dir_config *conf;
+    void *new_dir_conf = ap_create_per_dir_config(cmd->pool);
+    regex_t *r = NULL;
+    const char *old_end_token;
+    const command_rec *thiscmd = cmd->cmd;
+
+    const char *err = ap_check_cmd_context(cmd,
+					   NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    if (endp == NULL) {
+	return unclosed_directive(cmd);
+    }
+
+    *endp = '\0';
+
+    cmd->path = ap_getword_conf(cmd->pool, &arg);
+    cmd->override = OR_ALL|ACCESS_CONF;
+
+    if (thiscmd->cmd_data) { /* <DirectoryMatch> */
+        r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
+        if (!r) {
+            return "Regex could not be compiled";
+        }
+    }
+    else if (!strcmp(cmd->path, "~")) {
+        cmd->path = ap_getword_conf(cmd->pool, &arg);
+        r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
+        if (!r) {
+            return "Regex could not be compiled";
+        }
+    }
+#if defined(HAVE_DRIVE_LETTERS) || defined(NETWARE)
+    else if (strcmp(cmd->path, "/") == 0) {
+        /* Treat 'default' path / as an inalienable root */
+        cmd->path = ap_pstrdup(cmd->pool, cmd->path);
+    }
+#endif
+#if defined(HAVE_UNC_PATHS)
+    else if (strcmp(cmd->path, "//") == 0) {
+        /* Treat UNC path // as an inalienable root */
+        cmd->path = ap_pstrdup(cmd->pool, cmd->path);
+    }
+#endif
+    else {
+	/* Ensure that the pathname is canonical */
+	cmd->path = ap_os_canonical_filename(cmd->pool, cmd->path);
+    }
+
+    old_end_token = cmd->end_token;
+    cmd->end_token = thiscmd->cmd_data ? end_directorymatch_section : end_directory_section;
+    errmsg = ap_srm_command_loop(cmd, new_dir_conf);
+    if (errmsg == NULL) {
+	errmsg = missing_endsection(cmd, 1);
+    }
+    cmd->end_token = old_end_token;
+    if (errmsg != (thiscmd->cmd_data 
+		       ? end_directorymatch_section 
+		   : end_directory_section)) {
+	return errmsg;
+    }
+
+    conf = (core_dir_config *)ap_get_module_config(new_dir_conf, &core_module);
+    conf->r = r;
+
+    ap_add_per_dir_conf(cmd->server, new_dir_conf);
+
+    if (*arg != '\0') {
+	return ap_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
+			  "> arguments not (yet) supported.", NULL);
+    }
+
+    cmd->path = old_path;
+    cmd->override = old_overrides;
+
+    return NULL;
+}
+
+static const char *urlsection(cmd_parms *cmd, void *dummy, const char *arg)
+{
+    const char *errmsg;
+    char *endp = strrchr(arg, '>');
+    int old_overrides = cmd->override;
+    char *old_path = cmd->path;
+    core_dir_config *conf;
+    regex_t *r = NULL;
+    const char *old_end_token;
+    const command_rec *thiscmd = cmd->cmd;
+
+    void *new_url_conf = ap_create_per_dir_config(cmd->pool);
+
+    const char *err = ap_check_cmd_context(cmd,
+					   NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    if (endp == NULL) {
+	return unclosed_directive(cmd);
+    }
+
+    *endp = '\0';
+
+    cmd->path = ap_getword_conf(cmd->pool, &arg);
+    cmd->override = OR_ALL|ACCESS_CONF;
+
+    if (thiscmd->cmd_data) { /* <LocationMatch> */
+        r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
+        if (!r) {
+            return "Regex could not be compiled";
+        }
+    }
+    else if (!strcmp(cmd->path, "~")) {
+        cmd->path = ap_getword_conf(cmd->pool, &arg);
+        r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
+        if (!r) {
+            return "Regex could not be compiled";
+        }
+    }
+
+    old_end_token = cmd->end_token;
+    cmd->end_token = thiscmd->cmd_data ? end_locationmatch_section
+                                       : end_location_section;
+    errmsg = ap_srm_command_loop(cmd, new_url_conf);
+    if (errmsg == NULL) {
+	errmsg = missing_endsection(cmd, 1);
+    }
+    cmd->end_token = old_end_token;
+    if (errmsg != (thiscmd->cmd_data 
+		       ? end_locationmatch_section 
+		       : end_location_section)) {
+	return errmsg;
+    }
+
+    conf = (core_dir_config *)ap_get_module_config(new_url_conf, &core_module);
+    conf->d = ap_pstrdup(cmd->pool, cmd->path);	/* No mangling, please */
+    conf->d_is_fnmatch = ap_is_fnmatch(conf->d) != 0;
+    conf->r = r;
+
+    ap_add_per_url_conf(cmd->server, new_url_conf);
+    
+    if (*arg != '\0') {
+	return ap_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
+			  "> arguments not (yet) supported.", NULL);
+    }
+
+    cmd->path = old_path;
+    cmd->override = old_overrides;
+
+    return NULL;
+}
+
+static const char *filesection(cmd_parms *cmd, core_dir_config *c,
+			       const char *arg)
+{
+    const char *errmsg;
+    char *endp = strrchr(arg, '>');
+    int old_overrides = cmd->override;
+    char *old_path = cmd->path;
+    core_dir_config *conf;
+    regex_t *r = NULL;
+    const char *old_end_token;
+    const command_rec *thiscmd = cmd->cmd;
+
+    void *new_file_conf = ap_create_per_dir_config(cmd->pool);
+
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_LOCATION);
+    if (err != NULL) {
+        return err;
+    }
+
+    if (endp == NULL) {
+	return unclosed_directive(cmd);
+    }
+
+    *endp = '\0';
+
+    cmd->path = ap_getword_conf(cmd->pool, &arg);
+    /* Only if not an .htaccess file */
+    if (!old_path) {
+	cmd->override = OR_ALL|ACCESS_CONF;
+    }
+
+    if (thiscmd->cmd_data) { /* <FilesMatch> */
+        r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
+        if (!r) {
+            return "Regex could not be compiled";
+        }
+    }
+    else if (!strcmp(cmd->path, "~")) {
+        cmd->path = ap_getword_conf(cmd->pool, &arg);
+        r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
+        if (!r) {
+            return "Regex could not be compiled";
+        }
+    }
+    else {
+	/* Ensure that the pathname is canonical */
+	cmd->path = ap_os_canonical_filename(cmd->pool, cmd->path);
+    }
+
+    old_end_token = cmd->end_token;
+    cmd->end_token = thiscmd->cmd_data ? end_filesmatch_section : end_files_section;
+    errmsg = ap_srm_command_loop(cmd, new_file_conf);
+    if (errmsg == NULL) {
+	errmsg = missing_endsection(cmd, 1);
+    }
+    cmd->end_token = old_end_token;
+    if (errmsg != (thiscmd->cmd_data 
+		       ? end_filesmatch_section 
+		   : end_files_section)) {
+	return errmsg;
+    }
+
+    conf = (core_dir_config *)ap_get_module_config(new_file_conf,
+						   &core_module);
+    conf->d = cmd->path;
+    conf->d_is_fnmatch = ap_is_fnmatch(conf->d) != 0;
+    conf->r = r;
+
+    ap_add_file_conf(c, new_file_conf);
+
+    if (*arg != '\0') {
+	return ap_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
+			  "> arguments not (yet) supported.", NULL);
+    }
+
+    cmd->path = old_path;
+    cmd->override = old_overrides;
+
+    return NULL;
+}
+
+/* XXX: NB: Currently, we have no way of checking
+ * whether <IfModule> sections are closed properly.
+ * Extra (redundant, unpaired) </IfModule> directives are
+ * simply silently ignored.
+ */
+static const char *end_ifmod(cmd_parms *cmd, void *dummy)
+{
+    return NULL;
+}
+
+static const char *start_ifmod(cmd_parms *cmd, void *dummy, char *arg)
+{
+    char *endp = strrchr(arg, '>');
+    char l[MAX_STRING_LEN];
+    int not = (arg[0] == '!');
+    module *found;
+    int nest = 1;
+
+    if (endp == NULL) {
+	return unclosed_directive(cmd);
+    }
+
+    *endp = '\0';
+
+    if (not) {
+        arg++;
+    }
+
+    found = ap_find_linked_module(arg);
+
+    if ((!not && found) || (not && !found)) {
+        return NULL;
+    }
+
+    while (nest && !(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) {
+        if (!strncasecmp(l, "<IfModule", 9)) {
+	    nest++;
+	}
+	if (!strcasecmp(l, "</IfModule>")) {
+	  nest--;
+	}
+    }
+
+    if (nest) {
+	cmd->end_token = end_ifmodule_section;
+	return missing_endsection(cmd, nest);
+    }
+    return NULL;
+}
+
+API_EXPORT(int) ap_exists_config_define(char *name)
+{
+    char **defines;
+    int i;
+
+    defines = (char **)ap_server_config_defines->elts;
+    for (i = 0; i < ap_server_config_defines->nelts; i++) {
+        if (strcmp(defines[i], name) == 0) {
+            return 1;
+	}
+    }
+    return 0;
+}
+
+static const char *end_ifdefine(cmd_parms *cmd, void *dummy) 
+{
+    return NULL;
+}
+
+static const char *start_ifdefine(cmd_parms *cmd, void *dummy, char *arg)
+{
+    char *endp;
+    char l[MAX_STRING_LEN];
+    int defined;
+    int not = 0;
+    int nest = 1;
+
+    endp = strrchr(arg, '>');
+    if (endp == NULL) {
+	return unclosed_directive(cmd);
+    }
+
+    *endp = '\0';
+
+    if (arg[0] == '!') {
+        not = 1;
+	arg++;
+    }
+
+    defined = ap_exists_config_define(arg);
+
+    if ((!not && defined) || (not && !defined)) {
+	return NULL;
+    }
+
+    while (nest && !(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) {
+        if (!strncasecmp(l, "<IfDefine", 9)) {
+	    nest++;
+	}
+	if (!strcasecmp(l, "</IfDefine>")) {
+	    nest--;
+	}
+    }
+    if (nest) {
+	cmd->end_token = end_ifdefine_section;
+	return missing_endsection(cmd, nest);
+    }
+    return NULL;
+}
+
+/* httpd.conf commands... beginning with the <VirtualHost> business */
+
+static const char *virtualhost_section(cmd_parms *cmd, void *dummy, char *arg)
+{
+    server_rec *main_server = cmd->server, *s;
+    const char *errmsg;
+    char *endp = strrchr(arg, '>');
+    pool *p = cmd->pool, *ptemp = cmd->temp_pool;
+    const char *old_end_token;
+
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    if (endp == NULL) {
+	return unclosed_directive(cmd);
+    }
+
+    *endp = '\0';
+    
+    /* FIXME: There's another feature waiting to happen here -- since you
+	can now put multiple addresses/names on a single <VirtualHost>
+	you might want to use it to group common definitions and then
+	define other "subhosts" with their individual differences.  But
+	personally I'd rather just do it with a macro preprocessor. -djg */
+    if (main_server->is_virtual) {
+	return "<VirtualHost> doesn't nest!";
+    }
+    
+    errmsg = ap_init_virtual_host(p, arg, main_server, &s);
+    if (errmsg) {
+	return errmsg;
+    }
+
+    s->next = main_server->next;
+    main_server->next = s;
+
+    s->defn_name = cmd->config_file->name;
+    s->defn_line_number = cmd->config_file->line_number;
+
+    old_end_token = cmd->end_token;
+    cmd->end_token = end_virtualhost_section;
+    cmd->server = s;
+    errmsg = ap_srm_command_loop(cmd, s->lookup_defaults);
+    cmd->server = main_server;
+    if (errmsg == NULL) {
+	errmsg = missing_endsection(cmd, 1);
+    }
+    cmd->end_token = old_end_token;
+
+    if (s->srm_confname) {
+	ap_process_resource_config(s, s->srm_confname, p, ptemp);
+    }
+
+    if (s->access_confname) {
+	ap_process_resource_config(s, s->access_confname, p, ptemp);
+    }
+    
+    if (errmsg == end_virtualhost_section) {
+	return NULL;
+    }
+    return errmsg;
+}
+
+static const char *set_server_alias(cmd_parms *cmd, void *dummy,
+				    const char *arg)
+{
+    if (!cmd->server->names) {
+	return "ServerAlias only used in <VirtualHost>";
+    }
+    while (*arg) {
+	char **item, *name = ap_getword_conf(cmd->pool, &arg);
+	if (ap_is_matchexp(name)) {
+	    item = (char **)ap_push_array(cmd->server->wild_names);
+	}
+	else {
+	    item = (char **)ap_push_array(cmd->server->names);
+	}
+	*item = name;
+    }
+    return NULL;
+}
+
+static const char *add_module_command(cmd_parms *cmd, void *dummy, char *arg)
+{
+    module *modp;
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    for (modp = top_module; modp; modp = modp->next) {
+        if (modp->name != NULL && strcmp(modp->name, arg) == 0) {
+            ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, cmd->server,
+                          "module %s is already added, skipping", arg);
+            return NULL;
+        }
+    }
+
+    if (!ap_add_named_module(arg)) {
+	return ap_pstrcat(cmd->pool, "Cannot add module via name '", arg, 
+			  "': not in list of loaded modules", NULL);
+    }
+    return NULL;
+}
+
+static const char *clear_module_list_command(cmd_parms *cmd, void *dummy)
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    ap_clear_module_list();
+    return NULL;
+}
+
+static const char *set_server_string_slot(cmd_parms *cmd, void *dummy,
+					  char *arg)
+{
+    /* This one's pretty generic... */
+  
+    int offset = (int)(long)cmd->info;
+    char *struct_ptr = (char *)cmd->server;
+    
+    const char *err = ap_check_cmd_context(cmd, 
+					   NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    *(char **)(struct_ptr + offset) = arg;
+    return NULL;
+}
+
+static const char *server_type(cmd_parms *cmd, void *dummy, char *arg)
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    if (!strcasecmp(arg, "inetd")) {
+        ap_standalone = 0;
+    }
+    else if (!strcasecmp(arg, "standalone")) {
+        ap_standalone = 1;
+    }
+    else {
+        return "ServerType must be either 'inetd' or 'standalone'";
+    }
+
+    return NULL;
+}
+
+static const char *server_port(cmd_parms *cmd, void *dummy, char *arg)
+{
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    int port;
+
+    if (err != NULL) {
+	return err;
+    }
+    port = atoi(arg);
+    if (port <= 0 || port >= 65536) { /* 65536 == 1<<16 */
+	return ap_pstrcat(cmd->temp_pool, "The port number \"", arg, 
+			  "\" is outside the appropriate range "
+			  "(i.e., 1..65535).", NULL);
+    }
+    cmd->server->port = port;
+    return NULL;
+}
+
+static const char *set_signature_flag(cmd_parms *cmd, core_dir_config *d, 
+				      char *arg)
+{
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    if (strcasecmp(arg, "On") == 0) {
+	d->server_signature = srv_sig_on;
+    }
+    else if (strcasecmp(arg, "Off") == 0) {
+        d->server_signature = srv_sig_off;
+    }
+    else if (strcasecmp(arg, "EMail") == 0) {
+	d->server_signature = srv_sig_withmail;
+    }
+    else {
+	return "ServerSignature: use one of: off | on | email";
+    }
+    return NULL;
+}
+
+static const char *set_send_buffer_size(cmd_parms *cmd, void *dummy, char *arg)
+{
+    int s = atoi(arg);
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    if (s < 512 && s != 0) {
+        return "SendBufferSize must be >= 512 bytes, or 0 for system default.";
+    }
+    cmd->server->send_buffer_size = s;
+    return NULL;
+}
+
+static const char *set_user(cmd_parms *cmd, void *dummy, char *arg)
+{
+#ifdef WIN32
+    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, cmd->server,
+		 "User directive has no affect on Win32");
+    cmd->server->server_uid = ap_user_id = 1;
+#else
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    if (!cmd->server->is_virtual) {
+	ap_user_name = arg;
+	cmd->server->server_uid = ap_user_id = ap_uname2id(arg);
+    }
+    else {
+        if (ap_suexec_enabled) {
+	    cmd->server->server_uid = ap_uname2id(arg);
+	}
+	else {
+	    cmd->server->server_uid = ap_user_id;
+	    fprintf(stderr,
+		    "Warning: User directive in <VirtualHost> "
+		    "requires SUEXEC wrapper.\n");
+	}
+    }
+#if !defined (BIG_SECURITY_HOLE) && !defined (OS2)
+    if (cmd->server->server_uid == 0) {
+	fprintf(stderr,
+		"Error:\tApache has not been designed to serve pages while\n"
+		"\trunning as root.  There are known race conditions that\n"
+		"\twill allow any local user to read any file on the system.\n"
+		"\tIf you still desire to serve pages as root then\n"
+		"\tadd -DBIG_SECURITY_HOLE to the EXTRA_CFLAGS line in your\n"
+		"\tsrc/Configuration file and rebuild the server.  It is\n"
+		"\tstrongly suggested that you instead modify the User\n"
+		"\tdirective in your httpd.conf file to list a non-root\n"
+		"\tuser.\n");
+	exit (1);
+    }
+#endif
+#endif /* WIN32 */
+
+    return NULL;
+}
+
+static const char *set_group(cmd_parms *cmd, void *dummy, char *arg)
+{
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    if (!cmd->server->is_virtual) {
+	cmd->server->server_gid = ap_group_id = ap_gname2id(arg);
+    }
+    else {
+        if (ap_suexec_enabled) {
+	    cmd->server->server_gid = ap_gname2id(arg);
+	}
+	else {
+	    cmd->server->server_gid = ap_group_id;
+	    fprintf(stderr,
+		    "Warning: Group directive in <VirtualHost> requires "
+		    "SUEXEC wrapper.\n");
+	}
+    }
+
+    return NULL;
+}
+
+static const char *set_server_root(cmd_parms *cmd, void *dummy, char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+
+    if (err != NULL) {
+        return err;
+    }
+
+    arg = ap_os_canonical_filename(cmd->pool, arg);
+
+    if (!ap_is_directory(arg)) {
+        return "ServerRoot must be a valid directory";
+    }
+    /* ServerRoot is never '/' terminated */
+    while (strlen(ap_server_root) > 1 && ap_server_root[strlen(ap_server_root)-1] == '/')
+        ap_server_root[strlen(ap_server_root)-1] = '\0';
+    ap_cpystrn(ap_server_root, arg,
+	       sizeof(ap_server_root));
+    return NULL;
+}
+
+static const char *set_timeout(cmd_parms *cmd, void *dummy, char *arg)
+{
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    cmd->server->timeout = atoi(arg);
+    return NULL;
+}
+
+static const char *set_keep_alive_timeout(cmd_parms *cmd, void *dummy,
+					  char *arg)
+{
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    cmd->server->keep_alive_timeout = atoi(arg);
+    return NULL;
+}
+
+static const char *set_keep_alive(cmd_parms *cmd, void *dummy, char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    /* We've changed it to On/Off, but used to use numbers
+     * so we accept anything but "Off" or "0" as "On"
+     */
+    if (!strcasecmp(arg, "off") || !strcmp(arg, "0")) {
+	cmd->server->keep_alive = 0;
+    }
+    else {
+	cmd->server->keep_alive = 1;
+    }
+    return NULL;
+}
+
+static const char *set_keep_alive_max(cmd_parms *cmd, void *dummy, char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    cmd->server->keep_alive_max = atoi(arg);
+    return NULL;
+}
+
+#ifdef AP_ENABLE_EXCEPTION_HOOK
+static const char *set_exception_hook(cmd_parms *cmd, void *dummy, char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    if (cmd->server->is_virtual) {
+	return "EnableExceptionHook directive not allowed in <VirtualHost>";
+    }
+
+    if (strcasecmp(arg, "on") == 0) {
+        ap_exception_hook_enabled = 1;
+    }
+    else if (strcasecmp(arg, "off") == 0) {
+        ap_exception_hook_enabled = 0;
+    }
+    else {
+        return "parameter must be 'on' or 'off'";
+    }
+
+    return NULL;
+}
+#endif /* AP_ENABLE_EXCEPTION_HOOK */
+
+static const char *set_pidfile(cmd_parms *cmd, void *dummy, char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    if (cmd->server->is_virtual) {
+	return "PidFile directive not allowed in <VirtualHost>";
+    }
+    ap_pid_fname = arg;
+    return NULL;
+}
+
+static const char *set_scoreboard(cmd_parms *cmd, void *dummy, char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    ap_scoreboard_fname = arg;
+    return NULL;
+}
+
+static const char *set_lockfile(cmd_parms *cmd, void *dummy, char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    ap_lock_fname = arg;
+    return NULL;
+}
+
+static const char *set_idcheck(cmd_parms *cmd, core_dir_config *d, int arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    d->do_rfc1413 = arg != 0;
+    return NULL;
+}
+
+static const char *set_hostname_lookups(cmd_parms *cmd, core_dir_config *d,
+					char *arg)
+{
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    if (!strcasecmp(arg, "on")) {
+	d->hostname_lookups = HOSTNAME_LOOKUP_ON;
+    }
+    else if (!strcasecmp(arg, "off")) {
+	d->hostname_lookups = HOSTNAME_LOOKUP_OFF;
+    }
+    else if (!strcasecmp(arg, "double")) {
+	d->hostname_lookups = HOSTNAME_LOOKUP_DOUBLE;
+    }
+    else {
+	return "parameter must be 'on', 'off', or 'double'";
+    }
+    return NULL;
+}
+
+static const char *set_serverpath(cmd_parms *cmd, void *dummy, char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    cmd->server->path = arg;
+    cmd->server->pathlen = strlen(arg);
+    return NULL;
+}
+
+static const char *set_content_md5(cmd_parms *cmd, core_dir_config *d, int arg)
+{
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    d->content_md5 = arg != 0;
+    return NULL;
+}
+
+static const char *set_use_canonical_name(cmd_parms *cmd, core_dir_config *d, 
+					  char *arg)
+{
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
+    if (err != NULL) {
+	return err;
+    }
+
+    if (strcasecmp(arg, "on") == 0) {
+        d->use_canonical_name = USE_CANONICAL_NAME_ON;
+    }
+    else if (strcasecmp(arg, "off") == 0) {
+        d->use_canonical_name = USE_CANONICAL_NAME_OFF;
+    }
+    else if (strcasecmp(arg, "dns") == 0) {
+        d->use_canonical_name = USE_CANONICAL_NAME_DNS;
+    }
+    else {
+        return "parameter must be 'on', 'off', or 'dns'";
+    }
+    return NULL;
+}
+
+static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, char *arg) 
+{
+#ifdef WIN32
+    fprintf(stderr, "WARNING: StartServers has no effect on Win32\n");
+#elif defined(NETWARE)
+    fprintf(stderr, "WARNING: StartServers has no effect on NetWare\n");
+#else
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    ap_daemons_to_start = atoi(arg);
+#endif
+    return NULL;
+}
+
+static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, char *arg)
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    ap_daemons_min_free = atoi(arg);
+    if (ap_daemons_min_free <= 0) {
+       fprintf(stderr, "WARNING: detected MinSpareServers set to non-positive.\n");
+       fprintf(stderr, "Resetting to 1 to avoid almost certain Apache failure.\n");
+       fprintf(stderr, "Please read the documentation.\n");
+       ap_daemons_min_free = 1;
+    }
+       
+    return NULL;
+}
+
+static const char *set_max_free_servers(cmd_parms *cmd, void *dummy, char *arg)
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    ap_daemons_max_free = atoi(arg);
+    return NULL;
+}
+
+static const char *set_server_limit (cmd_parms *cmd, void *dummy, char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    ap_daemons_limit = atoi(arg);
+    if (ap_daemons_limit > HARD_SERVER_LIMIT) {
+       fprintf(stderr, "WARNING: MaxClients of %d exceeds compile time limit "
+           "of %d servers,\n", ap_daemons_limit, HARD_SERVER_LIMIT);
+       fprintf(stderr, " lowering MaxClients to %d.  To increase, please "
+           "see the\n", HARD_SERVER_LIMIT);
+       fprintf(stderr, " HARD_SERVER_LIMIT define in src/include/httpd.h.\n");
+       ap_daemons_limit = HARD_SERVER_LIMIT;
+    } 
+    else if (ap_daemons_limit < 1) {
+	fprintf(stderr, "WARNING: Require MaxClients > 0, setting to 1\n");
+	ap_daemons_limit = 1;
+    }
+    return NULL;
+}
+
+static const char *set_max_requests(cmd_parms *cmd, void *dummy, char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    ap_max_requests_per_child = atoi(arg);
+    return NULL;
+}
+
+static const char *set_threads(cmd_parms *cmd, void *dummy, char *arg) {
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    ap_threads_per_child = atoi(arg);
+    if (ap_threads_per_child > HARD_SERVER_LIMIT) {
+        fprintf(stderr, "WARNING: ThreadsPerChild of %d exceeds compile time limit "
+                "of %d threads,\n", ap_threads_per_child, HARD_SERVER_LIMIT);
+        fprintf(stderr, " lowering ThreadsPerChild to %d.  To increase, please "
+                "see the\n", HARD_SERVER_LIMIT);
+        fprintf(stderr, " HARD_SERVER_LIMIT define in src/include/httpd.h.\n");
+        ap_threads_per_child = HARD_SERVER_LIMIT;
+    } 
+    else if (ap_threads_per_child < 1) {
+	fprintf(stderr, "WARNING: Require ThreadsPerChild > 0, setting to 1\n");
+	ap_threads_per_child = 1;
+    }
+
+    return NULL;
+}
+
+static const char *set_excess_requests(cmd_parms *cmd, void *dummy, char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    ap_excess_requests_per_child = atoi(arg);
+    return NULL;
+}
+
+
+#if defined(RLIMIT_CPU) || defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_NPROC) || defined(RLIMIT_AS)
+static void set_rlimit(cmd_parms *cmd, struct rlimit **plimit, const char *arg,
+                       const char * arg2, int type)
+{
+    char *str;
+    struct rlimit *limit;
+    /* If your platform doesn't define rlim_t then typedef it in ap_config.h */
+    rlim_t cur = 0;
+    rlim_t max = 0;
+
+    *plimit = (struct rlimit *)ap_pcalloc(cmd->pool, sizeof(**plimit));
+    limit = *plimit;
+    if ((getrlimit(type, limit)) != 0)	{
+	*plimit = NULL;
+	ap_log_error(APLOG_MARK, APLOG_ERR, cmd->server,
+		     "%s: getrlimit failed", cmd->cmd->name);
+	return;
+    }
+
+    if ((str = ap_getword_conf(cmd->pool, &arg))) {
+	if (!strcasecmp(str, "max")) {
+	    cur = limit->rlim_max;
+	}
+	else {
+	    cur = atol(str);
+	}
+    }
+    else {
+	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, cmd->server,
+		     "Invalid parameters for %s", cmd->cmd->name);
+	return;
+    }
+    
+    if (arg2 && (str = ap_getword_conf(cmd->pool, &arg2))) {
+	max = atol(str);
+    }
+
+    /* if we aren't running as root, cannot increase max */
+    if (geteuid()) {
+	limit->rlim_cur = cur;
+	if (max) {
+	    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, cmd->server,
+			 "Must be uid 0 to raise maximum %s", cmd->cmd->name);
+	}
+    }
+    else {
+        if (cur) {
+	    limit->rlim_cur = cur;
+	}
+        if (max) {
+	    limit->rlim_max = max;
+	}
+    }
+}
+#endif
+
+#if !defined (RLIMIT_CPU) || !(defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)) || !defined (RLIMIT_NPROC)
+static const char *no_set_limit(cmd_parms *cmd, core_dir_config *conf,
+				char *arg, char *arg2)
+{
+    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, cmd->server,
+		"%s not supported on this platform", cmd->cmd->name);
+    return NULL;
+}
+#endif
+
+#ifdef RLIMIT_CPU
+static const char *set_limit_cpu(cmd_parms *cmd, core_dir_config *conf, 
+				 char *arg, char *arg2)
+{
+    set_rlimit(cmd, &conf->limit_cpu, arg, arg2, RLIMIT_CPU);
+    return NULL;
+}
+#endif
+
+#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)
+static const char *set_limit_mem(cmd_parms *cmd, core_dir_config *conf, 
+				 char *arg, char * arg2)
+{
+#if defined(RLIMIT_AS)
+    set_rlimit(cmd, &conf->limit_mem, arg, arg2 ,RLIMIT_AS);
+#elif defined(RLIMIT_DATA)
+    set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_DATA);
+#elif defined(RLIMIT_VMEM)
+    set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_VMEM);
+#endif
+    return NULL;
+}
+#endif
+
+#ifdef RLIMIT_NPROC
+static const char *set_limit_nproc(cmd_parms *cmd, core_dir_config *conf,  
+				   char *arg, char * arg2)
+{
+    set_rlimit(cmd, &conf->limit_nproc, arg, arg2, RLIMIT_NPROC);
+    return NULL;
+}
+#endif
+
+static const char *set_bind_address(cmd_parms *cmd, void *dummy, char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    ap_bind_address.s_addr = ap_get_virthost_addr(arg, NULL);
+    return NULL;
+}
+
+#ifdef NETWARE
+static const char *set_threadstacksize(cmd_parms *cmd, void *dummy, char *stacksize)
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+    
+    ap_thread_stack_size = atoi(stacksize);    
+    return NULL;
+}
+#endif
+
+/* Though the AcceptFilter functionality is not available across
+ * all platforms - we still allow the config directive to appear
+ * on all platforms and do intentionally not tie it to the compile
+ * time flag SO_ACCEPTFILTER. This makes configuration files significantly
+ * more portable; especially as an <IfModule http_core.c> or some
+ * other construct is not possible.
+ */
+static const char *set_acceptfilter(cmd_parms *cmd, void *dummy, int flag)
+{
+#ifdef SO_ACCEPTFILTER
+    ap_acceptfilter = flag;
+#endif
+    return NULL;
+}
+
+static const char *set_listener(cmd_parms *cmd, void *dummy, char *ips)
+{
+    listen_rec *new;
+    char *ports, *endptr;
+    long port;
+    
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    ports = strchr(ips, ':');
+    if (ports != NULL) {
+	if (ports == ips) {
+	    return "Missing IP address";
+	}
+	else if (ports[1] == '\0') {
+	    return "Address must end in :<port-number>";
+	}
+	*(ports++) = '\0';
+    }
+    else {
+	ports = ips;
+    }
+
+    new=ap_pcalloc(cmd->pool, sizeof(listen_rec));
+    new->local_addr.sin_family = AF_INET;
+    if (ports == ips) { /* no address */
+	new->local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    }
+    else {
+	new->local_addr.sin_addr.s_addr = ap_get_virthost_addr(ips, NULL);
+    }
+    errno = 0; /* clear errno before calling strtol */
+    port = ap_strtol(ports, &endptr, 10);
+    if (errno /* some sort of error */
+       || (endptr && *endptr) /* make sure no trailing characters */
+       || port < 1 || port > 65535) /* underflow/overflow */
+    {
+	return "Missing, invalid, or non-numeric port";
+    }
+    new->local_addr.sin_port = htons((unsigned short)port);
+    new->fd = -1;
+    new->used = 0;
+    new->next = ap_listeners;
+    ap_listeners = new;
+    return NULL;
+}
+
+static const char *set_listenbacklog(cmd_parms *cmd, void *dummy, char *arg) 
+{
+    int b;
+
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    b = atoi(arg);
+    if (b < 1) {
+        return "ListenBacklog must be > 0";
+    }
+    ap_listenbacklog = b;
+    return NULL;
+}
+
+static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, char *arg) 
+{
+    struct stat finfo;
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    arg = ap_server_root_relative(cmd->pool, arg);
+    if ((stat(arg, &finfo) == -1) || !S_ISDIR(finfo.st_mode)) {
+	return ap_pstrcat(cmd->pool, "CoreDumpDirectory ", arg, 
+			  " does not exist or is not a directory", NULL);
+    }
+    ap_cpystrn(ap_coredump_dir, arg, sizeof(ap_coredump_dir));
+    ap_coredump_dir_configured = 1;
+    return NULL;
+}
+
+static const char *include_config (cmd_parms *cmd, void *dummy, char *name)
+{
+    name = ap_server_root_relative(cmd->pool, name);
+    
+    ap_process_resource_config(cmd->server, name, cmd->pool, cmd->temp_pool);
+
+    return NULL;
+}
+
+static const char *set_loglevel(cmd_parms *cmd, void *dummy, const char *arg) 
+{
+    char *str;
+    
+    const char *err = ap_check_cmd_context(cmd,
+					   NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    if ((str = ap_getword_conf(cmd->pool, &arg))) {
+        if (!strcasecmp(str, "emerg")) {
+	    cmd->server->loglevel = APLOG_EMERG;
+	}
+	else if (!strcasecmp(str, "alert")) {
+	    cmd->server->loglevel = APLOG_ALERT;
+	}
+	else if (!strcasecmp(str, "crit")) {
+	    cmd->server->loglevel = APLOG_CRIT;
+	}
+	else if (!strcasecmp(str, "error")) {
+	    cmd->server->loglevel = APLOG_ERR;
+	}
+	else if (!strcasecmp(str, "warn")) {
+	    cmd->server->loglevel = APLOG_WARNING;
+	}
+	else if (!strcasecmp(str, "notice")) {
+	    cmd->server->loglevel = APLOG_NOTICE;
+	}
+	else if (!strcasecmp(str, "info")) {
+	    cmd->server->loglevel = APLOG_INFO;
+	}
+	else if (!strcasecmp(str, "debug")) {
+	    cmd->server->loglevel = APLOG_DEBUG;
+	}
+	else {
+            return "LogLevel requires level keyword: one of "
+	           "emerg/alert/crit/error/warn/notice/info/debug";
+	}
+    }
+    else {
+        return "LogLevel requires level keyword";
+    }
+
+    return NULL;
+}
+
+API_EXPORT(const char *) ap_psignature(const char *prefix, request_rec *r)
+{
+    char sport[20];
+    core_dir_config *conf;
+
+    conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+						   &core_module);
+    if ((conf->server_signature == srv_sig_off)
+	    || (conf->server_signature == srv_sig_unset)) {
+	return "";
+    }
+
+    ap_snprintf(sport, sizeof sport, "%u", (unsigned) ap_get_server_port(r));
+
+    if (conf->server_signature == srv_sig_withmail) {
+	return ap_pstrcat(r->pool, prefix, "<ADDRESS>" SERVER_BASEVERSION
+			  " Server at <A HREF=\"mailto:",
+			  r->server->server_admin, "\">",
+			  ap_escape_html(r->pool, ap_get_server_name(r)), 
+			  "</A> Port ", sport,
+			  "</ADDRESS>\n", NULL);
+    }
+    return ap_pstrcat(r->pool, prefix, "<ADDRESS>" SERVER_BASEVERSION
+		      " Server at ", 
+		      ap_escape_html(r->pool, ap_get_server_name(r)), 
+		      " Port ", sport,
+		      "</ADDRESS>\n", NULL);
+}
+
+/*
+ * Load an authorisation realm into our location configuration, applying the
+ * usual rules that apply to realms.
+ */
+static const char *set_authname(cmd_parms *cmd, void *mconfig, char *word1)
+{
+    core_dir_config *aconfig = (core_dir_config *)mconfig;
+
+    aconfig->ap_auth_name = ap_escape_quotes(cmd->pool, word1);
+    return NULL;
+}
+
+/*
+ * Load an authorisation nonce into our location configuration, and
+ * force it to be in the 0-9/A-Z realm.
+ */
+static const char *set_authnonce (cmd_parms *cmd, void *mconfig, char *word1)
+{
+    core_dir_config *aconfig = (core_dir_config *)mconfig;
+    size_t i;
+
+    aconfig->ap_auth_nonce = ap_escape_quotes(cmd->pool, word1);
+
+    if (strlen(aconfig->ap_auth_nonce) > 510)
+       return "AuthDigestRealmSeed length limited to 510 chars for browser compatibility";
+
+    for(i=0;i<strlen(aconfig->ap_auth_nonce );i++)
+       if (!ap_isalnum(aconfig->ap_auth_nonce [i]))
+         return "AuthDigestRealmSeed limited to 0-9 and A-Z range for browser compatibility";
+
+    return NULL;
+}
+
+
+#ifdef _OSD_POSIX /* BS2000 Logon Passwd file */
+static const char *set_bs2000_account(cmd_parms *cmd, void *dummy, char *name)
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    return os_set_account(cmd->pool, name);
+}
+#endif /*_OSD_POSIX*/
+
+static const char *set_protocol_req_check(cmd_parms *cmd,
+                                              core_dir_config *d, int arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    ap_protocol_req_check = arg != 0;
+    return NULL;
+}
+
+static const char *set_change_shmem_uid(cmd_parms *cmd,
+                                              core_dir_config *d, int arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    ap_change_shmem_uid = arg != 0;
+    return NULL;
+}
+
+/*
+ * Handle a request to include the server's OS platform in the Server
+ * response header field (the ServerTokens directive).  Unfortunately
+ * this requires a new global in order to communicate the setting back to
+ * http_main so it can insert the information in the right place in the
+ * string.
+ */
+static const char *set_serv_tokens(cmd_parms *cmd, void *dummy, char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    if (!strcasecmp(arg, "OS")) {
+        ap_server_tokens = SrvTk_OS;
+    }
+    else if (!strcasecmp(arg, "Min") || !strcasecmp(arg, "Minimal")) {
+        ap_server_tokens = SrvTk_MIN;
+    }
+    else if (!strcasecmp(arg, "Full")) {
+        ap_server_tokens = SrvTk_FULL;
+    }
+    else if (!strcasecmp(arg, "Prod") || !strcasecmp(arg, "ProductOnly")) {
+        ap_server_tokens = SrvTk_PRODUCT_ONLY;
+    }
+    else {
+	return ap_pstrcat(cmd->pool, "Unrecognised ServerTokens keyword: ",
+			  arg, NULL);
+    }
+    return NULL;
+}
+
+static const char *set_limit_req_line(cmd_parms *cmd, void *dummy, char *arg)
+{
+    const char *err = ap_check_cmd_context(cmd,
+                                           NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    int lim;
+
+    if (err != NULL) {
+        return err;
+    }
+    lim = atoi(arg);
+    if (lim < 0) {
+        return ap_pstrcat(cmd->temp_pool, "LimitRequestLine \"", arg, 
+                          "\" must be a non-negative integer", NULL);
+    }
+    if (lim > DEFAULT_LIMIT_REQUEST_LINE) {
+        return ap_psprintf(cmd->temp_pool, "LimitRequestLine \"%s\" "
+                           "must not exceed the precompiled maximum of %d",
+                           arg, DEFAULT_LIMIT_REQUEST_LINE);
+    }
+    cmd->server->limit_req_line = lim;
+    return NULL;
+}
+
+static const char *set_limit_req_fieldsize(cmd_parms *cmd, void *dummy,
+                                           char *arg)
+{
+    const char *err = ap_check_cmd_context(cmd,
+                                           NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    int lim;
+
+    if (err != NULL) {
+        return err;
+    }
+    lim = atoi(arg);
+    if (lim < 0) {
+        return ap_pstrcat(cmd->temp_pool, "LimitRequestFieldsize \"", arg, 
+                          "\" must be a non-negative integer (0 = no limit)",
+                          NULL);
+    }
+    if (lim > DEFAULT_LIMIT_REQUEST_FIELDSIZE) {
+        return ap_psprintf(cmd->temp_pool, "LimitRequestFieldsize \"%s\" "
+                          "must not exceed the precompiled maximum of %d",
+                           arg, DEFAULT_LIMIT_REQUEST_FIELDSIZE);
+    }
+    cmd->server->limit_req_fieldsize = lim;
+    return NULL;
+}
+
+static const char *set_limit_req_fields(cmd_parms *cmd, void *dummy, char *arg)
+{
+    const char *err = ap_check_cmd_context(cmd,
+                                           NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    int lim;
+
+    if (err != NULL) {
+        return err;
+    }
+    lim = atoi(arg);
+    if (lim < 0) {
+        return ap_pstrcat(cmd->temp_pool, "LimitRequestFields \"", arg, 
+                          "\" must be a non-negative integer (0 = no limit)",
+                          NULL);
+    }
+    cmd->server->limit_req_fields = lim;
+    return NULL;
+}
+
+static const char *set_limit_req_body(cmd_parms *cmd, core_dir_config *conf,
+                                      char *arg) 
+{
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    /* WTF: If strtoul is not portable, then write a replacement.
+     *      Instead we have an idiotic define in httpd.h that prevents
+     *      it from being used even when it is available. Sheesh.
+     */
+    conf->limit_req_body = (unsigned long)ap_strtol(arg, (char **)NULL, 10);
+    return NULL;
+}
+
+#ifdef WIN32
+static const char *set_interpreter_source(cmd_parms *cmd, core_dir_config *d,
+                                                char *arg)
+{
+    if (!strcasecmp(arg, "registry")) {
+        d->script_interpreter_source = INTERPRETER_SOURCE_REGISTRY;
+    } else if (!strcasecmp(arg, "script")) {
+        d->script_interpreter_source = INTERPRETER_SOURCE_SHEBANG;
+    } else {
+        return ap_pstrcat(cmd->temp_pool, "ScriptInterpreterSource \"", arg, 
+                          "\" must be \"registry\" or \"script\"",
+                          NULL);
+    }
+    return NULL;
+}
+#endif
+
+static const char *set_cgi_command_args(cmd_parms *cmd,
+                                              void *mconfig,
+                                              int arg)
+{
+    core_dir_config *cfg = (core_dir_config *)mconfig;
+    cfg->cgi_command_args = arg ? AP_FLAG_ON : AP_FLAG_OFF;
+    return NULL;
+}
+
+#ifdef CHARSET_EBCDIC
+
+typedef struct {
+  char conv_out[2];
+  char conv_in[2];
+} parsed_conf_t;
+
+/* Check for conversion syntax:  { On | Off } [ = { In | Out | InOut } ] */
+static parsed_conf_t *
+parse_on_off_in_out(pool *p, char *arg)
+{
+    static parsed_conf_t ret = { { conv_Unset, '\0' }, { conv_Unset, '\0' } };
+    char *onoff = ap_getword_nc(p, &arg, '=');
+    int in = 0, out = 0, inout = 0;
+    char conv_val;
+
+    /* Check for valid syntax:  { On | Off } [ = { In | Out | InOut } ] */
+    if (strcasecmp(onoff, "On") == 0)
+        conv_val = conv_On;
+    else if (strcasecmp(onoff, "Off") == 0)
+        conv_val = conv_Off;
+    else
+        return NULL;
+
+    /* Check the syntax, and at the same time assign the test results */
+    if (!(inout = (*arg == '\0')) &&
+        !(in = (strcasecmp(arg, "In") == 0)) &&
+        !(out = (strcasecmp(arg, "Out") == 0)) &&
+        !(inout = (strcasecmp(arg, "InOut") == 0))) {
+        /* Invalid string, not conforming to syntax! */
+        return NULL;
+    }
+
+    ret.conv_in[0]  = (in || inout)  ? conv_val : conv_Unset;
+    ret.conv_out[0] = (out || inout) ? conv_val : conv_Unset;
+
+    return &ret;
+}
+
+
+/* Handle the EBCDICConvert directive:
+ *   EBCDICConvert {On|Off}[={In|Out|InOut}] ext ...
+ */
+static const char *
+add_conversion_by_ext(cmd_parms *cmd, core_dir_config *m,
+		      char *onoff, char *ext)
+{
+    parsed_conf_t *onoff_code = parse_on_off_in_out(cmd->pool, onoff);
+
+    if (onoff_code == NULL)
+        return "Invalid syntax: use EBCDICConvert {On|Off}[={In|Out|InOut}] ext [...]";
+
+    if (*ext == '.')
+        ++ext;
+
+    if (*onoff_code->conv_in != conv_Unset)
+	ap_table_addn(m->ebcdicconversion_by_ext_in, ext,
+		      ap_pstrndup(cmd->pool, onoff_code->conv_in, 1));
+    if (*onoff_code->conv_out != conv_Unset)
+	ap_table_addn(m->ebcdicconversion_by_ext_out, ext,
+		      ap_pstrndup(cmd->pool, onoff_code->conv_out, 1));
+
+    return NULL;
+}
+
+
+/* Handle the EBCDICConvertByType directive:
+ *   EBCDICConvertByType {On|Off}[={In|Out|InOut}] mimetype ...
+ */
+static const char *
+add_conversion_by_type(cmd_parms *cmd, core_dir_config *m,
+		       char *onoff, char *type)
+{
+    parsed_conf_t *onoff_code = parse_on_off_in_out(cmd->pool, onoff);
+
+    if (onoff_code == NULL)
+        return "Invalid syntax: use EBCDICConvertByType {On|Off}[={In|Out|InOut}] mimetype [...]";
+
+    if (*onoff_code->conv_in != conv_Unset)
+	ap_table_addn(m->ebcdicconversion_by_type_in, type,
+		      ap_pstrndup(cmd->pool, onoff_code->conv_in, 1));
+    if (*onoff_code->conv_out != conv_Unset)
+	ap_table_addn(m->ebcdicconversion_by_type_out, type,
+		      ap_pstrndup(cmd->pool, onoff_code->conv_out, 1));
+
+    return NULL;
+}
+
+
+/* Handle the EBCDICKludge directive:
+ *   EBCDICKludge {On|Off}
+ */
+#ifdef LEGACY_KLUDGE
+static const char *
+set_x_ascii_kludge(cmd_parms *cmd, core_dir_config *m, int arg)
+{
+    m->x_ascii_magic_kludge = arg;
+
+    return NULL;
+}
+#endif
+
+#if ADD_EBCDICCONVERT_DEBUG_HEADER
+/* Handle the EBCDICDebugHeader directive:
+ *   EBCDICDebugHeader {On|Off}
+ */
+static const char *
+set_debug_header(cmd_parms *cmd, core_dir_config *m, int arg)
+{
+    m->ebcdicconversion_debug_header = arg;
+
+    return NULL;
+}
+#endif
+#endif /* CHARSET_EBCDIC */
+
+/*
+ * Note what data should be used when forming file ETag values.
+ * It would be nicer to do this as an ITERATE, but then we couldn't
+ * remember the +/- state properly.
+ */
+static const char *set_etag_bits(cmd_parms *cmd, void *mconfig,
+                                 const char *args_p)
+{
+    core_dir_config *cfg;
+    etag_components_t bit;
+    char action;
+    char *token;
+    const char *args;
+    int valid;
+    int first;
+    int explicit;
+
+    cfg = (core_dir_config *) mconfig;
+
+    args = args_p;
+    first = 1;
+    explicit = 0;
+    while (args[0] != '\0') {
+        action = '*';
+        bit = ETAG_UNSET;
+        valid = 1;
+        token = ap_getword_conf(cmd->pool, &args);
+        if ((*token == '+') || (*token == '-')) {
+            action = *token;
+            token++;
+        }
+        else {
+            /*
+             * The occurrence of an absolute setting wipes
+             * out any previous relative ones.  The first such
+             * occurrence forgets any inherited ones, too.
+             */
+            if (first) {
+                cfg->etag_bits = ETAG_UNSET;
+                cfg->etag_add = ETAG_UNSET;
+                cfg->etag_remove = ETAG_UNSET;
+                first = 0;
+            }
+        }
+
+        if (strcasecmp(token, "None") == 0) {
+            if (action != '*') {
+                valid = 0;
+            }
+            else {
+                cfg->etag_bits = bit = ETAG_NONE;
+                explicit = 1;
+            }
+        }
+        else if (strcasecmp(token, "All") == 0) {
+            if (action != '*') {
+                valid = 0;
+            }
+            else {
+                explicit = 1;
+                cfg->etag_bits = bit = ETAG_ALL;
+            }
+        }
+        else if (strcasecmp(token, "Size") == 0) {
+            bit = ETAG_SIZE;
+        }
+        else if ((strcasecmp(token, "LMTime") == 0)
+                 || (strcasecmp(token, "MTime") == 0)
+                 || (strcasecmp(token, "LastModified") == 0)) {
+            bit = ETAG_MTIME;
+        }
+        else if (strcasecmp(token, "INode") == 0) {
+            bit = ETAG_INODE;
+        }
+        else {
+            return ap_pstrcat(cmd->pool, "Unknown keyword '",
+                              token, "' for ", cmd->cmd->name,
+                              " directive", NULL);
+        }
+
+        if (! valid) {
+            return ap_pstrcat(cmd->pool, cmd->cmd->name, " keyword '",
+                              token, "' cannot be used with '+' or '-'",
+                              NULL);
+        }
+
+        if (action == '+') {
+            /*
+             * Make sure it's in the 'add' list and absent from the
+             * 'subtract' list.
+             */
+            cfg->etag_add |= bit;
+            cfg->etag_remove &= (~ bit);
+        }
+        else if (action == '-') {
+            cfg->etag_remove |= bit;
+            cfg->etag_add &= (~ bit);
+        }
+        else {
+            /*
+             * Non-relative values wipe out any + or - values
+             * accumulated so far.
+             */
+            cfg->etag_bits |= bit;
+            cfg->etag_add = ETAG_UNSET;
+            cfg->etag_remove = ETAG_UNSET;
+            explicit = 1;
+        }
+    }
+
+    /*
+     * Any setting at all will clear the 'None' and 'Unset' bits.
+     */
+
+    if (cfg->etag_add != ETAG_UNSET) {
+        cfg->etag_add &= (~ ETAG_UNSET);
+    }
+    if (cfg->etag_remove != ETAG_UNSET) {
+        cfg->etag_remove &= (~ ETAG_UNSET);
+    }
+    if (explicit) {
+        cfg->etag_bits &= (~ ETAG_UNSET);
+        if ((cfg->etag_bits & ETAG_NONE) != ETAG_NONE) {
+            cfg->etag_bits &= (~ ETAG_NONE);
+        }
+    }
+    return NULL;
+}
+
+static const char *set_recursion_limit(cmd_parms *cmd, void *dummy,
+                                       const char *arg1, const char *arg2)
+{
+    core_server_config *conf = ap_get_module_config(cmd->server->module_config,
+                                                    &core_module);
+    int limit = atoi(arg1);
+
+    if (limit < 0) {
+        return "The redirect recursion limit cannot be less than zero.";
+    }
+    if (limit && limit < 4) {
+        ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, cmd->server,
+                     "Limiting internal redirects to very low numbers may "
+                     "cause normal requests to fail.");
+    }
+
+    conf->redirect_limit = limit;
+
+    if (arg2) {
+        limit = atoi(arg2);
+
+        if (limit < 0) {
+            return "The subrequest recursion limit cannot be less than zero.";
+        }
+        if (limit && limit < 4) {
+            ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, cmd->server,
+                         "Limiting the subrequest depth to a very low level may"
+                         " cause normal requests to fail.");
+        }
+    }
+
+    conf->subreq_limit = limit;
+    conf->recursion_limit_set = 1;
+
+    return NULL;
+}
+
+static void log_backtrace(const request_rec *r)
+{
+    const request_rec *top = r;
+
+    ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,
+                  "r->uri = %s", r->uri ? r->uri : "(unexpectedly NULL)");
+
+    while (top && (top->prev || top->main)) {
+        if (top->prev) {
+            top = top->prev;
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,
+                          "redirected from r->uri = %s",
+                          top->uri ? top->uri : "(unexpectedly NULL)");
+        }
+
+        if (!top->prev && top->main) {
+            top = top->main;
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,
+                          "subrequested from r->uri = %s",
+                          top->uri ? top->uri : "(unexpectedly NULL)");
+        }
+    }
+}
+
+/*
+ * check whether redirect limit is reached
+ */
+API_EXPORT(int) ap_is_recursion_limit_exceeded(const request_rec *r)
+{
+    core_server_config *conf = ap_get_module_config(r->server->module_config,
+                                                    &core_module);
+    const request_rec *top = r;
+    int redirects = 0, subreqs = 0;
+    int rlimit = conf->recursion_limit_set
+                 ? conf->redirect_limit
+                 : AP_DEFAULT_MAX_INTERNAL_REDIRECTS;
+    int slimit = conf->recursion_limit_set
+                 ? conf->subreq_limit
+                 : AP_DEFAULT_MAX_SUBREQ_DEPTH;
+
+    /* fast exit (unlimited) */
+    if (!rlimit && !slimit) {
+        return 0;
+    }
+
+    while (top->prev || top->main) {
+        if (top->prev) {
+            if (rlimit && ++redirects >= rlimit) {
+                /* uuh, too much. */
+                ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
+                              "Request exceeded the limit of %d internal "
+                              "redirects due to probable configuration error. "
+                              "Use 'LimitInternalRecursion' to increase the "
+                              "limit if necessary. Use 'LogLevel debug' to get "
+                              "a backtrace.", rlimit);
+
+                /* post backtrace */
+                log_backtrace(r);
+
+                /* return failure */
+                return 1;
+            }
+
+            top = top->prev;
+        }
+
+        if (!top->prev && top->main) {
+            if (slimit && ++subreqs >= slimit) {
+                /* uuh, too much. */
+                ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
+                              "Request exceeded the limit of %d subrequest "
+                              "nesting levels due to probable confguration "
+                              "error. Use 'LimitInternalRecursion' to increase "
+                              "the limit if necessary. Use 'LogLevel debug' to "
+                              "get a backtrace.", slimit);
+
+                /* post backtrace */
+                log_backtrace(r);
+
+                /* return failure */
+                return 1;
+            }
+
+            top = top->main;
+        }
+    }
+
+    /* recursion state: ok */
+    return 0;
+}
+
+/* Note --- ErrorDocument will now work from .htaccess files.  
+ * The AllowOverride of Fileinfo allows webmasters to turn it off
+ */
+
+static const command_rec core_cmds[] = {
+
+/* Old access config file commands */
+
+{ "<Directory", dirsection, NULL, RSRC_CONF, RAW_ARGS,
+  "Container for directives affecting resources located in the specified "
+  "directories" },
+{ end_directory_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
+  "Marks end of <Directory>" },
+{ "<Location", urlsection, NULL, RSRC_CONF, RAW_ARGS,
+  "Container for directives affecting resources accessed through the "
+  "specified URL paths" },
+{ end_location_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
+  "Marks end of <Location>" },
+{ "<VirtualHost", virtualhost_section, NULL, RSRC_CONF, RAW_ARGS,
+  "Container to map directives to a particular virtual host, takes one or "
+  "more host addresses" },
+{ end_virtualhost_section, end_nested_section, NULL, RSRC_CONF, NO_ARGS,
+  "Marks end of <VirtualHost>" },
+{ "<Files", filesection, NULL, OR_ALL, RAW_ARGS, "Container for directives "
+  "affecting files matching specified patterns" },
+{ end_files_section, end_nested_section, NULL, OR_ALL, NO_ARGS,
+  "Marks end of <Files>" },
+{ "<Limit", ap_limit_section, NULL, OR_ALL, RAW_ARGS, "Container for "
+  "authentication directives when accessed using specified HTTP methods" },
+{ "</Limit>", endlimit_section, NULL, OR_ALL, NO_ARGS,
+  "Marks end of <Limit>" },
+{ "<LimitExcept", ap_limit_section, (void*)1, OR_ALL, RAW_ARGS,
+  "Container for authentication directives to be applied when any HTTP "
+  "method other than those specified is used to access the resource" },
+{ "</LimitExcept>", endlimit_section, (void*)1, OR_ALL, NO_ARGS,
+  "Marks end of <LimitExcept>" },
+{ "<IfModule", start_ifmod, NULL, OR_ALL, TAKE1,
+  "Container for directives based on existance of specified modules" },
+{ end_ifmodule_section, end_ifmod, NULL, OR_ALL, NO_ARGS,
+  "Marks end of <IfModule>" },
+{ "<IfDefine", start_ifdefine, NULL, OR_ALL, TAKE1,
+  "Container for directives based on existance of command line defines" },
+{ end_ifdefine_section, end_ifdefine, NULL, OR_ALL, NO_ARGS,
+  "Marks end of <IfDefine>" },
+{ "<DirectoryMatch", dirsection, (void*)1, RSRC_CONF, RAW_ARGS,
+  "Container for directives affecting resources located in the "
+  "specified directories" },
+{ end_directorymatch_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
+  "Marks end of <DirectoryMatch>" },
+{ "<LocationMatch", urlsection, (void*)1, RSRC_CONF, RAW_ARGS,
+  "Container for directives affecting resources accessed through the "
+  "specified URL paths" },
+{ end_locationmatch_section, end_nested_section, NULL, ACCESS_CONF, NO_ARGS,
+  "Marks end of <LocationMatch>" },
+{ "<FilesMatch", filesection, (void*)1, OR_ALL, RAW_ARGS,
+  "Container for directives affecting files matching specified patterns" },
+{ end_filesmatch_section, end_nested_section, NULL, OR_ALL, NO_ARGS,
+  "Marks end of <FilesMatch>" },
+{ "AuthType", ap_set_string_slot,
+  (void*)XtOffsetOf(core_dir_config, ap_auth_type), OR_AUTHCFG, TAKE1,
+  "An HTTP authorization type (e.g., \"Basic\")" },
+{ "AuthName", set_authname, NULL, OR_AUTHCFG, TAKE1,
+  "The authentication realm (e.g. \"Members Only\")" },
+{ "AuthDigestRealmSeed", set_authnonce, NULL, OR_AUTHCFG, TAKE1,
+  "An authentication token which should be different for each logical realm. "\
+  "A random value or the servers IP may be a good choise.\n" },
+{ "Require", require, NULL, OR_AUTHCFG, RAW_ARGS,
+  "Selects which authenticated users or groups may access a protected space" },
+{ "Satisfy", satisfy, NULL, OR_AUTHCFG, TAKE1,
+  "access policy if both allow and require used ('all' or 'any')" },    
+#ifdef GPROF
+{ "GprofDir", set_gprof_dir, NULL, RSRC_CONF, TAKE1,
+  "Directory to plop gmon.out files" },
+#endif
+{ "AddDefaultCharset", set_add_default_charset, NULL, OR_FILEINFO, 
+  TAKE1, "The name of the default charset to add to any Content-Type without one or 'Off' to disable" },
+
+/* Old resource config file commands */
+  
+{ "AccessFileName", set_access_name, NULL, RSRC_CONF, RAW_ARGS,
+  "Name(s) of per-directory config files (default: .htaccess)" },
+{ "DocumentRoot", set_document_root, NULL, RSRC_CONF, TAKE1,
+  "Root directory of the document tree"  },
+{ "ErrorDocument", set_error_document, NULL, OR_FILEINFO, RAW_ARGS,
+  "Change responses for HTTP errors" },
+{ "AllowOverride", set_override, NULL, ACCESS_CONF, RAW_ARGS,
+  "Controls what groups of directives can be configured by per-directory "
+  "config files" },
+{ "Options", set_options, NULL, OR_OPTIONS, RAW_ARGS,
+  "Set a number of attributes for a given directory" },
+{ "DefaultType", ap_set_string_slot,
+  (void*)XtOffsetOf (core_dir_config, ap_default_type),
+  OR_FILEINFO, TAKE1, "the default MIME type for untypable files" },
+
+/* Old server config file commands */
+
+{ "ServerType", server_type, NULL, RSRC_CONF, TAKE1,
+  "'inetd' or 'standalone'"},
+{ "Port", server_port, NULL, RSRC_CONF, TAKE1, "A TCP port number"},
+{ "HostnameLookups", set_hostname_lookups, NULL, ACCESS_CONF|RSRC_CONF, TAKE1,
+  "\"on\" to enable, \"off\" to disable reverse DNS lookups, or \"double\" to "
+  "enable double-reverse DNS lookups" },
+{ "User", set_user, NULL, RSRC_CONF, TAKE1,
+  "Effective user id for this server"},
+{ "Group", set_group, NULL, RSRC_CONF, TAKE1,
+  "Effective group id for this server"},
+{ "ServerAdmin", set_server_string_slot,
+  (void *)XtOffsetOf (server_rec, server_admin), RSRC_CONF, TAKE1,
+  "The email address of the server administrator" },
+{ "ServerName", set_server_string_slot,
+  (void *)XtOffsetOf (server_rec, server_hostname), RSRC_CONF, TAKE1,
+  "The hostname of the server" },
+{ "ServerSignature", set_signature_flag, NULL, OR_ALL, TAKE1,
+  "En-/disable server signature (on|off|email)" },
+{ "ServerRoot", set_server_root, NULL, RSRC_CONF, TAKE1,
+  "Common directory of server-related files (logs, confs, etc.)" },
+{ "ErrorLog", set_server_string_slot,
+  (void *)XtOffsetOf (server_rec, error_fname), RSRC_CONF, TAKE1,
+  "The filename of the error log" },
+{ "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1,
+    "A file for logging the server process ID"},
+{ "ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, TAKE1,
+    "A file for Apache to maintain runtime process management information"},
+{ "LockFile", set_lockfile, NULL, RSRC_CONF, TAKE1,
+    "The lockfile used when Apache needs to lock the accept() call"},
+{ "AccessConfig", set_server_string_slot,
+  (void *)XtOffsetOf (server_rec, access_confname), RSRC_CONF, TAKE1,
+  "The filename of the access config file" },
+{ "ResourceConfig", set_server_string_slot,
+  (void *)XtOffsetOf (server_rec, srm_confname), RSRC_CONF, TAKE1,
+  "The filename of the resource config file" },
+{ "ServerAlias", set_server_alias, NULL, RSRC_CONF, RAW_ARGS,
+  "A name or names alternately used to access the server" },
+{ "ServerPath", set_serverpath, NULL, RSRC_CONF, TAKE1,
+  "The pathname the server can be reached at" },
+{ "Timeout", set_timeout, NULL, RSRC_CONF, TAKE1, "Timeout duration (sec)" },
+{ "KeepAliveTimeout", set_keep_alive_timeout, NULL, RSRC_CONF, TAKE1,
+  "Keep-Alive timeout duration (sec)"},
+{ "MaxKeepAliveRequests", set_keep_alive_max, NULL, RSRC_CONF, TAKE1,
+  "Maximum number of Keep-Alive requests per connection, or 0 for infinite" },
+{ "KeepAlive", set_keep_alive, NULL, RSRC_CONF, TAKE1,
+  "Whether persistent connections should be On or Off" },
+{ "IdentityCheck", set_idcheck, NULL, RSRC_CONF|ACCESS_CONF, FLAG,
+  "Enable identd (RFC 1413) user lookups - SLOW" },
+{ "ContentDigest", set_content_md5, NULL, OR_OPTIONS,
+  FLAG, "whether or not to send a Content-MD5 header with each request" },
+{ "UseCanonicalName", set_use_canonical_name, NULL,
+  RSRC_CONF|ACCESS_CONF, TAKE1,
+  "How to work out the ServerName : Port when constructing URLs" },
+{ "StartServers", set_daemons_to_start, NULL, RSRC_CONF, TAKE1,
+  "Number of child processes launched at server startup" },
+{ "MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, TAKE1,
+  "Minimum number of idle children, to handle request spikes" },
+{ "MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1,
+  "Maximum number of idle children" },
+{ "MaxServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1,
+  "Deprecated equivalent to MaxSpareServers" },
+{ "ServersSafetyLimit", set_server_limit, NULL, RSRC_CONF, TAKE1,
+  "Deprecated equivalent to MaxClients" },
+{ "MaxClients", set_server_limit, NULL, RSRC_CONF, TAKE1,
+  "Maximum number of children alive at the same time" },
+{ "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1,
+  "Maximum number of requests a particular child serves before dying." },
+{ "RLimitCPU",
+#ifdef RLIMIT_CPU
+  set_limit_cpu, (void*)XtOffsetOf(core_dir_config, limit_cpu),
+#else
+  no_set_limit, NULL,
+#endif
+  OR_ALL, TAKE12, "Soft/hard limits for max CPU usage in seconds" },
+{ "RLimitMEM",
+#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined (RLIMIT_AS)
+  set_limit_mem, (void*)XtOffsetOf(core_dir_config, limit_mem),
+#else
+  no_set_limit, NULL,
+#endif
+  OR_ALL, TAKE12, "Soft/hard limits for max memory usage per process" },
+{ "RLimitNPROC",
+#ifdef RLIMIT_NPROC
+  set_limit_nproc, (void*)XtOffsetOf(core_dir_config, limit_nproc),
+#else
+  no_set_limit, NULL,
+#endif
+   OR_ALL, TAKE12, "soft/hard limits for max number of processes per uid" },
+{ "BindAddress", set_bind_address, NULL, RSRC_CONF, TAKE1,
+  "'*', a numeric IP address, or the name of a host with a unique IP address"},
+#ifdef NETWARE
+{ "ThreadStackSize", set_threadstacksize, NULL, RSRC_CONF, TAKE1,
+  "Stack size each created thread will use."},
+#endif
+{ "Listen", set_listener, NULL, RSRC_CONF, TAKE1,
+  "A port number or a numeric IP address and a port number"},
+{ "SendBufferSize", set_send_buffer_size, NULL, RSRC_CONF, TAKE1,
+  "Send buffer size in bytes"},
+{ "AddModule", add_module_command, NULL, RSRC_CONF, ITERATE,
+  "The name of a module" },
+{ "ClearModuleList", clear_module_list_command, NULL, RSRC_CONF, NO_ARGS, 
+  NULL },
+{ "ThreadsPerChild", set_threads, NULL, RSRC_CONF, TAKE1,
+  "Number of threads a child creates" },
+{ "ExcessRequestsPerChild", set_excess_requests, NULL, RSRC_CONF, TAKE1,
+  "Maximum number of requests a particular child serves after it is ready "
+  "to die." },
+{ "ListenBacklog", set_listenbacklog, NULL, RSRC_CONF, TAKE1,
+  "Maximum length of the queue of pending connections, as used by listen(2)" },
+{ "AcceptFilter", set_acceptfilter, NULL, RSRC_CONF, FLAG,
+  "Switch AcceptFiltering on/off (default is "
+#ifdef AP_ACCEPTFILTER_OFF
+	"off"
+#else
+	"on"
+#endif
+	")."
+#ifndef SO_ACCEPTFILTER
+	"This feature is currently not compiled in; so this directive "
+	"is ignored."
+#endif
+   },
+{ "CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, TAKE1,
+  "The location of the directory Apache changes to before dumping core" },
+{ "Include", include_config, NULL, (RSRC_CONF | ACCESS_CONF), TAKE1,
+  "Name of the config file to be included" },
+{ "LogLevel", set_loglevel, NULL, RSRC_CONF, TAKE1,
+  "Level of verbosity in error logging" },
+{ "NameVirtualHost", ap_set_name_virtual_host, NULL, RSRC_CONF, TAKE1,
+  "A numeric IP address:port, or the name of a host" },
+#ifdef _OSD_POSIX
+{ "BS2000Account", set_bs2000_account, NULL, RSRC_CONF, TAKE1,
+  "Name of server User's bs2000 logon account name" },
+#endif
+#ifdef WIN32
+{ "ScriptInterpreterSource", set_interpreter_source, NULL, OR_FILEINFO, TAKE1,
+  "Where to find interpreter to run Win32 scripts - Registry or Script (shebang line)" },
+#endif
+{ "CGICommandArgs", set_cgi_command_args, NULL, OR_OPTIONS, FLAG,
+  "Allow or Disallow CGI requests to pass args on the command line" },
+{ "ServerTokens", set_serv_tokens, NULL, RSRC_CONF, TAKE1,
+  "Tokens displayed in the Server: header - Min[imal], OS, Prod[uctOnly], Full" },
+{ "LimitRequestLine", set_limit_req_line, NULL, RSRC_CONF, TAKE1,
+  "Limit on maximum size of an HTTP request line"},
+{ "LimitRequestFieldsize", set_limit_req_fieldsize, NULL, RSRC_CONF, TAKE1,
+  "Limit on maximum size of an HTTP request header field"},
+{ "LimitRequestFields", set_limit_req_fields, NULL, RSRC_CONF, TAKE1,
+  "Limit (0 = unlimited) on max number of header fields in a request message"},
+{ "LimitRequestBody", set_limit_req_body,
+  (void*)XtOffsetOf(core_dir_config, limit_req_body),
+  OR_ALL, TAKE1,
+  "Limit (in bytes) on maximum size of request message body" },
+{ "ProtocolReqCheck", set_protocol_req_check, NULL, RSRC_CONF, FLAG,
+  "Enable strict checking of Protocol type in requests" },
+{ "ShmemUIDisUser", set_change_shmem_uid, NULL, RSRC_CONF, FLAG,
+  "Enable the setting of SysV shared memory scoreboard uid/gid to User/Group" },
+{ "AcceptMutex", set_accept_mutex, NULL, RSRC_CONF, TAKE1,
+  "Serialized Accept Mutex; the methods " 
+#ifdef HAVE_USLOCK_SERIALIZED_ACCEPT
+    "'uslock' "                           
+#endif
+#ifdef HAVE_PTHREAD_SERIALIZED_ACCEPT
+    "'pthread' "
+#endif
+#ifdef HAVE_SYSVSEM_SERIALIZED_ACCEPT
+    "'sysvsem' "
+#endif
+#ifdef HAVE_FCNTL_SERIALIZED_ACCEPT
+    "'fcntl' "
+#endif
+#ifdef HAVE_FLOCK_SERIALIZED_ACCEPT
+    "'flock' "
+#endif
+#ifdef HAVE_OS2SEM_SERIALIZED_ACCEPT
+    "'os2sem' "
+#endif
+#ifdef HAVE_TPF_CORE_SERIALIZED_ACCEPT
+    "'tpfcore' "
+#endif
+#ifdef HAVE_BEOS_SERIALIZED_ACCEPT
+    "'beos_sem' "
+#endif
+#ifdef HAVE_NONE_SERIALIZED_ACCEPT
+    "'none' "
+#endif
+    "are compiled in"
+},
+#ifdef AP_ENABLE_EXCEPTION_HOOK
+{ "EnableExceptionHook", set_exception_hook, NULL, RSRC_CONF, TAKE1,
+  "Controls whether exception hook may be called after a crash" },
+#endif
+
+/* EBCDIC Conversion directives: */
+#ifdef CHARSET_EBCDIC
+{ "EBCDICConvert", add_conversion_by_ext, NULL, OR_FILEINFO, ITERATE2,
+    "{On|Off}[={In|Out|InOut}] followed by one or more file extensions" },
+{ "EBCDICConvertByType", add_conversion_by_type, NULL, OR_FILEINFO, ITERATE2,
+    "{On|Off}[={In|Out|InOut}] followed by one or more MIME types" },
+#ifdef LEGACY_KLUDGE
+{ "EBCDICKludge", set_x_ascii_kludge, NULL, OR_FILEINFO, FLAG,
+    "'On': enable or default='Off': disable the old text/x-ascii-mimetype kludge" },
+#endif
+#if ADD_EBCDICCONVERT_DEBUG_HEADER
+{ "EBCDICDebugHeader", set_debug_header, NULL, OR_FILEINFO, FLAG,
+    "'On': enable or default='Off': disable the EBCDIC Debugging MIME Header" },
+#endif
+#endif /* CHARSET_EBCDIC */
+
+{ "FileETag", set_etag_bits, NULL, OR_FILEINFO, RAW_ARGS,
+  "Specify components used to construct a file's ETag"},
+
+{ "LimitInternalRecursion", set_recursion_limit, NULL, RSRC_CONF, TAKE12,
+  "maximum recursion depth of internal redirects and subrequests"},
+
+{ NULL }
+};
+
+/*****************************************************************
+ *
+ * Core handlers for various phases of server operation...
+ */
+
+static int core_translate(request_rec *r)
+{
+    void *sconf = r->server->module_config;
+    core_server_config *conf = ap_get_module_config(sconf, &core_module);
+  
+    if (r->proxyreq != NOT_PROXY) {
+        return HTTP_FORBIDDEN;
+    }
+    if ((r->uri[0] != '/') && strcmp(r->uri, "*")) {
+	ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+		     "Invalid URI in request %s", r->the_request);
+	return BAD_REQUEST;
+    }
+    
+    if (r->server->path 
+	&& !strncmp(r->uri, r->server->path, r->server->pathlen)
+	&& (r->server->path[r->server->pathlen - 1] == '/'
+	    || r->uri[r->server->pathlen] == '/'
+	    || r->uri[r->server->pathlen] == '\0')) {
+        r->filename = ap_pstrcat(r->pool, conf->ap_document_root,
+				 (r->uri + r->server->pathlen), NULL);
+    }
+    else {
+	/*
+         * Make sure that we do not mess up the translation by adding two
+         * /'s in a row.  This happens under windows when the document
+         * root ends with a /
+         */
+        if ((conf->ap_document_root[strlen(conf->ap_document_root)-1] == '/')
+	    && (*(r->uri) == '/')) {
+	    r->filename = ap_pstrcat(r->pool, conf->ap_document_root, r->uri+1,
+				     NULL);
+	}
+	else {
+	    r->filename = ap_pstrcat(r->pool, conf->ap_document_root, r->uri,
+				     NULL);
+	}
+    }
+
+    return OK;
+}
+
+static int do_nothing(request_rec *r) { return OK; }
+
+#ifdef CHARSET_EBCDIC
+struct do_mime_match_parms {
+    request_rec *request;     /* [In] current request_rec */
+    int direction;            /* [In] determine conversion for: dir_In|dir_Out */
+    const char *content_type; /* [In] Content-Type (dir_In: from MIME Header, else r->content_type) */
+    int match_found;          /* [Out] nonzero if a match was found */
+    int conv;                 /* [Out] conversion setting if match was found */
+};
+
+
+/* This routine is called for each mime type configured by the
+ * EBCDICConvertByType directive.
+ */
+static int
+do_mime_match(void *rec, const char *key, const char *val)
+{
+    int conv = (val[0] == conv_On);
+    const char *content_type;
+#if ADD_EBCDICCONVERT_DEBUG_HEADER
+    request_rec *r = ((struct do_mime_match_parms *) rec)->request;
+#endif
+
+    ((struct do_mime_match_parms *) rec)->match_found = 0;
+    ((struct do_mime_match_parms *) rec)->conv = conv_Unset;
+
+    content_type = ((struct do_mime_match_parms *) rec)->content_type;
+
+    /* If no type set: no need to continue */
+    if (content_type == NULL)
+        return 0;
+
+    /* If the MIME type matches, set the conversion flag appropriately */
+    if ((ap_is_matchexp(key) && ap_strcasecmp_match(content_type, key) == 0)
+        || (strcasecmp(key, content_type) == 0)) {
+
+        ((struct do_mime_match_parms *) rec)->match_found = 1;
+        ((struct do_mime_match_parms *) rec)->conv = conv;
+
+#if ADD_EBCDICCONVERT_DEBUG_HEADER
+	ap_table_setn(r->headers_out,
+               ((((struct do_mime_match_parms *) rec)->direction) == dir_In)
+		      ? "X-EBCDIC-Debug-In" : "X-EBCDIC-Debug-Out",
+                       ap_psprintf(r->pool, "EBCDICConversionByType %s %s",
+                                   conv ? "On" : "Off",
+                                   key));
+#endif
+
+        /* the mime type scan stops at the first  match. */
+        return 0;
+    }
+
+    return 1;
+}
+
+static void
+ap_checkconv_dir(request_rec *r, const char **pType, int dir)
+{
+    core_dir_config *conf =
+    (core_dir_config *) ap_get_module_config(r->per_dir_config, &core_module);
+    table *conv_by_ext, *conv_by_type;
+    const char *type, *conversion;
+    char *ext;
+    int conv_valid = 0, conv;
+
+    conv_by_ext  = (dir == dir_In) ? conf->ebcdicconversion_by_ext_in  : conf->ebcdicconversion_by_ext_out;
+    conv_by_type = (dir == dir_In) ? conf->ebcdicconversion_by_type_in : conf->ebcdicconversion_by_type_out;
+
+    type = (*pType == NULL) ? ap_default_type(r) : *pType;
+
+    /* Pseudo "loop" which is executed once only, with break's at individual steps */
+    do {
+        /* Step 0: directories result in redirections or in directory listings.
+	 * Both are EBCDIC text documents.
+	 * @@@ Should we check for the handler instead?
+	 */
+        if (S_ISDIR(r->finfo.st_mode) && dir == dir_Out) {
+            conv = conv_valid = 1;
+            break;
+        }
+
+        /* 1st step: check the binding on file extension. This allows us to
+         * override the conversion default based on a specific name.
+         * For instance, the following would allow some HTML files
+         * to be converted (.html) and others passed unconverted (.ahtml):
+         *     AddType text/html .html .ahtml
+         *     EBCDICConvert Off .ahtml
+         * For uploads, this assumes that the destination file name
+	 * has the correct extension. That may not be true for, e.g.,
+	 * Netscape Communicator roaming profile uploads!
+         */
+        if (r->filename && !ap_is_empty_table(conv_by_ext)) {
+            const char *fn = strrchr(r->filename, '/');
+
+            if (fn == NULL)
+                fn = r->filename;
+
+            /* Parse filename extension */
+            if ((ext = strrchr(fn, '.')) != NULL) {
+                ++ext;
+
+                /* Check for Content-Type */
+                if ((conversion = ap_table_get(conv_by_ext, ext)) != NULL) {
+
+#if ADD_EBCDICCONVERT_DEBUG_HEADER
+		    if (conf->ebcdicconversion_debug_header)
+		        ap_table_setn(r->headers_out,
+				      (dir == dir_In) ? "X-EBCDIC-Debug-In" : "X-EBCDIC-Debug-Out",
+				      ap_psprintf(r->pool, "EBCDICConversion %s .%s",
+						  (conversion[0] == conv_On) ? "On" : "Off",
+						  ext));
+#endif
+
+                    conv = (conversion[0] == conv_On);
+                    conv_valid = 1;
+                    break;
+                }
+            }
+        }
+
+
+        /* 2nd step: test for the old "legacy kludge", that is, a default
+         * conversion=on for text/?* message/?* multipart/?* and the possibility
+         * to override the text/?* conversion with a definition like
+         *    AddType text/x-ascii-plain .atxt
+         *    AddType text/x-ascii-html  .ahtml
+         * where the "x-ascii-" would be removed and the conversion switched
+         * off.
+         * This step must be performed prior to testing wildcard MIME types
+         * like text/?* by the EBCDICConvertByType directive.
+         */
+#ifdef LEGACY_KLUDGE
+        /* This fallback is only used when enabled (default=off) */
+        if (conf->x_ascii_magic_kludge) {
+            char *magic;
+
+            /* If the mime type of a document is set to
+             * "text/x-ascii-anything", it gets changed to
+             * "text/anything" here and the conversion is forced to off
+             * ("binary" or ASCII documents).
+             */
+            if (*pType != NULL
+                && (magic = strstr(*pType, "/x-ascii-")) != NULL) {
+
+#if ADD_EBCDICCONVERT_DEBUG_HEADER
+		if (conf->ebcdicconversion_debug_header)
+		    ap_table_setn(r->headers_out,
+				  (dir == dir_In) ? "X-EBCDIC-Debug-In" : "X-EBCDIC-Debug-Out",
+				  ap_psprintf(r->pool, "EBCDICKludge On (and type is: %s, thus no conversion)",
+					      *pType));
+#endif
+
+                /* the mime type scan stops at the first  match. */
+                magic[1] = '\0';        /* overwrite 'x' */
+
+                /* Fix MIME type: strip out the magic "x-ascii-" substring */
+                *pType = ap_pstrcat(r->pool, *pType, &magic[9], NULL);
+
+                magic[1] = 'x'; /* restore 'x' in old string (just in case) */
+
+                /* Switch conversion to BINARY */
+                conv = 0;       /* do NOT convert this document */
+                conv_valid = 1;
+                break;
+            }
+        }
+#endif /*LEGACY_KLUDGE */
+
+
+        /* 3rd step: check whether a generic conversion was defined for a MIME type,
+         * like in
+         *    EBCDICConvertByType  On  model/vrml application/postscript text/?*
+         */
+        if (!ap_is_empty_table(conv_by_type)) {
+            struct do_mime_match_parms do_par;
+
+            do_par.request = r;
+            do_par.direction = dir;
+	    do_par.content_type = type;
+
+            ap_table_do(do_mime_match, (void *) &do_par, conv_by_type, NULL);
+
+            if ((conv_valid = do_par.match_found) != 0) {
+                conv = do_par.conv;
+                break;
+            }
+        }
+        else /* If no conversion by type was configured, use the default: */
+        {
+            /*
+             * As a final step, mime types starting with "text/", "message/" or
+             * "multipart/" imply a conversion, while all the rest is
+             * delivered unconverted (i.e., binary, e.g. application/octet-stream).
+             */
+
+            /* If no content type is set then treat it as text (conversion=on) */
+            conv =
+                (type == NULL) ||
+                (strncasecmp(type, "text/", 5) == 0) ||
+                (strncasecmp(type, "message/", 8) == 0) ||
+                (strncasecmp(type, "multipart/", 10) == 0) ||
+                (strcasecmp(type, "application/x-www-form-urlencoded") == 0);
+
+#if ADD_EBCDICCONVERT_DEBUG_HEADER
+		if (conf->ebcdicconversion_debug_header)
+		    ap_table_setn(r->headers_out,
+				  (dir == dir_In) ? "X-EBCDIC-Debug-In" : "X-EBCDIC-Debug-Out",
+				  ap_psprintf(r->pool,
+					      "No EBCDICConversion configured (and type is: %s, "
+					      "=> guessed conversion = %s)",
+					      type, conv ? "On" : "Off"));
+#endif
+            conv_valid = 1;
+            break;
+        }
+    } while (0);
+
+    if (conv_valid) {
+        if (dir == dir_In)
+            r->ebcdic.conv_in = conv;
+        else
+            r->ebcdic.conv_out = conv;
+    }
+}
+
+/* This function determines the conversion for uploads (PUT/POST): */
+API_EXPORT(int)
+ap_checkconv_in(request_rec *r)
+{
+    const char *typep;
+
+    /* If nothing is being sent as input anyway, we don't bother about conversion */
+    /* (see ap_should_client_block())*/
+    if (r->read_length || (!r->read_chunked && (r->remaining <= 0)))
+        return r->ebcdic.conv_in;
+
+    typep = ap_table_get(r->headers_in, "Content-Type");
+    ap_checkconv_dir(r, &typep, dir_In);
+
+    return r->ebcdic.conv_in;
+}
+
+
+/* Backward compatibility function */
+API_EXPORT(int)
+ap_checkconv(request_rec *r)
+{
+    ap_checkconv_dir(r, &r->content_type, dir_Out);
+    return r->ebcdic.conv_out;
+}
+
+#endif /* CHARSET_EBCDIC */
+
+
+#ifdef USE_MMAP_FILES
+struct mmap_rec {
+    void *mm;
+    size_t length;
+};
+
+static void mmap_cleanup(void *mmv)
+{
+    struct mmap_rec *mmd = mmv;
+
+    if (munmap(mmd->mm, mmd->length) == -1) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, NULL,
+                     "Failed to munmap memory of length %ld at 0x%lx",
+                     (long) mmd->length, (long) mmd->mm);
+    }
+}
+#endif
+
+/*
+ * Default handler for MIME types without other handlers.  Only GET
+ * and OPTIONS at this point... anyone who wants to write a generic
+ * handler for PUT or POST is free to do so, but it seems unwise to provide
+ * any defaults yet... So, for now, we assume that this will always be
+ * the last handler called and return 405 or 501.
+ */
+
+static int default_handler(request_rec *r)
+{
+    core_dir_config *d =
+      (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
+    int rangestatus, errstatus;
+    FILE *f;
+#ifdef USE_MMAP_FILES
+    caddr_t mm;
+#endif
+
+    /* This handler has no use for a request body (yet), but we still
+     * need to read and discard it if the client sent one.
+     */
+    if ((errstatus = ap_discard_request_body(r)) != OK) {
+        return errstatus;
+    }
+
+    r->allowed |= (1 << M_GET) | (1 << M_OPTIONS);
+
+    if (r->method_number == M_INVALID) {
+	ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+		    "Invalid method in request %s",
+		    ap_escape_logitem(r->pool, r->the_request));
+	return NOT_IMPLEMENTED;
+    }
+    if (r->method_number == M_OPTIONS) {
+        return ap_send_http_options(r);
+    }
+    if (r->method_number == M_PUT) {
+        return METHOD_NOT_ALLOWED;
+    }
+
+    if (r->finfo.st_mode == 0 || (r->path_info && *r->path_info)) {
+	ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
+		      "File does not exist: %s",r->path_info ?
+		      ap_pstrcat(r->pool, r->filename, r->path_info, NULL)
+		      : r->filename);
+	return HTTP_NOT_FOUND;
+    }
+    if (r->method_number != M_GET) {
+        return METHOD_NOT_ALLOWED;
+    }
+	
+#if defined(OS2) || defined(WIN32) || defined(NETWARE) || defined(CYGWIN)
+    /* Need binary mode for OS/2 */
+    f = ap_pfopen(r->pool, r->filename, "rb");
+#else
+    f = ap_pfopen(r->pool, r->filename, "r");
+#endif
+
+    if (f == NULL) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
+		     "file permissions deny server access: %s", r->filename);
+        return FORBIDDEN;
+    }
+	
+    ap_update_mtime(r, r->finfo.st_mtime);
+    ap_set_last_modified(r);
+    ap_set_etag(r);
+    ap_table_setn(r->headers_out, "Accept-Ranges", "bytes");
+    if (((errstatus = ap_meets_conditions(r)) != OK)
+	|| (errstatus = ap_set_content_length(r, r->finfo.st_size))) {
+        return errstatus;
+    }
+
+#ifdef USE_MMAP_FILES
+    ap_block_alarms();
+    if ((r->finfo.st_size >= MMAP_THRESHOLD)
+	&& (r->finfo.st_size < MMAP_LIMIT)
+	&& (!r->header_only || (d->content_md5 & 1))) {
+	/* we need to protect ourselves in case we die while we've got the
+ 	 * file mmapped */
+	mm = mmap(NULL, r->finfo.st_size, PROT_READ, MAP_PRIVATE,
+		  fileno(f), 0);
+	if (mm == (caddr_t)-1) {
+	    ap_log_rerror(APLOG_MARK, APLOG_CRIT, r,
+			 "default_handler: mmap failed: %s", r->filename);
+	}
+    }
+    else {
+	mm = (caddr_t)-1;
+    }
+
+    if (mm == (caddr_t)-1) {
+	ap_unblock_alarms();
+#endif
+
+#ifdef CHARSET_EBCDIC
+	if (d->content_md5 & 1) {
+	    ap_table_setn(r->headers_out, "Content-MD5",
+			  ap_md5digest(r->pool, f, r->ebcdic.conv_out));
+	}
+#else
+	if (d->content_md5 & 1) {
+	    ap_table_setn(r->headers_out, "Content-MD5",
+			  ap_md5digest(r->pool, f));
+	}
+#endif /* CHARSET_EBCDIC */
+
+	rangestatus = ap_set_byterange(r);
+
+	ap_send_http_header(r);
+	
+	if (!r->header_only) {
+	    if (!rangestatus) {
+		ap_send_fd(f, r);
+	    }
+	    else {
+		long offset, length;
+		while (ap_each_byterange(r, &offset, &length)) {
+		    /*
+		     * Non zero returns are more portable than checking
+		     * for a return of -1.
+		     */
+		    if (fseek(f, offset, SEEK_SET)) {
+			ap_log_error(APLOG_MARK, APLOG_ERR, r->server,
+			      "Failed to fseek for byterange (%ld, %ld): %s",
+			      offset, length, r->filename);
+		    }
+		    else {
+			ap_send_fd_length(f, r, length);
+		    }
+		}
+	    }
+	}
+
+#ifdef USE_MMAP_FILES
+    }
+    else {
+	struct mmap_rec *mmd;
+
+	mmd = ap_palloc(r->pool, sizeof(*mmd));
+	mmd->mm = mm;
+	mmd->length = r->finfo.st_size;
+	ap_register_cleanup(r->pool, (void *)mmd, mmap_cleanup, mmap_cleanup);
+	ap_unblock_alarms();
+
+	if (d->content_md5 & 1) {
+	    AP_MD5_CTX context;
+	    
+	    ap_MD5Init(&context);
+	    ap_MD5Update(&context, (void *)mm, (unsigned int)r->finfo.st_size);
+	    ap_table_setn(r->headers_out, "Content-MD5",
+			  ap_md5contextTo64(r->pool, &context));
+	}
+
+	rangestatus = ap_set_byterange(r);
+	ap_send_http_header(r);
+	
+	if (!r->header_only) {
+	    if (!rangestatus) {
+		ap_send_mmap(mm, r, 0, r->finfo.st_size);
+	    }
+	    else {
+		long offset, length;
+		while (ap_each_byterange(r, &offset, &length)) {
+		    ap_send_mmap(mm, r, offset, length);
+		}
+	    }
+	}
+    }
+#endif
+
+    ap_pfclose(r->pool, f);
+    return OK;
+}
+
+static const handler_rec core_handlers[] = {
+{ "*/*", default_handler },
+{ "default-handler", default_handler },
+{ NULL, NULL }
+};
+
+API_VAR_EXPORT module core_module = {
+    STANDARD_MODULE_STUFF,
+    NULL,			/* initializer */
+    create_core_dir_config,	/* create per-directory config structure */
+    merge_core_dir_configs,	/* merge per-directory config structures */
+    create_core_server_config,	/* create per-server config structure */
+    merge_core_server_configs,	/* merge per-server config structures */
+    core_cmds,			/* command table */
+    core_handlers,		/* handlers */
+    core_translate,		/* translate_handler */
+    NULL,			/* check_user_id */
+    NULL,			/* check auth */
+    do_nothing,			/* check access */
+    do_nothing,			/* type_checker */
+    NULL,			/* pre-run fixups */
+    NULL,			/* logger */
+    NULL,			/* header parser */
+    NULL,			/* child_init */
+    NULL,			/* child_exit */
+    NULL			/* post_read_request */
+};
diff -udrN apache_1.3.33/src/main/http_protocol.c apache_1.3.33-mod/src/main/http_protocol.c
--- apache_1.3.33/src/main/http_protocol.c	Wed Sep 15 16:45:18 2004
+++ apache_1.3.33-mod/src/main/http_protocol.c	Fri Apr  1 10:06:38 2005
@@ -20,6 +20,7 @@
  * and the Apache Group.
  */
 
+#include <stdint.h>
 #define CORE_PRIVATE
 #include "httpd.h"
 #include "http_config.h"
@@ -120,7 +121,7 @@
 };
 
 static enum byterange_token
-    parse_byterange(request_rec *r, long *start, long *end)
+    parse_byterange(request_rec *r, int64_t *start, int64_t *end)
 {
     /* parsing first, semantics later */
 
@@ -137,7 +138,7 @@
     }
 
     if (ap_isdigit(*r->range))
-	*start = ap_strtol(r->range, (char **)&r->range, 10);
+	*start = ap_strtoll(r->range, (char **)&r->range, 10);
     else
 	*start = -1;
 
@@ -152,7 +153,7 @@
         ++r->range;
 
     if (ap_isdigit(*r->range))
-	*end = ap_strtol(r->range, (char **)&r->range, 10);
+	*end = ap_strtoll(r->range, (char **)&r->range, 10);
     else
 	*end = -1;
 
@@ -242,8 +243,8 @@
 API_EXPORT(int) ap_set_byterange(request_rec *r)
 {
     const char *range, *if_range, *match;
-    long length, start, end, one_start = 0, one_end = 0;
-    int ranges, empty;
+    int64_t length, start, end, one_start = 0, one_end = 0;
+    int64_t ranges, empty;
     
     if (!r->clength || r->assbackwards)
         return 0;
@@ -326,7 +327,7 @@
 	}
 	else {
 	    ap_table_setn(r->headers_out, "Content-Range",
-		ap_psprintf(r->pool, "bytes */%ld", r->clength));
+		ap_psprintf(r->pool, "bytes */%qd", r->clength));
 	    ap_set_content_length(r, 0);			  
 	    r->boundary = NULL;
 	    r->range = range;
@@ -338,10 +339,10 @@
     else if (ranges == 1) {
 	/* simple handling of a single range -- no boundaries */
         ap_table_setn(r->headers_out, "Content-Range",
-	    ap_psprintf(r->pool, "bytes %ld-%ld/%ld",
+	    ap_psprintf(r->pool, "bytes %qd-%qd/%qd",
 		one_start, one_end, r->clength));
 	ap_table_setn(r->headers_out, "Content-Length",
-	    ap_psprintf(r->pool, "%ld", one_end - one_start + 1));
+	    ap_psprintf(r->pool, "%qd", one_end - one_start + 1));
 	r->boundary = NULL;
 	r->byterange = 1;
 	r->range = range;
@@ -352,7 +353,7 @@
 	/* multiple ranges */
 	length += byterange_boundary(r, -1, -1, 0);
 	ap_table_setn(r->headers_out, "Content-Length",
-	    ap_psprintf(r->pool, "%ld", length));
+	    ap_psprintf(r->pool, "%qd", length));
 	r->byterange = 2;
 	r->range = range;
 	r->status = PARTIAL_CONTENT;
@@ -360,9 +361,9 @@
     }
 }
 
-API_EXPORT(int) ap_each_byterange(request_rec *r, long *offset, long *length)
+API_EXPORT(int64_t) ap_each_byterange(request_rec *r, int64_t *offset, int64_t *length)
 {
-    long start, end;
+    int64_t start, end;
 
     do {
 	if (parse_byterange(r, &start, &end) == BYTERANGE_OK) {
@@ -378,10 +379,10 @@
     return 0;
 }
 
-API_EXPORT(int) ap_set_content_length(request_rec *r, long clength)
+API_EXPORT(int64_t) ap_set_content_length(request_rec *r, int64_t clength)
 {
     r->clength = clength;
-    ap_table_setn(r->headers_out, "Content-Length", ap_psprintf(r->pool, "%ld", clength));
+    ap_table_setn(r->headers_out, "Content-Length", ap_psprintf(r->pool, "%qd", clength));
     return 0;
 }
 
@@ -2017,7 +2018,7 @@
         else {
             char *endstr;
             errno = 0;
-            r->remaining = ap_strtol(lenp, &endstr, 10);
+            r->remaining = ap_strtoll(lenp, &endstr, 10);
             if (errno || (endstr && *endstr) || (r->remaining < 0)) {
                 conversion_error = 1;
             }
@@ -2342,15 +2343,15 @@
 /*
  * Send the body of a response to the client.
  */
-API_EXPORT(long) ap_send_fd(FILE *f, request_rec *r)
+API_EXPORT(int64_t) ap_send_fd(FILE *f, request_rec *r)
 {
     return ap_send_fd_length(f, r, -1);
 }
 
-API_EXPORT(long) ap_send_fd_length(FILE *f, request_rec *r, long length)
+API_EXPORT(int64_t) ap_send_fd_length(FILE *f, request_rec *r, int64_t length)
 {
     char buf[IOBUFSIZE];
-    long total_bytes_sent = 0;
+    int64_t total_bytes_sent = 0;
     register int n, w, o, len;
 
     if (length == 0)
@@ -2401,15 +2402,15 @@
 /*
  * Send the body of a response to the client.
  */
-API_EXPORT(long) ap_send_fb(BUFF *fb, request_rec *r)
+API_EXPORT(int64_t) ap_send_fb(BUFF *fb, request_rec *r)
 {
     return ap_send_fb_length(fb, r, -1);
 }
 
-API_EXPORT(long) ap_send_fb_length(BUFF *fb, request_rec *r, long length)
+API_EXPORT(int64_t) ap_send_fb_length(BUFF *fb, request_rec *r, int64_t length)
 {
     char buf[IOBUFSIZE];
-    long total_bytes_sent = 0;
+    int64_t total_bytes_sent = 0;
     register int n, w, o, len, fd;
     fd_set fds;
 #ifdef TPF_HAVE_NONSOCKET_SELECT
@@ -2538,10 +2539,9 @@
 #endif
 
 /* send data from an in-memory buffer */
-API_EXPORT(size_t) ap_send_mmap(void *mm, request_rec *r, size_t offset,
-                             size_t length)
+API_EXPORT(int64_t) ap_send_mmap(void *mm, request_rec *r, off_t offset, int64_t length)
 {
-    size_t total_bytes_sent = 0;
+    int64_t total_bytes_sent = 0;
     int n, w;
 
     if (length == 0)
diff -udrN apache_1.3.33/src/main/http_protocol.c.orig apache_1.3.33-mod/src/main/http_protocol.c.orig
--- apache_1.3.33/src/main/http_protocol.c.orig	Wed Dec 31 16:00:00 1969
+++ apache_1.3.33-mod/src/main/http_protocol.c.orig	Wed Sep 15 16:45:18 2004
@@ -0,0 +1,3140 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * http_protocol.c --- routines which directly communicate with the client.
+ *
+ * Code originally by Rob McCool; much redone by Robert S. Thau
+ * and the Apache Group.
+ */
+
+#define CORE_PRIVATE
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_main.h"
+#include "http_request.h"
+#include "http_vhost.h"
+#include "http_log.h"           /* For errors detected in basic auth common
+                                 * support code... */
+#include "util_date.h"          /* For parseHTTPdate and BAD_DATE */
+#include <stdarg.h>
+#include "http_conf_globals.h"
+#include "util_md5.h"           /* For digestAuth */
+
+#define SET_BYTES_SENT(r) \
+  do { if (r->sent_bodyct) \
+          ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
+  } while (0)
+
+#ifdef CHARSET_EBCDIC
+/* Save & Restore the current conversion settings
+ * "input"  means: ASCII -> EBCDIC (when reading MIME Headers and PUT/POST data)
+ * "output" means: EBCDIC -> ASCII (when sending MIME Headers and Chunks)
+ */
+
+#define PUSH_EBCDIC_INPUTCONVERSION_STATE(_buff, _onoff) \
+        int _convert_in = ap_bgetflag(_buff, B_ASCII2EBCDIC); \
+        ap_bsetflag(_buff, B_ASCII2EBCDIC, _onoff);
+
+#define POP_EBCDIC_INPUTCONVERSION_STATE(_buff) \
+        ap_bsetflag(_buff, B_ASCII2EBCDIC, _convert_in);
+
+#define PUSH_EBCDIC_INPUTCONVERSION_STATE_r(_req, _onoff) \
+        ap_bsetflag(_req->connection->client, B_ASCII2EBCDIC, _onoff);
+
+#define POP_EBCDIC_INPUTCONVERSION_STATE_r(_req) \
+        ap_bsetflag(_req->connection->client, B_ASCII2EBCDIC, _req->ebcdic.conv_in);
+
+#define PUSH_EBCDIC_OUTPUTCONVERSION_STATE_r(_req, _onoff) \
+        ap_bsetflag(_req->connection->client, B_EBCDIC2ASCII, _onoff);
+
+#define POP_EBCDIC_OUTPUTCONVERSION_STATE_r(_req) \
+        ap_bsetflag(_req->connection->client, B_EBCDIC2ASCII, _req->ebcdic.conv_out);
+
+#endif /*CHARSET_EBCDIC*/
+
+/*
+ * Builds the content-type that should be sent to the client from the
+ * content-type specified.  The following rules are followed:
+ *    - if type is NULL, type is set to ap_default_type(r)
+ *    - if charset adding is disabled, stop processing and return type.
+ *    - then, if there are no parameters on type, add the default charset
+ *    - return type
+ */
+static const char *make_content_type(request_rec *r, const char *type) {
+    char *needcset[] = {
+	"text/plain",
+	"text/html",
+	NULL };
+    char **pcset;
+    core_dir_config *conf;
+
+    conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+                                                   &core_module);
+    if (!type) {
+        type = ap_default_type(r);
+    }
+    if (conf->add_default_charset != ADD_DEFAULT_CHARSET_ON) {
+        return type;
+    }
+
+    if (ap_strcasestr(type, "charset=") != NULL) {
+	/* already has parameter, do nothing */
+	/* XXX we don't check the validity */
+	;
+    }
+    else {
+    	/* see if it makes sense to add the charset. At present,
+	 * we only add it if the Content-type is one of needcset[]
+	 */
+	for (pcset = needcset; *pcset ; pcset++) {
+	    if (ap_strcasestr(type, *pcset) != NULL) {
+		type = ap_pstrcat(r->pool, type, "; charset=", 
+                                  conf->add_default_charset_name, NULL);
+		break;
+	    }
+        }
+    }
+    return type;
+}
+
+enum byterange_token {
+    BYTERANGE_OK,
+    BYTERANGE_EMPTY,
+    BYTERANGE_BADSYNTAX,
+    BYTERANGE_UNSATISFIABLE
+};
+
+static enum byterange_token
+    parse_byterange(request_rec *r, long *start, long *end)
+{
+    /* parsing first, semantics later */
+
+    while (ap_isspace(*r->range))
+        ++r->range;
+
+    /* check for an empty range, which is OK */
+    if (*r->range == '\0') {
+	return BYTERANGE_EMPTY;
+    }
+    else if (*r->range == ',') {
+	++r->range;
+	return BYTERANGE_EMPTY;
+    }
+
+    if (ap_isdigit(*r->range))
+	*start = ap_strtol(r->range, (char **)&r->range, 10);
+    else
+	*start = -1;
+
+    while (ap_isspace(*r->range))
+        ++r->range;
+
+    if (*r->range != '-')
+	return BYTERANGE_BADSYNTAX;
+    ++r->range;
+
+    while (ap_isspace(*r->range))
+        ++r->range;
+
+    if (ap_isdigit(*r->range))
+	*end = ap_strtol(r->range, (char **)&r->range, 10);
+    else
+	*end = -1;
+
+    while (ap_isspace(*r->range))
+        ++r->range;
+
+    /* check the end of the range */
+    if (*r->range == ',') {
+	++r->range;
+    }
+    else if (*r->range != '\0') {
+	return BYTERANGE_BADSYNTAX;
+    }
+
+    /* parsing done; now check the numbers */
+
+    if (*start < 0) { /* suffix-byte-range-spec */
+	if (*end < 0) /* no numbers */
+	    return BYTERANGE_BADSYNTAX;
+	*start = r->clength - *end;
+	if (*start < 0)
+	    *start = 0;
+	*end = r->clength - 1;
+    }
+    else {
+	if (*end >= 0 && *start > *end) /* out-of-order range */
+	    return BYTERANGE_BADSYNTAX;
+	if (*end < 0 || *end >= r->clength)
+	    *end = r->clength - 1;
+    }
+    /* RFC 2616 is somewhat unclear about what we should do if the end
+     * is missing and the start is after the clength. The robustness
+     * principle says we should accept it as an unsatisfiable range.
+     * We accept suffix-byte-range-specs like -0 for the same reason.
+     */
+    if (*start >= r->clength)
+	return BYTERANGE_UNSATISFIABLE;
+
+    return BYTERANGE_OK;
+}
+
+/* If this function is called with output=1, it will spit out the
+ * correct headers for a byterange chunk. If output=0 it will not
+ * output anything but just return the number of bytes it would have
+ * output. If start or end are less than 0 then it will do a byterange
+ * chunk trailer instead of a header.
+ */
+static int byterange_boundary(request_rec *r, long start, long end, int output)
+{
+    int length = 0;
+
+#ifdef CHARSET_EBCDIC
+    /* determine current setting of conversion flag,
+     * set to ON (protocol strings MUST be converted)
+     * and reset to original setting before returning
+     */
+    PUSH_EBCDIC_OUTPUTCONVERSION_STATE_r(r, 1);
+#endif /*CHARSET_EBCDIC*/
+
+    if (start < 0 || end < 0) {
+	if (output)
+	    ap_rvputs(r, CRLF "--", r->boundary, "--" CRLF, NULL);
+	else
+	    length = 4 + strlen(r->boundary) + 4;
+    }
+    else {
+	const char *ct = make_content_type(r, r->content_type);
+	char ts[MAX_STRING_LEN];
+
+	ap_snprintf(ts, sizeof(ts), "%ld-%ld/%ld", start, end, r->clength);
+	if (output)
+	    ap_rvputs(r, CRLF "--", r->boundary, CRLF "Content-type: ",
+		      ct, CRLF "Content-range: bytes ", ts, CRLF CRLF,
+		      NULL);
+	else
+	    length = 4 + strlen(r->boundary) + 16
+		+ strlen(ct) + 23 + strlen(ts) + 4;
+    }
+
+#ifdef CHARSET_EBCDIC
+    POP_EBCDIC_OUTPUTCONVERSION_STATE_r(r);
+#endif /*CHARSET_EBCDIC*/
+
+    return length;
+}
+
+API_EXPORT(int) ap_set_byterange(request_rec *r)
+{
+    const char *range, *if_range, *match;
+    long length, start, end, one_start = 0, one_end = 0;
+    int ranges, empty;
+    
+    if (!r->clength || r->assbackwards)
+        return 0;
+
+    /* Check for Range request-header (HTTP/1.1) or Request-Range for
+     * backwards-compatibility with second-draft Luotonen/Franks
+     * byte-ranges (e.g. Netscape Navigator 2-3).
+     *
+     * We support this form, with Request-Range, and (farther down) we
+     * send multipart/x-byteranges instead of multipart/byteranges for
+     * Request-Range based requests to work around a bug in Netscape
+     * Navigator 2-3 and MSIE 3.
+     */
+
+    if (!(range = ap_table_get(r->headers_in, "Range")))
+        range = ap_table_get(r->headers_in, "Request-Range");
+
+    if (!range || strncasecmp(range, "bytes=", 6) || (r->status != HTTP_OK)) {
+        return 0;
+    }
+    range += 6;
+
+    /* Check the If-Range header for Etag or Date.
+     * Note that this check will return false (as required) if either
+     * of the two etags are weak.
+     */
+    if ((if_range = ap_table_get(r->headers_in, "If-Range"))) {
+        if (if_range[0] == '"') {
+            if (!(match = ap_table_get(r->headers_out, "Etag")) ||
+                (strcmp(if_range, match) != 0))
+                return 0;
+        }
+        else if (!(match = ap_table_get(r->headers_out, "Last-Modified")) ||
+                 (strcmp(if_range, match) != 0))
+            return 0;
+    }
+
+    /*
+     * Parse the byteranges, counting how many of them there are and
+     * the total number of bytes we will send to the client. This is a
+     * dummy run for the while(ap_each_byterange()) loop that the
+     * caller will perform if we return 1.
+     */
+    r->range = range;
+    r->boundary = ap_psprintf(r->pool, "%lx%lx",
+			      r->request_time, (long) getpid());
+    length = 0;
+    ranges = 0;
+    empty = 1;
+    do {
+	switch (parse_byterange(r, &start, &end)) {
+	case BYTERANGE_UNSATISFIABLE:
+	    empty = 0;
+	    break;
+	default:
+	    /* be more defensive here? */
+	case BYTERANGE_BADSYNTAX:
+	    r->boundary = NULL;
+	    r->range = NULL;
+	    return 0;
+	case BYTERANGE_EMPTY:
+	    break;
+	case BYTERANGE_OK:
+	    ++ranges;
+	    length += byterange_boundary(r, start, end, 0)
+		+ end - start + 1;
+	    /* save in case of unsatisfiable ranges */
+	    one_start = start;
+	    one_end = end;
+	    break;
+	}
+    } while (*r->range != '\0');
+
+    if (ranges == 0) {
+	/* no ranges or only unsatisfiable ranges */
+	if (empty || if_range) {
+	    r->boundary = NULL;
+	    r->range = NULL;
+	    return 0;
+	}
+	else {
+	    ap_table_setn(r->headers_out, "Content-Range",
+		ap_psprintf(r->pool, "bytes */%ld", r->clength));
+	    ap_set_content_length(r, 0);			  
+	    r->boundary = NULL;
+	    r->range = range;
+	    r->header_only = 1;
+	    r->status = HTTP_RANGE_NOT_SATISFIABLE;
+	    return 1;
+	}
+    }
+    else if (ranges == 1) {
+	/* simple handling of a single range -- no boundaries */
+        ap_table_setn(r->headers_out, "Content-Range",
+	    ap_psprintf(r->pool, "bytes %ld-%ld/%ld",
+		one_start, one_end, r->clength));
+	ap_table_setn(r->headers_out, "Content-Length",
+	    ap_psprintf(r->pool, "%ld", one_end - one_start + 1));
+	r->boundary = NULL;
+	r->byterange = 1;
+	r->range = range;
+	r->status = PARTIAL_CONTENT;
+	return 1;
+    }
+    else {
+	/* multiple ranges */
+	length += byterange_boundary(r, -1, -1, 0);
+	ap_table_setn(r->headers_out, "Content-Length",
+	    ap_psprintf(r->pool, "%ld", length));
+	r->byterange = 2;
+	r->range = range;
+	r->status = PARTIAL_CONTENT;
+	return 1;
+    }
+}
+
+API_EXPORT(int) ap_each_byterange(request_rec *r, long *offset, long *length)
+{
+    long start, end;
+
+    do {
+	if (parse_byterange(r, &start, &end) == BYTERANGE_OK) {
+	    if (r->byterange > 1)
+		byterange_boundary(r, start, end, 1);
+	    *offset = start;
+	    *length = end - start + 1;
+	    return 1;
+	}
+    } while (*r->range != '\0');
+    if (r->byterange > 1)
+	byterange_boundary(r, -1, -1, 1);
+    return 0;
+}
+
+API_EXPORT(int) ap_set_content_length(request_rec *r, long clength)
+{
+    r->clength = clength;
+    ap_table_setn(r->headers_out, "Content-Length", ap_psprintf(r->pool, "%ld", clength));
+    return 0;
+}
+
+API_EXPORT(int) ap_set_keepalive(request_rec *r)
+{
+    int ka_sent = 0;
+    int wimpy = ap_find_token(r->pool,
+                           ap_table_get(r->headers_out, "Connection"), "close");
+    const char *conn = ap_table_get(r->headers_in, "Connection");
+
+    /* The following convoluted conditional determines whether or not
+     * the current connection should remain persistent after this response
+     * (a.k.a. HTTP Keep-Alive) and whether or not the output message
+     * body should use the HTTP/1.1 chunked transfer-coding.  In English,
+     *
+     *   IF  we have not marked this connection as errored;
+     *   and the response body has a defined length due to the status code
+     *       being 304 or 204, the request method being HEAD, already
+     *       having defined Content-Length or Transfer-Encoding: chunked, or
+     *       the request version being HTTP/1.1 and thus capable of being set
+     *       as chunked [we know the (r->chunked = 1) side-effect is ugly];
+     *   and the server configuration enables keep-alive;
+     *   and the server configuration has a reasonable inter-request timeout;
+     *   and there is no maximum # requests or the max hasn't been reached;
+     *   and the response status does not require a close;
+     *   and the response generator has not already indicated close;
+     *   and the client did not request non-persistence (Connection: close);
+     *   and    we haven't been configured to ignore the buggy twit
+     *       or they're a buggy twit coming through a HTTP/1.1 proxy
+     *   and    the client is requesting an HTTP/1.0-style keep-alive
+     *       or the client claims to be HTTP/1.1 compliant (perhaps a proxy);
+     *   THEN we can be persistent, which requires more headers be output.
+     *
+     * Note that the condition evaluation order is extremely important.
+     */
+    if ((r->connection->keepalive != -1) &&
+        ((r->status == HTTP_NOT_MODIFIED) ||
+         (r->status == HTTP_NO_CONTENT) ||
+         r->header_only ||
+         ap_table_get(r->headers_out, "Content-Length") ||
+         ap_find_last_token(r->pool,
+                         ap_table_get(r->headers_out, "Transfer-Encoding"),
+                         "chunked") ||
+         ((r->proto_num >= HTTP_VERSION(1,1)) &&
+	  (r->chunked = 1))) && /* THIS CODE IS CORRECT, see comment above. */
+        r->server->keep_alive &&
+        (r->server->keep_alive_timeout > 0) &&
+        ((r->server->keep_alive_max == 0) ||
+         (r->server->keep_alive_max > r->connection->keepalives)) &&
+        !ap_status_drops_connection(r->status) &&
+        !wimpy &&
+        !ap_find_token(r->pool, conn, "close") &&
+        (!ap_table_get(r->subprocess_env, "nokeepalive") ||
+         ap_table_get(r->headers_in, "Via")) &&
+        ((ka_sent = ap_find_token(r->pool, conn, "keep-alive")) ||
+         (r->proto_num >= HTTP_VERSION(1,1)))
+       ) {
+        int left = r->server->keep_alive_max - r->connection->keepalives;
+
+	/*
+	 * ap_set_keepalive could be called multiple times (eg: in
+	 * ap_die() followed by ap_send_http_header()) during this
+	 * one single request. To ensure that we don't incorrectly
+	 * increment the keepalives counter for each call, we
+	 * assume that only here do we set keepalive. So if keepalive
+	 * is already set to 1, we must have already been here and
+	 * we should not increment the keepalives counter since we
+	 * already done so for this request.
+	 */
+        if (r->connection->keepalive != 1) {
+            r->connection->keepalive = 1;
+            r->connection->keepalives++;
+	}
+
+        /* If they sent a Keep-Alive token, send one back */
+        if (ka_sent) {
+            if (r->server->keep_alive_max)
+		ap_table_setn(r->headers_out, "Keep-Alive",
+		    ap_psprintf(r->pool, "timeout=%d, max=%d",
+                            r->server->keep_alive_timeout, left));
+            else
+		ap_table_setn(r->headers_out, "Keep-Alive",
+		    ap_psprintf(r->pool, "timeout=%d",
+                            r->server->keep_alive_timeout));
+            ap_table_mergen(r->headers_out, "Connection", "Keep-Alive");
+        }
+
+        return 1;
+    }
+
+    /* Otherwise, we need to indicate that we will be closing this
+     * connection immediately after the current response.
+     *
+     * We only really need to send "close" to HTTP/1.1 clients, but we
+     * always send it anyway, because a broken proxy may identify itself
+     * as HTTP/1.0, but pass our request along with our HTTP/1.1 tag
+     * to a HTTP/1.1 client. Better safe than sorry.
+     */
+    if (!wimpy)
+	ap_table_mergen(r->headers_out, "Connection", "close");
+
+    r->connection->keepalive = 0;
+
+    return 0;
+}
+
+/*
+ * Return the latest rational time from a request/mtime (modification time)
+ * pair.  We return the mtime unless it's in the future, in which case we
+ * return the current time.  We use the request time as a reference in order
+ * to limit the number of calls to time().  We don't check for futurosity
+ * unless the mtime is at least as new as the reference.
+ */
+API_EXPORT(time_t) ap_rationalize_mtime(request_rec *r, time_t mtime)
+{
+    time_t now;
+
+    /* For all static responses, it's almost certain that the file was
+     * last modified before the beginning of the request.  So there's
+     * no reason to call time(NULL) again.  But if the response has been
+     * created on demand, then it might be newer than the time the request
+     * started.  In this event we really have to call time(NULL) again
+     * so that we can give the clients the most accurate Last-Modified.  If we
+     * were given a time in the future, we return the current time - the
+     * Last-Modified can't be in the future.
+     */
+    now = (mtime < r->request_time) ? r->request_time : time(NULL);
+    return (mtime > now) ? now : mtime;
+}
+
+API_EXPORT(int) ap_meets_conditions(request_rec *r)
+{
+    const char *etag = ap_table_get(r->headers_out, "ETag");
+    const char *if_match, *if_modified_since, *if_unmodified, *if_nonematch;
+    time_t mtime;
+
+    /* Check for conditional requests --- note that we only want to do
+     * this if we are successful so far and we are not processing a
+     * subrequest or an ErrorDocument.
+     *
+     * The order of the checks is important, since ETag checks are supposed
+     * to be more accurate than checks relative to the modification time.
+     * However, not all documents are guaranteed to *have* ETags, and some
+     * might have Last-Modified values w/o ETags, so this gets a little
+     * complicated.
+     */
+
+    if (!ap_is_HTTP_SUCCESS(r->status) || r->no_local_copy) {
+        return OK;
+    }
+
+    mtime = (r->mtime != 0) ? r->mtime : time(NULL);
+
+    /* If an If-Match request-header field was given
+     * AND the field value is not "*" (meaning match anything)
+     * AND if our strong ETag does not match any entity tag in that field,
+     *     respond with a status of 412 (Precondition Failed).
+     */
+    if ((if_match = ap_table_get(r->headers_in, "If-Match")) != NULL) {
+        if (if_match[0] != '*' &&
+            (etag == NULL || etag[0] == 'W' ||
+             !ap_find_list_item(r->pool, if_match, etag))) {
+            return HTTP_PRECONDITION_FAILED;
+        }
+    }
+    else {
+        /* Else if a valid If-Unmodified-Since request-header field was given
+         * AND the requested resource has been modified since the time
+         * specified in this field, then the server MUST
+         *     respond with a status of 412 (Precondition Failed).
+         */
+        if_unmodified = ap_table_get(r->headers_in, "If-Unmodified-Since");
+        if (if_unmodified != NULL) {
+            time_t ius = ap_parseHTTPdate(if_unmodified);
+
+            if ((ius != BAD_DATE) && (mtime > ius)) {
+                return HTTP_PRECONDITION_FAILED;
+            }
+        }
+    }
+
+    /* If an If-None-Match request-header field was given
+     * AND the field value is "*" (meaning match anything)
+     *     OR our ETag matches any of the entity tags in that field, fail.
+     *
+     * If the request method was GET or HEAD, failure means the server
+     *    SHOULD respond with a 304 (Not Modified) response.
+     * For all other request methods, failure means the server MUST
+     *    respond with a status of 412 (Precondition Failed).
+     *
+     * GET or HEAD allow weak etag comparison, all other methods require
+     * strong comparison.  We can only use weak if it's not a range request.
+     */
+    if_nonematch = ap_table_get(r->headers_in, "If-None-Match");
+    if (if_nonematch != NULL) {
+        if (r->method_number == M_GET) {
+            if (if_nonematch[0] == '*')
+                return HTTP_NOT_MODIFIED;
+            if (etag != NULL) {
+                if (ap_table_get(r->headers_in, "Range")) {
+                    if (etag[0] != 'W' &&
+                        ap_find_list_item(r->pool, if_nonematch, etag)) {
+                        return HTTP_NOT_MODIFIED;
+                    }
+                }
+                else if (strstr(if_nonematch, etag)) {
+                    return HTTP_NOT_MODIFIED;
+                }
+            }
+        }
+        else if (if_nonematch[0] == '*' ||
+                 (etag != NULL &&
+                  ap_find_list_item(r->pool, if_nonematch, etag))) {
+            return HTTP_PRECONDITION_FAILED;
+        }
+    }
+    /* Else if a valid If-Modified-Since request-header field was given
+     * AND it is a GET or HEAD request
+     * AND the requested resource has not been modified since the time
+     * specified in this field, then the server MUST
+     *    respond with a status of 304 (Not Modified).
+     * A date later than the server's current request time is invalid.
+     */
+    else if ((r->method_number == M_GET)
+             && ((if_modified_since =
+                  ap_table_get(r->headers_in, "If-Modified-Since")) != NULL)) {
+        time_t ims = ap_parseHTTPdate(if_modified_since);
+
+        if ((ims >= mtime) && (ims <= r->request_time)) {
+            return HTTP_NOT_MODIFIED;
+        }
+    }
+    return OK;
+}
+
+/*
+ * Construct an entity tag (ETag) from resource information.  If it's a real
+ * file, build in some of the file characteristics.  If the modification time
+ * is newer than (request-time minus 1 second), mark the ETag as weak - it
+ * could be modified again in as short an interval.  We rationalize the
+ * modification time we're given to keep it from being in the future.
+ */
+API_EXPORT(char *) ap_make_etag(request_rec *r, int force_weak)
+{
+    char *etag;
+    char *weak;
+    core_dir_config *cfg;
+    etag_components_t etag_bits;
+
+    cfg = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+                                                  &core_module);
+    etag_bits = (cfg->etag_bits & (~ cfg->etag_remove)) | cfg->etag_add;
+    if (etag_bits == ETAG_UNSET) {
+        etag_bits = ETAG_BACKWARD;
+    }
+    /*
+     * Make an ETag header out of various pieces of information. We use
+     * the last-modified date and, if we have a real file, the
+     * length and inode number - note that this doesn't have to match
+     * the content-length (i.e. includes), it just has to be unique
+     * for the file.
+     *
+     * If the request was made within a second of the last-modified date,
+     * we send a weak tag instead of a strong one, since it could
+     * be modified again later in the second, and the validation
+     * would be incorrect.
+     */
+    
+    weak = ((r->request_time - r->mtime > 1) && !force_weak) ? "" : "W/";
+
+    if (r->finfo.st_mode != 0) {
+        char **ent;
+        array_header *components;
+        int i;
+
+        /*
+         * If it's a file (or we wouldn't be here) and no ETags
+         * should be set for files, return an empty string and
+         * note it for ap_send_header_field() to ignore.
+         */
+        if (etag_bits & ETAG_NONE) {
+            ap_table_setn(r->notes, "no-etag", "omit");
+            return "";
+        }
+
+        components = ap_make_array(r->pool, 4, sizeof(char *));
+        if (etag_bits & ETAG_INODE) {
+            ent = (char **) ap_push_array(components);
+            *ent = ap_psprintf(r->pool, "%lx",
+                               (unsigned long) r->finfo.st_ino);
+        }
+        if (etag_bits & ETAG_SIZE) {
+            ent = (char **) ap_push_array(components);
+            *ent = ap_psprintf(r->pool, "%lx",
+                               (unsigned long) r->finfo.st_size);
+        }
+        if (etag_bits & ETAG_MTIME) {
+            ent = (char **) ap_push_array(components);
+            *ent = ap_psprintf(r->pool, "%lx", (unsigned long) r->mtime);
+        }
+        ent = (char **) components->elts;
+        etag = ap_pstrcat(r->pool, weak, "\"", NULL);
+        for (i = 0; i < components->nelts; ++i) {
+            etag = ap_psprintf(r->pool, "%s%s%s", etag,
+                               (i == 0 ? "" : "-"),
+                               ent[i]);
+        }
+        etag = ap_pstrcat(r->pool, etag, "\"", NULL);
+    }
+    else {
+        etag = ap_psprintf(r->pool, "%s\"%lx\"", weak,
+                    (unsigned long) r->mtime);
+    }
+
+    return etag;
+}
+
+API_EXPORT(void) ap_set_etag(request_rec *r)
+{
+    char *etag;
+    char *variant_etag, *vlv;
+    int vlv_weak;
+
+    if (!r->vlist_validator) {
+        etag = ap_make_etag(r, 0);
+
+        /* If we get a blank etag back, don't set the header. */
+        if (!etag[0]) {
+            return;
+        }
+    }
+    else {
+        /* If we have a variant list validator (vlv) due to the
+         * response being negotiated, then we create a structured
+         * entity tag which merges the variant etag with the variant
+         * list validator (vlv).  This merging makes revalidation
+         * somewhat safer, ensures that caches which can deal with
+         * Vary will (eventually) be updated if the set of variants is
+         * changed, and is also a protocol requirement for transparent
+         * content negotiation.
+         */
+
+        /* if the variant list validator is weak, we make the whole
+         * structured etag weak.  If we would not, then clients could
+         * have problems merging range responses if we have different
+         * variants with the same non-globally-unique strong etag.
+         */
+
+        vlv = r->vlist_validator;
+        vlv_weak = (vlv[0] == 'W');
+               
+        variant_etag = ap_make_etag(r, vlv_weak);
+
+        /* If we get a blank etag back, don't append vlv and stop now. */
+        if (!variant_etag[0]) {
+            return;
+        }
+
+        /* merge variant_etag and vlv into a structured etag */
+        variant_etag[strlen(variant_etag) - 1] = '\0';
+        if (vlv_weak)
+            vlv += 3;
+        else
+            vlv++;
+        etag = ap_pstrcat(r->pool, variant_etag, ";", vlv, NULL);
+    }
+
+    ap_table_setn(r->headers_out, "ETag", etag);
+}
+
+/*
+ * This function sets the Last-Modified output header field to the value
+ * of the mtime field in the request structure - rationalized to keep it from
+ * being in the future.
+ */
+API_EXPORT(void) ap_set_last_modified(request_rec *r)
+{
+    time_t mod_time = ap_rationalize_mtime(r, r->mtime);
+
+    ap_table_setn(r->headers_out, "Last-Modified",
+              ap_gm_timestr_822(r->pool, mod_time));
+}
+
+/* Get the method number associated with the given string, assumed to
+ * contain an HTTP method.  Returns M_INVALID if not recognized.
+ *
+ * This is the first step toward placing method names in a configurable
+ * list.  Hopefully it (and other routines) can eventually be moved to
+ * something like a mod_http_methods.c, complete with config stuff.
+ */
+API_EXPORT(int) ap_method_number_of(const char *method)
+{
+    switch (*method) {
+        case 'H':
+           if (strcmp(method, "HEAD") == 0)
+               return M_GET;   /* see header_only in request_rec */
+           break;
+        case 'G':
+           if (strcmp(method, "GET") == 0)
+               return M_GET;
+           break;
+        case 'P':
+           if (strcmp(method, "POST") == 0)
+               return M_POST;
+           if (strcmp(method, "PUT") == 0)
+               return M_PUT;
+           if (strcmp(method, "PATCH") == 0)
+               return M_PATCH;
+           if (strcmp(method, "PROPFIND") == 0)
+               return M_PROPFIND;
+           if (strcmp(method, "PROPPATCH") == 0)
+               return M_PROPPATCH;
+           break;
+        case 'D':
+           if (strcmp(method, "DELETE") == 0)
+               return M_DELETE;
+           break;
+        case 'C':
+           if (strcmp(method, "CONNECT") == 0)
+               return M_CONNECT;
+           if (strcmp(method, "COPY") == 0)
+               return M_COPY;
+           break;
+        case 'M':
+           if (strcmp(method, "MKCOL") == 0)
+               return M_MKCOL;
+           if (strcmp(method, "MOVE") == 0)
+               return M_MOVE;
+           break;
+        case 'O':
+           if (strcmp(method, "OPTIONS") == 0)
+               return M_OPTIONS;
+           break;
+        case 'T':
+           if (strcmp(method, "TRACE") == 0)
+               return M_TRACE;
+           break;
+        case 'L':
+           if (strcmp(method, "LOCK") == 0)
+               return M_LOCK;
+           break;
+        case 'U':
+           if (strcmp(method, "UNLOCK") == 0)
+               return M_UNLOCK;
+           break;
+    }
+    return M_INVALID;
+}
+
+/* Get a line of protocol input, including any continuation lines
+ * caused by MIME folding (or broken clients) if fold != 0, and place it
+ * in the buffer s, of size n bytes, without the ending newline.
+ *
+ * Returns -1 on error, or the length of s.
+ *
+ * Note: Because bgets uses 1 char for newline and 1 char for NUL,
+ *       the most we can get is (n - 2) actual characters if it
+ *       was ended by a newline, or (n - 1) characters if the line
+ *       length exceeded (n - 1).  So, if the result == (n - 1),
+ *       then the actual input line exceeded the buffer length,
+ *       and it would be a good idea for the caller to puke 400 or 414.
+ */
+API_EXPORT(int) ap_getline(char *s, int n, BUFF *in, int fold)
+{
+    char *pos, next;
+    int retval;
+    int total = 0;
+#ifdef CHARSET_EBCDIC
+    /* When ap_getline() is called, the HTTP protocol is in a state
+     * where we MUST be reading "plain text" protocol stuff,
+     * (Request line, MIME headers, Chunk sizes) regardless of
+     * the MIME type and conversion setting of the document itself.
+     * Save the current setting of the ASCII-EBCDIC conversion flag
+     * for uploads, then temporarily set it to ON
+     * (and restore it before returning).
+     */
+    PUSH_EBCDIC_INPUTCONVERSION_STATE(in, 1);
+#endif /*CHARSET_EBCDIC*/
+
+    pos = s;
+
+    do {
+        retval = ap_bgets(pos, n, in);     /* retval == -1 if error, 0 if EOF */
+
+        if (retval <= 0) {
+            total = ((retval < 0) && (total == 0)) ? -1 : total;
+            break;
+        }
+
+        /* retval is the number of characters read, not including NUL      */
+
+        n -= retval;            /* Keep track of how much of s is full     */
+        pos += (retval - 1);    /* and where s ends                        */
+        total += retval;        /* and how long s has become               */
+
+        if (*pos == '\n') {     /* Did we get a full line of input?        */
+            /*
+             * Trim any extra trailing spaces or tabs except for the first
+             * space or tab at the beginning of a blank string.  This makes
+             * it much easier to check field values for exact matches, and
+             * saves memory as well.  Terminate string at end of line.
+             */
+            while (pos > (s + 1) && (*(pos - 1) == ' ' || *(pos - 1) == '\t')) {
+                --pos;          /* trim extra trailing spaces or tabs      */
+                --total;        /* but not one at the beginning of line    */
+                ++n;
+            }
+            *pos = '\0';
+            --total;
+            ++n;
+        }
+        else
+            break;       /* if not, input line exceeded buffer size */
+
+        /* Continue appending if line folding is desired and
+         * the last line was not empty and we have room in the buffer and
+         * the next line begins with a continuation character.
+         */
+    } while (fold && (retval != 1) && (n > 1)
+                  && (ap_blookc(&next, in) == 1)
+                  && ((next == ' ') || (next == '\t')));
+
+#ifdef CHARSET_EBCDIC
+    /* restore ASCII->EBCDIC conversion state */
+    POP_EBCDIC_INPUTCONVERSION_STATE(in);
+#endif /*CHARSET_EBCDIC*/
+
+    return total;
+}
+
+/* parse_uri: break apart the uri
+ * Side Effects:
+ * - sets r->args to rest after '?' (or NULL if no '?')
+ * - sets r->uri to request uri (without r->args part)
+ * - sets r->hostname (if not set already) from request (scheme://host:port)
+ */
+CORE_EXPORT(void) ap_parse_uri(request_rec *r, const char *uri)
+{
+    int status = HTTP_OK;
+
+    r->unparsed_uri = ap_pstrdup(r->pool, uri);
+
+    if (r->method_number == M_CONNECT) {
+	status = ap_parse_hostinfo_components(r->pool, uri, &r->parsed_uri);
+    } else {
+	/* Simple syntax Errors in URLs are trapped by parse_uri_components(). */
+	status = ap_parse_uri_components(r->pool, uri, &r->parsed_uri);
+    }
+
+    if (ap_is_HTTP_SUCCESS(status)) {
+	/* if it has a scheme we may need to do absoluteURI vhost stuff */
+	if (r->parsed_uri.scheme
+	    && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))) {
+	    r->hostname = r->parsed_uri.hostname;
+	} else if (r->method_number == M_CONNECT) {
+	    r->hostname = r->parsed_uri.hostname;
+	}
+	r->args = r->parsed_uri.query;
+	r->uri = r->parsed_uri.path ? r->parsed_uri.path
+				    : ap_pstrdup(r->pool, "/");
+#if defined(OS2) || defined(WIN32)
+	/* Handle path translations for OS/2 and plug security hole.
+	 * This will prevent "http://www.wherever.com/..\..\/" from
+	 * returning a directory for the root drive.
+	 */
+	{
+	    char *x;
+
+	    for (x = r->uri; (x = strchr(x, '\\')) != NULL; )
+		*x = '/';
+	}
+#endif  /* OS2 || WIN32 */
+    }
+    else {
+	r->args = NULL;
+	r->hostname = NULL;
+	r->status = status;             /* set error status */
+	r->uri = ap_pstrdup(r->pool, uri);
+    }
+}
+
+static int read_request_line(request_rec *r)
+{
+    char l[DEFAULT_LIMIT_REQUEST_LINE + 2]; /* ap_getline's two extra for \n\0 */
+    const char *ll = l;
+    const char *uri;
+    conn_rec *conn = r->connection;
+    unsigned int major = 1, minor = 0;   /* Assume HTTP/1.0 if non-"HTTP" protocol */
+    int len = 0;
+    int valid_protocol = 1;
+
+    /* Read past empty lines until we get a real request line,
+     * a read error, the connection closes (EOF), or we timeout.
+     *
+     * We skip empty lines because browsers have to tack a CRLF on to the end
+     * of POSTs to support old CERN webservers.  But note that we may not
+     * have flushed any previous response completely to the client yet.
+     * We delay the flush as long as possible so that we can improve
+     * performance for clients that are pipelining requests.  If a request
+     * is pipelined then we won't block during the (implicit) read() below.
+     * If the requests aren't pipelined, then the client is still waiting
+     * for the final buffer flush from us, and we will block in the implicit
+     * read().  B_SAFEREAD ensures that the BUFF layer flushes if it will
+     * have to block during a read.
+     */
+    ap_bsetflag(conn->client, B_SAFEREAD, 1);
+    while ((len = ap_getline(l, sizeof(l), conn->client, 0)) <= 0) {
+        if ((len < 0) || ap_bgetflag(conn->client, B_EOF) || !conn->keepalives) {
+            ap_bsetflag(conn->client, B_SAFEREAD, 0);
+	    /* this is a hack to make sure that request time is set,
+	     * it's not perfect, but it's better than nothing 
+	     */
+	    r->request_time = time(0);
+            return 0;
+        }
+    }
+    /* we've probably got something to do, ignore graceful restart requests */
+#ifdef SIGUSR1
+    signal(SIGUSR1, SIG_IGN);
+#endif
+
+    ap_bsetflag(conn->client, B_SAFEREAD, 0);
+
+    r->request_time = time(NULL);
+    r->the_request = ap_pstrdup(r->pool, l);
+    r->method = ap_getword_white(r->pool, &ll);
+    uri = ap_getword_white(r->pool, &ll);
+
+    /* Provide quick information about the request method as soon as known */
+
+    r->method_number = ap_method_number_of(r->method);
+    if (r->method_number == M_GET && r->method[0] == 'H') {
+        r->header_only = 1;
+    }
+
+    ap_parse_uri(r, uri);
+
+    /* ap_getline returns (size of max buffer - 1) if it fills up the
+     * buffer before finding the end-of-line.  This is only going to
+     * happen if it exceeds the configured limit for a request-line.
+     */
+    if (len > r->server->limit_req_line) {
+        r->status    = HTTP_REQUEST_URI_TOO_LARGE;
+        r->proto_num = HTTP_VERSION(1,0);
+        r->protocol  = ap_pstrdup(r->pool, "HTTP/1.0");
+        return 0;
+    }
+
+    r->assbackwards = (ll[0] == '\0');
+    r->protocol = ap_pstrdup(r->pool, ll[0] ? ll : "HTTP/0.9");
+
+    /* Avoid sscanf in the common case */
+    if (strlen(r->protocol) == 8
+        && r->protocol[0] == 'H' && r->protocol[1] == 'T'
+	&& r->protocol[2] == 'T' && r->protocol[3] == 'P'
+        && r->protocol[4] == '/' && ap_isdigit(r->protocol[5])
+	&& r->protocol[6] == '.' && ap_isdigit(r->protocol[7])) {
+        r->proto_num = HTTP_VERSION(r->protocol[5] - '0', r->protocol[7] - '0');
+    }
+    else {
+        char lint[2];
+        char http[5];
+	if (3 == sscanf(r->protocol, "%4s/%u.%u%1s", http, &major, &minor, lint)
+            && (strcasecmp("http", http) == 0)
+	    && (minor < HTTP_VERSION(1,0)) ) /* don't allow HTTP/0.1000 */
+	    r->proto_num = HTTP_VERSION(major, minor);
+	else {
+	    r->proto_num = HTTP_VERSION(1,0);
+	    valid_protocol = 0;
+	}
+    }
+
+    /* Check for a valid protocol, and disallow everything but whitespace
+     * after the protocol string. A protocol string of nothing but
+     * whitespace is considered valid */
+    if (ap_protocol_req_check && !valid_protocol) {
+        int n = 0;
+	while (ap_isspace(r->protocol[n]))
+	    ++n;
+	if (r->protocol[n] != '\0') {
+	    r->status    = HTTP_BAD_REQUEST;
+	    r->proto_num = HTTP_VERSION(1,0);
+	    r->protocol  = ap_pstrdup(r->pool, "HTTP/1.0");
+	    ap_table_setn(r->notes, "error-notes",
+                     "The request line contained invalid characters "
+                     "following the protocol string.<P>\n");
+	    return 0;
+	}
+    }
+
+    return 1;
+}
+
+static void get_mime_headers(request_rec *r)
+{
+    char field[DEFAULT_LIMIT_REQUEST_FIELDSIZE + 2]; /* ap_getline's two extra */
+    conn_rec *c = r->connection;
+    char *value;
+    char *copy;
+    int len;
+    int fields_read = 0;
+    table *tmp_headers;
+
+    /* We'll use ap_overlap_tables later to merge these into r->headers_in. */
+    tmp_headers = ap_make_table(r->pool, 50);
+
+    /*
+     * Read header lines until we get the empty separator line, a read error,
+     * the connection closes (EOF), reach the server limit, or we timeout.
+     */
+    while ((len = ap_getline(field, sizeof(field), c->client, 1)) > 0) {
+
+        if (r->server->limit_req_fields &&
+            (++fields_read > r->server->limit_req_fields)) {
+            r->status = HTTP_BAD_REQUEST;
+            ap_table_setn(r->notes, "error-notes",
+                          "The number of request header fields exceeds "
+                          "this server's limit.<P>\n");
+            return;
+        }
+        /* ap_getline returns (size of max buffer - 1) if it fills up the
+         * buffer before finding the end-of-line.  This is only going to
+         * happen if it exceeds the configured limit for a field size.
+         */
+        if (len > r->server->limit_req_fieldsize) {
+            r->status = HTTP_BAD_REQUEST;
+            ap_table_setn(r->notes, "error-notes", ap_pstrcat(r->pool,
+                "Size of a request header field exceeds server limit.<P>\n"
+                "<PRE>\n", ap_escape_html(r->pool, field), "</PRE>\n", NULL));
+            return;
+        }
+        copy = ap_palloc(r->pool, len + 1);
+        memcpy(copy, field, len + 1);
+
+        if (!(value = strchr(copy, ':'))) {     /* Find the colon separator */
+            r->status = HTTP_BAD_REQUEST;       /* or abort the bad request */
+            ap_table_setn(r->notes, "error-notes", ap_pstrcat(r->pool,
+                "Request header field is missing colon separator.<P>\n"
+                "<PRE>\n", ap_escape_html(r->pool, copy), "</PRE>\n", NULL));
+            return;
+        }
+
+        *value = '\0';
+        ++value;
+        while (*value == ' ' || *value == '\t')
+            ++value;            /* Skip to start of value   */
+
+	ap_table_addn(tmp_headers, copy, value);
+    }
+
+    ap_overlap_tables(r->headers_in, tmp_headers, AP_OVERLAP_TABLES_MERGE);
+}
+
+API_EXPORT(request_rec *) ap_read_request(conn_rec *conn)
+{
+    request_rec *r;
+    pool *p;
+    const char *expect;
+    int access_status;
+
+    p = ap_make_sub_pool(conn->pool);
+    r = ap_pcalloc(p, sizeof(request_rec));
+    r->pool            = p;
+    r->connection      = conn;
+    conn->server       = conn->base_server;
+    r->server          = conn->server;
+
+    conn->keptalive    = conn->keepalive == 1;
+    conn->keepalive    = 0;
+
+    conn->user         = NULL;
+    conn->ap_auth_type    = NULL;
+
+    r->headers_in      = ap_make_table(r->pool, 50);
+    r->subprocess_env  = ap_make_table(r->pool, 50);
+    r->headers_out     = ap_make_table(r->pool, 12);
+    r->err_headers_out = ap_make_table(r->pool, 5);
+    r->notes           = ap_make_table(r->pool, 5);
+
+    r->request_config  = ap_create_request_config(r->pool);
+    r->per_dir_config  = r->server->lookup_defaults;
+
+    r->sent_bodyct     = 0;                      /* bytect isn't for body */
+
+    r->read_length     = 0;
+    r->read_body       = REQUEST_NO_BODY;
+
+    r->status          = HTTP_REQUEST_TIME_OUT;  /* Until we get a request */
+    r->the_request     = NULL;
+
+#ifdef CHARSET_EBCDIC
+    ap_bsetflag(r->connection->client, B_ASCII2EBCDIC, r->ebcdic.conv_in  = 1);
+    ap_bsetflag(r->connection->client, B_EBCDIC2ASCII, r->ebcdic.conv_out = 1);
+#endif
+
+    /* Get the request... */
+
+    ap_keepalive_timeout("read request line", r);
+    if (!read_request_line(r)) {
+        ap_kill_timeout(r);
+        if (r->status == HTTP_REQUEST_URI_TOO_LARGE) {
+
+            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+                         "request failed: URI too long");
+            ap_send_error_response(r, 0);
+            ap_log_transaction(r);
+            return r;
+        }
+        else if (r->status == HTTP_BAD_REQUEST) {
+            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+                         "request failed: erroneous characters after protocol string: %s",
+			 ap_escape_logitem(r->pool, r->the_request));
+            ap_send_error_response(r, 0);
+            ap_log_transaction(r);
+            return r;
+        }
+        return NULL;
+    }
+    if (!r->assbackwards) {
+        ap_hard_timeout("read request headers", r);
+        get_mime_headers(r);
+        ap_kill_timeout(r);
+        if (r->status != HTTP_REQUEST_TIME_OUT) {
+            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+                         "request failed: error reading the headers");
+            ap_send_error_response(r, 0);
+            ap_log_transaction(r);
+            return r;
+        }
+    }
+    else {
+        ap_kill_timeout(r);
+
+        if (r->header_only) {
+            /*
+             * Client asked for headers only with HTTP/0.9, which doesn't send
+             * headers! Have to dink things just to make sure the error message
+             * comes through...
+             */
+            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+                          "client sent invalid HTTP/0.9 request: HEAD %s",
+                          r->uri);
+            r->header_only = 0;
+            r->status = HTTP_BAD_REQUEST;
+            ap_send_error_response(r, 0);
+            ap_log_transaction(r);
+            return r;
+        }
+    }
+
+    r->status = HTTP_OK;                         /* Until further notice. */
+
+    /* update what we think the virtual host is based on the headers we've
+     * now read. may update status.
+     */
+    ap_update_vhost_from_headers(r);
+
+    /* we may have switched to another server */
+    r->per_dir_config = r->server->lookup_defaults;
+
+    conn->keptalive = 0;        /* We now have a request to play with */
+
+    if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1,1))) ||
+        ((r->proto_num == HTTP_VERSION(1,1)) &&
+         !ap_table_get(r->headers_in, "Host"))) {
+        /*
+         * Client sent us an HTTP/1.1 or later request without telling us the
+         * hostname, either with a full URL or a Host: header. We therefore
+         * need to (as per the 1.1 spec) send an error.  As a special case,
+         * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain
+         * a Host: header, and the server MUST respond with 400 if it doesn't.
+         */
+        r->status = HTTP_BAD_REQUEST;
+        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+                      "client sent HTTP/1.1 request without hostname "
+                      "(see RFC2616 section 14.23): %s", r->uri);
+    }
+    if (r->status != HTTP_OK) {
+        ap_send_error_response(r, 0);
+        ap_log_transaction(r);
+        return r;
+    }
+
+    if ((access_status = ap_run_post_read_request(r))) {
+        ap_die(access_status, r);
+        ap_log_transaction(r);
+        return NULL;
+    }
+
+    if (((expect = ap_table_get(r->headers_in, "Expect")) != NULL) &&
+        (expect[0] != '\0')) {
+        /*
+         * The Expect header field was added to HTTP/1.1 after RFC 2068
+         * as a means to signal when a 100 response is desired and,
+         * unfortunately, to signal a poor man's mandatory extension that
+         * the server must understand or return 417 Expectation Failed.
+         */
+        if (strcasecmp(expect, "100-continue") == 0) {
+            r->expecting_100 = 1;
+        }
+        else {
+            r->status = HTTP_EXPECTATION_FAILED;
+            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, r,
+                          "client sent an unrecognized expectation value of "
+                          "Expect: %s", expect);
+            ap_send_error_response(r, 0);
+            (void) ap_discard_request_body(r);
+            ap_log_transaction(r);
+            return r;
+        }
+    }
+
+    return r;
+}
+
+/*
+ * A couple of other functions which initialize some of the fields of
+ * a request structure, as appropriate for adjuncts of one kind or another
+ * to a request in progress.  Best here, rather than elsewhere, since
+ * *someone* has to set the protocol-specific fields...
+ */
+
+API_EXPORT(void) ap_set_sub_req_protocol(request_rec *rnew, const request_rec *r)
+{
+    rnew->the_request     = r->the_request;  /* Keep original request-line */
+
+    rnew->assbackwards    = 1;   /* Don't send headers from this. */
+    rnew->no_local_copy   = 1;   /* Don't try to send USE_LOCAL_COPY for a
+                                  * fragment. */
+    rnew->method          = "GET";
+    rnew->method_number   = M_GET;
+    rnew->protocol        = "INCLUDED";
+
+    rnew->status          = HTTP_OK;
+
+    rnew->headers_in      = r->headers_in;
+    rnew->subprocess_env  = ap_copy_table(rnew->pool, r->subprocess_env);
+    rnew->headers_out     = ap_make_table(rnew->pool, 5);
+    rnew->err_headers_out = ap_make_table(rnew->pool, 5);
+    rnew->notes           = ap_make_table(rnew->pool, 5);
+
+    rnew->expecting_100   = r->expecting_100;
+    rnew->read_length     = r->read_length;
+    rnew->read_body       = REQUEST_NO_BODY;
+
+    rnew->main = (request_rec *) r;
+}
+
+API_EXPORT(void) ap_finalize_sub_req_protocol(request_rec *sub)
+{
+    SET_BYTES_SENT(sub->main);
+}
+
+/*
+ * Support for the Basic authentication protocol, and a bit for Digest.
+ */
+
+API_EXPORT(void) ap_note_auth_failure(request_rec *r)
+{
+    if (!strcasecmp(ap_auth_type(r), "Basic"))
+        ap_note_basic_auth_failure(r);
+    else if (!strcasecmp(ap_auth_type(r), "Digest"))
+        ap_note_digest_auth_failure(r);
+}
+
+API_EXPORT(void) ap_note_basic_auth_failure(request_rec *r)
+{
+    if (strcasecmp(ap_auth_type(r), "Basic"))
+        ap_note_auth_failure(r);
+    else
+        ap_table_setn(r->err_headers_out,
+                  r->proxyreq == STD_PROXY ? "Proxy-Authenticate"
+		      : "WWW-Authenticate",
+                  ap_pstrcat(r->pool, "Basic realm=\"", ap_auth_name(r), "\"",
+                          NULL));
+}
+
+API_EXPORT(void) ap_note_digest_auth_failure(request_rec *r)
+{
+    /* We need to create a nonce which:
+     * a) changes all the time (see r->request_time)
+     *    below and
+     * b) of which we can verify that it is our own
+     *    fairly easily when it comes to veryfing
+     *    the digest coming back in the response.
+     * c) and which as a whole should not
+     *    be unlikely to be in use anywhere else.
+     */
+    char * nonce_prefix = ap_md5(r->pool,
+           (unsigned char *)
+           ap_psprintf(r->pool, "%s%lu",
+                       ap_auth_nonce(r), r->request_time));
+
+    ap_table_setn(r->err_headers_out,
+	    r->proxyreq == STD_PROXY ? "Proxy-Authenticate"
+		  : "WWW-Authenticate",
+           ap_psprintf(r->pool, "Digest realm=\"%s\", nonce=\"%s%lu\"",
+               ap_auth_name(r), nonce_prefix, r->request_time));
+}
+
+API_EXPORT(int) ap_get_basic_auth_pw(request_rec *r, const char **pw)
+{
+    const char *auth_line = ap_table_get(r->headers_in,
+					 r->proxyreq == STD_PROXY
+					 ? "Proxy-Authorization"
+					 : "Authorization");
+    const char *t;
+
+    if (!(t = ap_auth_type(r)) || strcasecmp(t, "Basic"))
+        return DECLINED;
+
+    if (!ap_auth_name(r)) {
+        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR,
+		    r, "need AuthName: %s", r->uri);
+        return SERVER_ERROR;
+    }
+
+    if (!auth_line) {
+        ap_note_basic_auth_failure(r);
+        return AUTH_REQUIRED;
+    }
+
+    if (strcasecmp(ap_getword(r->pool, &auth_line, ' '), "Basic")) {
+        /* Client tried to authenticate using wrong auth scheme */
+        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+                    "client used wrong authentication scheme: %s", r->uri);
+        ap_note_basic_auth_failure(r);
+        return AUTH_REQUIRED;
+    }
+
+    /* No CHARSET_EBCDIC Issue here because the line has already
+     * been converted to native text.
+     */
+    while (*auth_line== ' ' || *auth_line== '\t')
+        auth_line++;
+
+    t = ap_pbase64decode(r->pool, auth_line);
+    /* Note that this allocation has to be made from r->connection->pool
+     * because it has the lifetime of the connection.  The other allocations
+     * are temporary and can be tossed away any time.
+     */
+    r->connection->user = ap_getword_nulls (r->connection->pool, &t, ':');
+    r->connection->ap_auth_type = "Basic";
+
+    *pw = t;
+
+    return OK;
+}
+
+/* New Apache routine to map status codes into array indicies
+ *  e.g.  100 -> 0,  101 -> 1,  200 -> 2 ...
+ * The number of status lines must equal the value of RESPONSE_CODES (httpd.h)
+ * and must be listed in order.
+ */
+
+#ifdef UTS21
+/* The second const triggers an assembler bug on UTS 2.1.
+ * Another workaround is to move some code out of this file into another,
+ *   but this is easier.  Dave Dykstra, 3/31/99 
+ */
+static const char * status_lines[RESPONSE_CODES] =
+#else
+static const char * const status_lines[RESPONSE_CODES] =
+#endif
+{
+    "100 Continue",
+    "101 Switching Protocols",
+    "102 Processing",
+#define LEVEL_200  3
+    "200 OK",
+    "201 Created",
+    "202 Accepted",
+    "203 Non-Authoritative Information",
+    "204 No Content",
+    "205 Reset Content",
+    "206 Partial Content",
+    "207 Multi-Status",
+#define LEVEL_300 11
+    "300 Multiple Choices",
+    "301 Moved Permanently",
+    "302 Found",
+    "303 See Other",
+    "304 Not Modified",
+    "305 Use Proxy",
+    "306 unused",
+    "307 Temporary Redirect",
+#define LEVEL_400 19
+    "400 Bad Request",
+    "401 Authorization Required",
+    "402 Payment Required",
+    "403 Forbidden",
+    "404 Not Found",
+    "405 Method Not Allowed",
+    "406 Not Acceptable",
+    "407 Proxy Authentication Required",
+    "408 Request Time-out",
+    "409 Conflict",
+    "410 Gone",
+    "411 Length Required",
+    "412 Precondition Failed",
+    "413 Request Entity Too Large",
+    "414 Request-URI Too Large",
+    "415 Unsupported Media Type",
+    "416 Requested Range Not Satisfiable",
+    "417 Expectation Failed",
+    "418 unused",
+    "419 unused",
+    "420 unused",
+    "421 unused",
+    "422 Unprocessable Entity",
+    "423 Locked",
+    "424 Failed Dependency",
+#define LEVEL_500 44
+    "500 Internal Server Error",
+    "501 Method Not Implemented",
+    "502 Bad Gateway",
+    "503 Service Temporarily Unavailable",
+    "504 Gateway Time-out",
+    "505 HTTP Version Not Supported",
+    "506 Variant Also Negotiates",
+    "507 Insufficient Storage",
+    "508 unused",
+    "509 unused",
+    "510 Not Extended"
+};
+
+/* The index is found by its offset from the x00 code of each level.
+ * Although this is fast, it will need to be replaced if some nutcase
+ * decides to define a high-numbered code before the lower numbers.
+ * If that sad event occurs, replace the code below with a linear search
+ * from status_lines[shortcut[i]] to status_lines[shortcut[i+1]-1];
+ */
+API_EXPORT(int) ap_index_of_response(int status)
+{
+    static int shortcut[6] = {0, LEVEL_200, LEVEL_300, LEVEL_400,
+    LEVEL_500, RESPONSE_CODES};
+    int i, pos;
+
+    if (status < 100)           /* Below 100 is illegal for HTTP status */
+        return LEVEL_500;
+
+    for (i = 0; i < 5; i++) {
+        status -= 100;
+        if (status < 100) {
+            pos = (status + shortcut[i]);
+            if (pos < shortcut[i + 1])
+                return pos;
+            else
+                return LEVEL_500;       /* status unknown (falls in gap) */
+        }
+    }
+    return LEVEL_500;           /* 600 or above is also illegal */
+}
+
+/* Send a single HTTP header field to the client.  Note that this function
+ * is used in calls to table_do(), so their interfaces are co-dependent.
+ * In other words, don't change this one without checking table_do in alloc.c.
+ * It returns true unless there was a write error of some kind.
+ */
+API_EXPORT_NONSTD(int) ap_send_header_field(request_rec *r,
+                                            const char *fieldname,
+                                            const char *fieldval)
+{
+    if (strcasecmp(fieldname, "ETag") == 0) {
+        if (ap_table_get(r->notes, "no-etag") != NULL) {
+            return 1;
+        }
+    }
+    return (0 < ap_rvputs(r, fieldname, ": ", fieldval, CRLF, NULL));
+}
+
+API_EXPORT(void) ap_basic_http_header(request_rec *r)
+{
+    char *protocol;
+
+    if (r->assbackwards)
+        return;
+
+    if (!r->status_line)
+        r->status_line = status_lines[ap_index_of_response(r->status)];
+
+    /* kluge around broken browsers when indicated by force-response-1.0
+     */
+    if (r->proto_num == HTTP_VERSION(1,0)
+       && ap_table_get(r->subprocess_env, "force-response-1.0")) {
+
+        protocol = "HTTP/1.0";
+        r->connection->keepalive = -1;
+    }
+    else
+        protocol = SERVER_PROTOCOL;
+
+#ifdef CHARSET_EBCDIC
+    PUSH_EBCDIC_OUTPUTCONVERSION_STATE_r(r, 1);
+#endif /*CHARSET_EBCDIC*/
+
+    /* output the HTTP/1.x Status-Line */
+    ap_rvputs(r, protocol, " ", r->status_line, CRLF, NULL);
+
+    /* output the date header */
+    ap_send_header_field(r, "Date", ap_gm_timestr_822(r->pool, r->request_time));
+
+    /* keep the set-by-proxy server header, otherwise
+     * generate a new server header */
+    if (r->proxyreq) {
+        const char *server = ap_table_get(r->headers_out, "Server");
+        if (server) {
+            ap_send_header_field(r, "Server", server);
+        }
+    }
+    else {
+        ap_send_header_field(r, "Server", ap_get_server_version());
+    }
+
+    /* unset so we don't send them again */
+    ap_table_unset(r->headers_out, "Date");        /* Avoid bogosity */
+    ap_table_unset(r->headers_out, "Server");
+#ifdef CHARSET_EBCDIC
+    POP_EBCDIC_OUTPUTCONVERSION_STATE_r(r);
+#endif /*CHARSET_EBCDIC*/
+}
+
+/* Navigator versions 2.x, 3.x and 4.0 betas up to and including 4.0b2
+ * have a header parsing bug.  If the terminating \r\n occur starting
+ * at offset 256, 257 or 258 of output then it will not properly parse
+ * the headers.  Curiously it doesn't exhibit this problem at 512, 513.
+ * We are guessing that this is because their initial read of a new request
+ * uses a 256 byte buffer, and subsequent reads use a larger buffer.
+ * So the problem might exist at different offsets as well.
+ *
+ * This should also work on keepalive connections assuming they use the
+ * same small buffer for the first read of each new request.
+ *
+ * At any rate, we check the bytes written so far and, if we are about to
+ * tickle the bug, we instead insert a bogus padding header.  Since the bug
+ * manifests as a broken image in Navigator, users blame the server.  :(
+ * It is more expensive to check the User-Agent than it is to just add the
+ * bytes, so we haven't used the BrowserMatch feature here.
+ */
+static void terminate_header(BUFF *client)
+{
+    long int bs;
+
+    ap_bgetopt(client, BO_BYTECT, &bs);
+    if (bs >= 255 && bs <= 257)
+        ap_bputs("X-Pad: avoid browser bug" CRLF, client);
+
+    ap_bputs(CRLF, client);  /* Send the terminating empty line */
+}
+
+/* Build the Allow field-value from the request handler method mask.
+ * Note that we always allow TRACE, since it is handled below.
+ */
+static char *make_allow(request_rec *r)
+{
+    return 2 + ap_pstrcat(r->pool,
+                   (r->allowed & (1 << M_GET))       ? ", GET, HEAD" : "",
+                   (r->allowed & (1 << M_POST))      ? ", POST"      : "",
+                   (r->allowed & (1 << M_PUT))       ? ", PUT"       : "",
+                   (r->allowed & (1 << M_DELETE))    ? ", DELETE"    : "",
+                   (r->allowed & (1 << M_CONNECT))   ? ", CONNECT"   : "",
+                   (r->allowed & (1 << M_OPTIONS))   ? ", OPTIONS"   : "",
+                   (r->allowed & (1 << M_PATCH))     ? ", PATCH"     : "",
+                   (r->allowed & (1 << M_PROPFIND))  ? ", PROPFIND"  : "",
+                   (r->allowed & (1 << M_PROPPATCH)) ? ", PROPPATCH" : "",
+                   (r->allowed & (1 << M_MKCOL))     ? ", MKCOL"     : "",
+                   (r->allowed & (1 << M_COPY))      ? ", COPY"      : "",
+                   (r->allowed & (1 << M_MOVE))      ? ", MOVE"      : "",
+                   (r->allowed & (1 << M_LOCK))      ? ", LOCK"      : "",
+                   (r->allowed & (1 << M_UNLOCK))    ? ", UNLOCK"    : "",
+                   ", TRACE",
+                   NULL);
+}
+
+API_EXPORT(int) ap_send_http_trace(request_rec *r)
+{
+    int rv;
+
+    /* Get the original request */
+    while (r->prev)
+        r = r->prev;
+
+    if ((rv = ap_setup_client_block(r, REQUEST_NO_BODY)))
+        return rv;
+
+    ap_hard_timeout("send TRACE", r);
+
+    r->content_type = "message/http";
+    ap_send_http_header(r);
+#ifdef CHARSET_EBCDIC
+    /* Server-generated response, converted */
+    ap_bsetflag(r->connection->client, B_EBCDIC2ASCII, r->ebcdic.conv_out = 1);
+#endif
+
+    /* Now we recreate the request, and echo it back */
+
+    ap_rvputs(r, r->the_request, CRLF, NULL);
+
+    ap_table_do((int (*) (void *, const char *, const char *))
+                ap_send_header_field, (void *) r, r->headers_in, NULL);
+    ap_rputs(CRLF, r);
+
+    ap_kill_timeout(r);
+    return OK;
+}
+
+API_EXPORT(int) ap_send_http_options(request_rec *r)
+{
+    const long int zero = 0L;
+
+    if (r->assbackwards)
+        return DECLINED;
+
+    ap_hard_timeout("send OPTIONS", r);
+
+    ap_basic_http_header(r);
+
+    ap_table_setn(r->headers_out, "Content-Length", "0");
+    ap_table_setn(r->headers_out, "Allow", make_allow(r));
+    ap_set_keepalive(r);
+
+    ap_table_do((int (*) (void *, const char *, const char *)) ap_send_header_field,
+             (void *) r, r->headers_out, NULL);
+
+    terminate_header(r->connection->client);
+
+    ap_kill_timeout(r);
+    ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
+
+    return OK;
+}
+
+/*
+ * Here we try to be compatible with clients that want multipart/x-byteranges
+ * instead of multipart/byteranges (also see above), as per HTTP/1.1. We
+ * look for the Request-Range header (e.g. Netscape 2 and 3) as an indication
+ * that the browser supports an older protocol. We also check User-Agent
+ * for Microsoft Internet Explorer 3, which needs this as well.
+ */
+static int use_range_x(request_rec *r)
+{
+    const char *ua;
+    return (ap_table_get(r->headers_in, "Request-Range") ||
+            ((ua = ap_table_get(r->headers_in, "User-Agent"))
+             && strstr(ua, "MSIE 3")));
+}
+
+/* This routine is called by ap_table_do and merges all instances of
+ * the passed field values into a single array that will be further
+ * processed by some later routine.  Originally intended to help split
+ * and recombine multiple Vary fields, though it is generic to any field
+ * consisting of comma/space-separated tokens.
+ */
+static int uniq_field_values(void *d, const char *key, const char *val)
+{
+    array_header *values;
+    char *start;
+    char *e;
+    char **strpp;
+    int  i;
+
+    values = (array_header *)d;
+
+    e = ap_pstrdup(values->pool, val);
+
+    do {
+        /* Find a non-empty fieldname */
+
+        while (*e == ',' || ap_isspace(*e)) {
+            ++e;
+        }
+        if (*e == '\0') {
+            break;
+        }
+        start = e;
+        while (*e != '\0' && *e != ',' && !ap_isspace(*e)) {
+            ++e;
+        }
+        if (*e != '\0') {
+            *e++ = '\0';
+        }
+
+        /* Now add it to values if it isn't already represented.
+         * Could be replaced by a ap_array_strcasecmp() if we had one.
+         */
+        for (i = 0, strpp = (char **) values->elts; i < values->nelts;
+             ++i, ++strpp) {
+            if (*strpp && strcasecmp(*strpp, start) == 0) {
+                break;
+            }
+        }
+        if (i == values->nelts) {  /* if not found */
+           *(char **)ap_push_array(values) = start;
+        }
+    } while (*e != '\0');
+
+    return 1;
+}
+
+/*
+ * Since some clients choke violently on multiple Vary fields, or
+ * Vary fields with duplicate tokens, combine any multiples and remove
+ * any duplicates.
+ */
+static void fixup_vary(request_rec *r)
+{
+    array_header *varies;
+
+    varies = ap_make_array(r->pool, 5, sizeof(char *));
+
+    /* Extract all Vary fields from the headers_out, separate each into
+     * its comma-separated fieldname values, and then add them to varies
+     * if not already present in the array.
+     */
+    ap_table_do((int (*)(void *, const char *, const char *))uniq_field_values,
+		(void *) varies, r->headers_out, "Vary", NULL);
+
+    /* If we found any, replace old Vary fields with unique-ified value */
+
+    if (varies->nelts > 0) {
+	ap_table_setn(r->headers_out, "Vary",
+		      ap_array_pstrcat(r->pool, varies, ','));
+    }
+}
+
+API_EXPORT(void) ap_send_http_header(request_rec *r)
+{
+    int i;
+    const long int zero = 0L;
+
+#ifdef CHARSET_EBCDIC
+    /* Use previously determined conversion (output): */
+    ap_bsetflag(r->connection->client, B_EBCDIC2ASCII, ap_checkconv(r));
+#endif /*CHARSET_EBCDIC*/
+
+    if (r->assbackwards) {
+        if (!r->main)
+            ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
+        r->sent_bodyct = 1;
+        return;
+    }
+
+    /*
+     * Now that we are ready to send a response, we need to combine the two
+     * header field tables into a single table.  If we don't do this, our
+     * later attempts to set or unset a given fieldname might be bypassed.
+     */
+    if (!ap_is_empty_table(r->err_headers_out))
+        r->headers_out = ap_overlay_tables(r->pool, r->err_headers_out,
+                                        r->headers_out);
+
+    /*
+     * Remove the 'Vary' header field if the client can't handle it.
+     * Since this will have nasty effects on HTTP/1.1 caches, force
+     * the response into HTTP/1.0 mode.
+     */
+    if (ap_table_get(r->subprocess_env, "force-no-vary") != NULL) {
+	ap_table_unset(r->headers_out, "Vary");
+	r->proto_num = HTTP_VERSION(1,0);
+	ap_table_set(r->subprocess_env, "force-response-1.0", "1");
+    }
+    else {
+	fixup_vary(r);
+    }
+
+    ap_hard_timeout("send headers", r);
+
+    ap_basic_http_header(r);
+
+#ifdef CHARSET_EBCDIC
+    PUSH_EBCDIC_OUTPUTCONVERSION_STATE_r(r, 1);
+#endif /*CHARSET_EBCDIC*/
+
+    ap_set_keepalive(r);
+
+    if (r->chunked) {
+        ap_table_mergen(r->headers_out, "Transfer-Encoding", "chunked");
+        ap_table_unset(r->headers_out, "Content-Length");
+    }
+
+    if (r->byterange > 1)
+        ap_table_setn(r->headers_out, "Content-Type",
+                  ap_pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/",
+                          "byteranges; boundary=", r->boundary, NULL));
+    else ap_table_setn(r->headers_out, "Content-Type", make_content_type(r, 
+	r->content_type));
+
+    if (r->content_encoding)
+        ap_table_setn(r->headers_out, "Content-Encoding", r->content_encoding);
+
+    if (r->content_languages && r->content_languages->nelts) {
+        for (i = 0; i < r->content_languages->nelts; ++i) {
+            ap_table_mergen(r->headers_out, "Content-Language",
+                        ((char **) (r->content_languages->elts))[i]);
+        }
+    }
+    else if (r->content_language)
+        ap_table_setn(r->headers_out, "Content-Language", r->content_language);
+
+    /*
+     * Control cachability for non-cachable responses if not already set by
+     * some other part of the server configuration.
+     */
+    if (r->no_cache && !ap_table_get(r->headers_out, "Expires"))
+        ap_table_addn(r->headers_out, "Expires",
+                  ap_gm_timestr_822(r->pool, r->request_time));
+
+    /* Send the entire table of header fields, terminated by an empty line. */
+
+    ap_table_do((int (*) (void *, const char *, const char *)) ap_send_header_field,
+             (void *) r, r->headers_out, NULL);
+
+    terminate_header(r->connection->client);
+
+    ap_kill_timeout(r);
+
+    ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
+    r->sent_bodyct = 1;         /* Whatever follows is real body stuff... */
+
+    /* Set buffer flags for the body */
+    if (r->chunked)
+        ap_bsetflag(r->connection->client, B_CHUNK, 1);
+#ifdef CHARSET_EBCDIC
+    POP_EBCDIC_OUTPUTCONVERSION_STATE_r(r);
+#endif /*CHARSET_EBCDIC*/
+}
+
+/* finalize_request_protocol is called at completion of sending the
+ * response.  It's sole purpose is to send the terminating protocol
+ * information for any wrappers around the response message body
+ * (i.e., transfer encodings).  It should have been named finalize_response.
+ */
+API_EXPORT(void) ap_finalize_request_protocol(request_rec *r)
+{
+    if (r->chunked && !r->connection->aborted) {
+#ifdef CHARSET_EBCDIC
+        PUSH_EBCDIC_OUTPUTCONVERSION_STATE_r(r, 1);
+#endif
+        /*
+         * Turn off chunked encoding --- we can only do this once.
+         */
+        r->chunked = 0;
+        ap_bsetflag(r->connection->client, B_CHUNK, 0);
+
+        ap_soft_timeout("send ending chunk", r);
+        ap_rputs("0" CRLF, r);
+        /* If we had footer "headers", we'd send them now */
+        ap_rputs(CRLF, r);
+        ap_kill_timeout(r);
+
+#ifdef CHARSET_EBCDIC
+        POP_EBCDIC_OUTPUTCONVERSION_STATE_r(r);
+#endif /*CHARSET_EBCDIC*/
+    }
+}
+
+/* Here we deal with getting the request message body from the client.
+ * Whether or not the request contains a body is signaled by the presence
+ * of a non-zero Content-Length or by a Transfer-Encoding: chunked.
+ *
+ * Note that this is more complicated than it was in Apache 1.1 and prior
+ * versions, because chunked support means that the module does less.
+ *
+ * The proper procedure is this:
+ *
+ * 1. Call setup_client_block() near the beginning of the request
+ *    handler. This will set up all the necessary properties, and will
+ *    return either OK, or an error code. If the latter, the module should
+ *    return that error code. The second parameter selects the policy to
+ *    apply if the request message indicates a body, and how a chunked
+ *    transfer-coding should be interpreted. Choose one of
+ *
+ *    REQUEST_NO_BODY          Send 413 error if message has any body
+ *    REQUEST_CHUNKED_ERROR    Send 411 error if body without Content-Length
+ *    REQUEST_CHUNKED_DECHUNK  If chunked, remove the chunks for me.
+ *    REQUEST_CHUNKED_PASS     Pass the chunks to me without removal.
+ *
+ *    In order to use the last two options, the caller MUST provide a buffer
+ *    large enough to hold a chunk-size line, including any extensions.
+ *
+ * 2. When you are ready to read a body (if any), call should_client_block().
+ *    This will tell the module whether or not to read input. If it is 0,
+ *    the module should assume that there is no message body to read.
+ *    This step also sends a 100 Continue response to HTTP/1.1 clients,
+ *    so should not be called until the module is *definitely* ready to
+ *    read content. (otherwise, the point of the 100 response is defeated).
+ *    Never call this function more than once.
+ *
+ * 3. Finally, call get_client_block in a loop. Pass it a buffer and its size.
+ *    It will put data into the buffer (not necessarily a full buffer), and
+ *    return the length of the input block. When it is done reading, it will
+ *    return 0 if EOF, or -1 if there was an error.
+ *    If an error occurs on input, we force an end to keepalive.
+ */
+
+API_EXPORT(int) ap_setup_client_block(request_rec *r, int read_policy)
+{
+    const char *tenc = ap_table_get(r->headers_in, "Transfer-Encoding");
+    const char *lenp = ap_table_get(r->headers_in, "Content-Length");
+    unsigned long max_body;
+
+    r->read_body = read_policy;
+    r->read_chunked = 0;
+    r->remaining = 0;
+
+    if (tenc) {
+        if (strcasecmp(tenc, "chunked")) {
+            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+                        "Unknown Transfer-Encoding %s", tenc);
+            return HTTP_NOT_IMPLEMENTED;
+        }
+        if (r->read_body == REQUEST_CHUNKED_ERROR) {
+            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+                        "chunked Transfer-Encoding forbidden: %s", r->uri);
+            return (lenp) ? HTTP_BAD_REQUEST : HTTP_LENGTH_REQUIRED;
+        }
+
+        r->read_chunked = 1;
+    }
+    else if (lenp) {
+        const char *pos = lenp;
+        int conversion_error = 0;
+
+        while (ap_isspace(*pos))
+            ++pos;
+
+        if (*pos == '\0') {
+            /* special case test - a C-L field NULL or all blanks is
+             * assumed OK and defaults to 0. Otherwise, we do a
+             * strict check of the field */
+            r->remaining = 0;
+        }
+        else {
+            char *endstr;
+            errno = 0;
+            r->remaining = ap_strtol(lenp, &endstr, 10);
+            if (errno || (endstr && *endstr) || (r->remaining < 0)) {
+                conversion_error = 1;
+            }
+        }
+
+        if (conversion_error) {
+            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+                        "Invalid Content-Length");
+            return HTTP_BAD_REQUEST;
+        }
+    }
+
+    if ((r->read_body == REQUEST_NO_BODY) &&
+        (r->read_chunked || (r->remaining > 0))) {
+        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+                    "%s with body is not allowed for %s", r->method, r->uri);
+        return HTTP_REQUEST_ENTITY_TOO_LARGE;
+    }
+
+    max_body = ap_get_limit_req_body(r);
+    if (max_body && ((unsigned long)r->remaining > max_body)
+                 && (r->remaining >= 0)) {
+        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+          "Request content-length of %s is larger than the configured "
+          "limit of %lu", lenp, max_body);
+        return HTTP_REQUEST_ENTITY_TOO_LARGE;
+    }
+
+#ifdef CHARSET_EBCDIC
+    {
+        /* Determine the EBCDIC conversion for the uploaded content
+         * by looking at the Content-Type MIME header. 
+         * If no Content-Type header is found, text conversion is assumed.
+         */
+        ap_bsetflag(r->connection->client, B_ASCII2EBCDIC, ap_checkconv_in(r));
+    }
+#endif
+
+    return OK;
+}
+
+API_EXPORT(int) ap_should_client_block(request_rec *r)
+{
+    /* First check if we have already read the request body */
+
+    if (r->read_length || (!r->read_chunked && (r->remaining <= 0)))
+        return 0;
+
+    if (r->expecting_100 && r->proto_num >= HTTP_VERSION(1,1)) {
+        /* sending 100 Continue interim response */
+        ap_rvputs(r, SERVER_PROTOCOL, " ", status_lines[0], CRLF CRLF,
+                  NULL);
+        ap_rflush(r);
+    }
+
+    return 1;
+}
+
+/**
+ * Parse a chunk extension, detect overflow.
+ * There are two error cases:
+ *  1) If the conversion would require too many bits, a -1 is returned.
+ *  2) If the conversion used the correct number of bits, but an overflow
+ *     caused only the sign bit to flip, then that negative number is
+ *     returned.
+ * In general, any negative number can be considered an overflow error.
+ */
+API_EXPORT(long) ap_get_chunk_size(char *b)
+{
+    long chunksize = 0;
+    long chunkbits = sizeof(long) * 8;
+
+    /* Skip leading zeros */
+    while (*b == '0') {
+        ++b;
+    }
+
+    while (ap_isxdigit(*b) && (chunkbits > 0)) {
+        int xvalue = 0;
+
+        if (*b >= '0' && *b <= '9') {
+            xvalue = *b - '0';
+        }
+        else if (*b >= 'A' && *b <= 'F') {
+            xvalue = *b - 'A' + 0xa;
+        }
+        else if (*b >= 'a' && *b <= 'f') {
+            xvalue = *b - 'a' + 0xa;
+        }
+
+        chunksize = (chunksize << 4) | xvalue;
+        chunkbits -= 4;
+        ++b;
+    }
+    if (ap_isxdigit(*b) && (chunkbits <= 0)) {
+        /* overflow */
+        return -1;
+    }
+
+    return chunksize;
+}
+
+/* get_client_block is called in a loop to get the request message body.
+ * This is quite simple if the client includes a content-length
+ * (the normal case), but gets messy if the body is chunked. Note that
+ * r->remaining is used to maintain state across calls and that
+ * r->read_length is the total number of bytes given to the caller
+ * across all invocations.  It is messy because we have to be careful not
+ * to read past the data provided by the client, since these reads block.
+ * Returns 0 on End-of-body, -1 on error or premature chunk end.
+ *
+ * Reading the chunked encoding requires a buffer size large enough to
+ * hold a chunk-size line, including any extensions. For now, we'll leave
+ * that to the caller, at least until we can come up with a better solution.
+ */
+API_EXPORT(long) ap_get_client_block(request_rec *r, char *buffer, int bufsiz)
+{
+    int c;
+    long len_read, len_to_read;
+    long chunk_start = 0;
+    unsigned long max_body;
+
+    if (!r->read_chunked) {     /* Content-length read */
+        len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining;
+        len_read = ap_bread(r->connection->client, buffer, len_to_read);
+        if (len_read <= 0) {
+            if (len_read < 0)
+                r->connection->keepalive = -1;
+            return len_read;
+        }
+        r->read_length += len_read;
+        r->remaining -= len_read;
+        return len_read;
+    }
+
+    /*
+     * Handle chunked reading Note: we are careful to shorten the input
+     * bufsiz so that there will always be enough space for us to add a CRLF
+     * (if necessary).
+     */
+    if (r->read_body == REQUEST_CHUNKED_PASS)
+        bufsiz -= 2;
+    if (bufsiz <= 0)
+        return -1;              /* Cannot read chunked with a small buffer */
+
+    /* Check to see if we have already read too much request data.
+     * For efficiency reasons, we only check this at the top of each
+     * caller read pass, since the limit exists just to stop infinite
+     * length requests and nobody cares if it goes over by one buffer.
+     */
+    max_body = ap_get_limit_req_body(r);
+    if (max_body && ((unsigned long) r->read_length > max_body)
+                 && (r->read_length >= 0)) {
+        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+            "Chunked request body is larger than the configured limit of %lu",
+            max_body);
+        r->connection->keepalive = -1;
+        return -1;
+    }
+
+    if (r->remaining == 0) {    /* Start of new chunk */
+
+        chunk_start = ap_getline(buffer, bufsiz, r->connection->client, 0);
+        if ((chunk_start <= 0) || (chunk_start >= (bufsiz - 1))
+            || !ap_isxdigit(*buffer)) {
+            r->connection->keepalive = -1;
+            return -1;
+        }
+
+        len_to_read = ap_get_chunk_size(buffer);
+
+        if (len_to_read == 0) { /* Last chunk indicated, get footers */
+            if (r->read_body == REQUEST_CHUNKED_DECHUNK) {
+                get_mime_headers(r);
+                ap_snprintf(buffer, bufsiz, "%ld", r->read_length);
+                ap_table_unset(r->headers_in, "Transfer-Encoding");
+                ap_table_setn(r->headers_in, "Content-Length",
+                    ap_pstrdup(r->pool, buffer));
+                return 0;
+            }
+            r->remaining = -1;  /* Indicate footers in-progress */
+        }
+        else if (len_to_read < 0) {
+            r->connection->keepalive = -1;
+            return -1;
+        }
+        else {
+            r->remaining = len_to_read;
+        }
+        if (r->read_body == REQUEST_CHUNKED_PASS) {
+            buffer[chunk_start++] = CR; /* Restore chunk-size line end  */
+            buffer[chunk_start++] = LF;
+            buffer += chunk_start;      /* and pass line on to caller   */
+            bufsiz -= chunk_start;
+        }
+        else {
+            /* REQUEST_CHUNKED_DECHUNK -- do not include the length of the
+             * header in the return value
+             */
+            chunk_start = 0;
+        }
+    }
+                                /* When REQUEST_CHUNKED_PASS, we are */
+    if (r->remaining == -1) {   /* reading footers until empty line  */
+        len_read = chunk_start;
+
+        while ((bufsiz > 1) && ((len_read =
+                  ap_getline(buffer, bufsiz, r->connection->client, 1)) > 0)) {
+
+            if (len_read != (bufsiz - 1)) {
+                buffer[len_read++] = CR;        /* Restore footer line end  */
+                buffer[len_read++] = LF;
+            }
+            chunk_start += len_read;
+            buffer += len_read;
+            bufsiz -= len_read;
+        }
+        if (len_read < 0) {
+            r->connection->keepalive = -1;
+            return -1;
+        }
+
+        if (len_read == 0) {    /* Indicates an empty line */
+            buffer[0] = CR;
+            buffer[1] = LF;
+            chunk_start += 2;
+            r->remaining = -2;
+        }
+        r->read_length += chunk_start;
+        return chunk_start;
+    }
+                                /* When REQUEST_CHUNKED_PASS, we     */
+    if (r->remaining == -2) {   /* finished footers when last called */
+        r->remaining = 0;       /* so now we must signal EOF         */
+        return 0;
+    }
+
+    /* Otherwise, we are in the midst of reading a chunk of data */
+
+    len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining;
+
+    len_read = ap_bread(r->connection->client, buffer, len_to_read);
+    if (len_read <= 0) {
+        r->connection->keepalive = -1;
+        return -1;
+    }
+
+    r->remaining -= len_read;
+
+    if (r->remaining == 0) {    /* End of chunk, get trailing CRLF */
+#ifdef CHARSET_EBCDIC
+        /* Chunk end is Protocol stuff! Set conversion = 1 to read CR LF: */
+        PUSH_EBCDIC_INPUTCONVERSION_STATE_r(r, 1);
+#endif /*CHARSET_EBCDIC*/
+
+        if ((c = ap_bgetc(r->connection->client)) == CR) {
+            c = ap_bgetc(r->connection->client);
+        }
+
+#ifdef CHARSET_EBCDIC
+        /* restore ASCII->EBCDIC conversion state */
+        POP_EBCDIC_INPUTCONVERSION_STATE_r(r);
+#endif /*CHARSET_EBCDIC*/
+
+        if (c != LF) {
+            r->connection->keepalive = -1;
+            return -1;
+        }
+        if (r->read_body == REQUEST_CHUNKED_PASS) {
+            buffer[len_read++] = CR;
+            buffer[len_read++] = LF;
+        }
+    }
+    r->read_length += (chunk_start + len_read);
+
+    return (chunk_start + len_read);
+}
+
+/* In HTTP/1.1, any method can have a body.  However, most GET handlers
+ * wouldn't know what to do with a request body if they received one.
+ * This helper routine tests for and reads any message body in the request,
+ * simply discarding whatever it receives.  We need to do this because
+ * failing to read the request body would cause it to be interpreted
+ * as the next request on a persistent connection.
+ *
+ * Since we return an error status if the request is malformed, this
+ * routine should be called at the beginning of a no-body handler, e.g.,
+ *
+ *    if ((retval = ap_discard_request_body(r)) != OK)
+ *        return retval;
+ */
+API_EXPORT(int) ap_discard_request_body(request_rec *r)
+{
+    int rv;
+
+    if ((rv = ap_setup_client_block(r, REQUEST_CHUNKED_PASS)))
+        return rv;
+
+    /* In order to avoid sending 100 Continue when we already know the
+     * final response status, and yet not kill the connection if there is
+     * no request body to be read, we need to duplicate the test from
+     * ap_should_client_block() here negated rather than call it directly.
+     */
+    if ((r->read_length == 0) && (r->read_chunked || (r->remaining > 0))) {
+        char dumpbuf[HUGE_STRING_LEN];
+
+        if (r->expecting_100) {
+            r->connection->keepalive = -1;
+            return OK;
+        }
+        ap_hard_timeout("reading request body", r);
+        while ((rv = ap_get_client_block(r, dumpbuf, HUGE_STRING_LEN)) > 0)
+            continue;
+        ap_kill_timeout(r);
+
+        if (rv < 0)
+            return HTTP_BAD_REQUEST;
+    }
+    return OK;
+}
+
+/*
+ * Send the body of a response to the client.
+ */
+API_EXPORT(long) ap_send_fd(FILE *f, request_rec *r)
+{
+    return ap_send_fd_length(f, r, -1);
+}
+
+API_EXPORT(long) ap_send_fd_length(FILE *f, request_rec *r, long length)
+{
+    char buf[IOBUFSIZE];
+    long total_bytes_sent = 0;
+    register int n, w, o, len;
+
+    if (length == 0)
+        return 0;
+
+    ap_soft_timeout("send body", r);
+
+    while (!r->connection->aborted) {
+        if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length)
+            len = length - total_bytes_sent;
+        else
+            len = IOBUFSIZE;
+
+        while ((n = fread(buf, sizeof(char), len, f)) < 1
+               && ferror(f) && errno == EINTR && !r->connection->aborted)
+            continue;
+
+        if (n < 1) {
+            break;
+        }
+        o = 0;
+
+        while (n && !r->connection->aborted) {
+            w = ap_bwrite(r->connection->client, &buf[o], n);
+            if (w > 0) {
+                ap_reset_timeout(r); /* reset timeout after successful write */
+                total_bytes_sent += w;
+                n -= w;
+                o += w;
+            }
+            else if (w < 0) {
+                if (!r->connection->aborted) {
+                    ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
+                     "client stopped connection before send body completed");
+                    ap_bsetflag(r->connection->client, B_EOUT, 1);
+                    r->connection->aborted = 1;
+                }
+                break;
+            }
+        }
+    }
+
+    ap_kill_timeout(r);
+    SET_BYTES_SENT(r);
+    return total_bytes_sent;
+}
+
+/*
+ * Send the body of a response to the client.
+ */
+API_EXPORT(long) ap_send_fb(BUFF *fb, request_rec *r)
+{
+    return ap_send_fb_length(fb, r, -1);
+}
+
+API_EXPORT(long) ap_send_fb_length(BUFF *fb, request_rec *r, long length)
+{
+    char buf[IOBUFSIZE];
+    long total_bytes_sent = 0;
+    register int n, w, o, len, fd;
+    fd_set fds;
+#ifdef TPF_HAVE_NONSOCKET_SELECT
+    struct timeval tv;
+#endif 
+
+    if (length == 0)
+        return 0;
+
+    /* Make fb unbuffered and non-blocking */
+    ap_bsetflag(fb, B_RD, 0);
+#ifndef TPF_NO_NONSOCKET_SELECT
+    ap_bnonblock(fb, B_RD);
+#endif
+    fd = ap_bfileno(fb, B_RD);
+#ifdef CHECK_FD_SETSIZE
+    if (fd >= FD_SETSIZE) {
+	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
+	    "send body: filedescriptor (%u) larger than FD_SETSIZE (%u) "
+	    "found, you probably need to rebuild Apache with a "
+	    "larger FD_SETSIZE", fd, FD_SETSIZE);
+	return 0;
+    }
+#endif
+
+    ap_soft_timeout("send body", r);
+
+    FD_ZERO(&fds);
+    while (!r->connection->aborted) {
+#ifdef NDELAY_PIPE_RETURNS_ZERO
+	/* Contributed by dwd@bell-labs.com for UTS 2.1.2, where the fcntl */
+	/*   O_NDELAY flag causes read to return 0 when there's nothing */
+	/*   available when reading from a pipe.  That makes it tricky */
+	/*   to detect end-of-file :-(.  This stupid bug is even documented */
+	/*   in the read(2) man page where it says that everything but */
+	/*   pipes return -1 and EAGAIN.  That makes it a feature, right? */
+	int afterselect = 0;
+#endif
+        if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length)
+            len = length - total_bytes_sent;
+        else
+            len = IOBUFSIZE;
+
+        do {
+            n = ap_bread(fb, buf, len);
+#ifdef NDELAY_PIPE_RETURNS_ZERO
+	    if ((n > 0) || (n == 0 && afterselect))
+		break;
+#else
+            if (n >= 0)
+                break;
+#endif
+            if (r->connection->aborted)
+                break;
+            if (n < 0 && errno != EAGAIN)
+                break;
+
+            /* we need to block, so flush the output first */
+            if (ap_bflush(r->connection->client) < 0) {
+                ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
+                    "client stopped connection before send body completed");
+                ap_bsetflag(r->connection->client, B_EOUT, 1);
+                r->connection->aborted = 1;
+                break;
+            }
+            FD_SET(fd, &fds);
+            /*
+             * we don't care what select says, we might as well loop back
+             * around and try another read
+             */
+#ifdef TPF_HAVE_NONSOCKET_SELECT
+            tv.tv_sec =  1;
+            tv.tv_usec = 0;
+            ap_select(fd + 1, &fds, NULL, NULL, &tv);
+#else
+            ap_select(fd + 1, &fds, NULL, NULL, NULL);
+#endif  
+#ifdef NDELAY_PIPE_RETURNS_ZERO
+	    afterselect = 1;
+#endif
+        } while (!r->connection->aborted);
+
+        if (n < 1 || r->connection->aborted) {
+            break;
+        }
+        o = 0;
+
+        while (n && !r->connection->aborted) {
+            w = ap_bwrite(r->connection->client, &buf[o], n);
+            if (w > 0) {
+                ap_reset_timeout(r); /* reset timeout after successful write */
+                total_bytes_sent += w;
+                n -= w;
+                o += w;
+            }
+            else if (w < 0) {
+                if (!r->connection->aborted) {
+                    ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
+                       "client stopped connection before send body completed");
+                    ap_bsetflag(r->connection->client, B_EOUT, 1);
+                    r->connection->aborted = 1;
+                }
+                break;
+            }
+        }
+    }
+
+    ap_kill_timeout(r);
+    SET_BYTES_SENT(r);
+    return total_bytes_sent;
+}
+
+
+
+/* The code writes MMAP_SEGMENT_SIZE bytes at a time.  This is due to Apache's
+ * timeout model, which is a timeout per-write rather than a time for the
+ * entire transaction to complete.  Essentially this should be small enough
+ * so that in one Timeout period, your slowest clients should be reasonably
+ * able to receive this many bytes.
+ *
+ * To take advantage of zero-copy TCP under Solaris 2.6 this should be a
+ * multiple of 16k.  (And you need a SunATM2.0 network card.)
+ */
+#ifndef MMAP_SEGMENT_SIZE
+#define MMAP_SEGMENT_SIZE       32768
+#endif
+
+/* send data from an in-memory buffer */
+API_EXPORT(size_t) ap_send_mmap(void *mm, request_rec *r, size_t offset,
+                             size_t length)
+{
+    size_t total_bytes_sent = 0;
+    int n, w;
+
+    if (length == 0)
+        return 0;
+
+    ap_soft_timeout("send mmap", r);
+
+    length += offset;
+    while (!r->connection->aborted && offset < length) {
+        if (length - offset > MMAP_SEGMENT_SIZE) {
+            n = MMAP_SEGMENT_SIZE;
+        }
+        else {
+            n = length - offset;
+        }
+
+        while (n && !r->connection->aborted) {
+            w = ap_bwrite(r->connection->client, (char *) mm + offset, n);
+            if (w > 0) {
+                ap_reset_timeout(r); /* reset timeout after successful write */
+                total_bytes_sent += w;
+                n -= w;
+                offset += w;
+            }
+            else if (w < 0) {
+                if (!r->connection->aborted) {
+                    ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
+                       "client stopped connection before send mmap completed");
+                    ap_bsetflag(r->connection->client, B_EOUT, 1);
+                    r->connection->aborted = 1;
+                }
+                break;
+            }
+        }
+    }
+
+    ap_kill_timeout(r);
+    SET_BYTES_SENT(r);
+    return total_bytes_sent;
+}
+
+API_EXPORT(int) ap_rputc(int c, request_rec *r)
+{
+    if (r->connection->aborted)
+        return EOF;
+
+    if (ap_bputc(c, r->connection->client) < 0) {
+        if (!r->connection->aborted) {
+            ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
+                "client stopped connection before rputc completed");
+            ap_bsetflag(r->connection->client, B_EOUT, 1);
+            r->connection->aborted = 1;
+        }
+        return EOF;
+    }
+    SET_BYTES_SENT(r);
+    return c;
+}
+
+API_EXPORT(int) ap_rputs(const char *str, request_rec *r)
+{
+    int rcode;
+
+    if (r->connection->aborted)
+        return EOF;
+    
+    rcode = ap_bputs(str, r->connection->client);
+    if (rcode < 0) {
+        if (!r->connection->aborted) {
+            ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
+                "client stopped connection before rputs completed");
+            ap_bsetflag(r->connection->client, B_EOUT, 1);
+            r->connection->aborted = 1;
+        }
+        return EOF;
+    }
+    SET_BYTES_SENT(r);
+    return rcode;
+}
+
+API_EXPORT(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
+{
+    int n;
+
+    if (r->connection->aborted)
+        return -1;
+
+    n = ap_bwrite(r->connection->client, buf, nbyte);
+    if (n < 0) {
+        if (!r->connection->aborted) {
+            ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
+                "client stopped connection before rwrite completed");
+            ap_bsetflag(r->connection->client, B_EOUT, 1);
+            r->connection->aborted = 1;
+        }
+        return -1;
+    }
+    SET_BYTES_SENT(r);
+    return n;
+}
+
+API_EXPORT(int) ap_vrprintf(request_rec *r, const char *fmt, va_list ap)
+{
+    int n;
+
+    if (r->connection->aborted)
+        return -1;
+
+    n = ap_vbprintf(r->connection->client, fmt, ap);
+
+    if (n < 0) {
+        if (!r->connection->aborted) {
+            ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
+                "client stopped connection before vrprintf completed");
+            ap_bsetflag(r->connection->client, B_EOUT, 1);
+            r->connection->aborted = 1;
+        }
+        return -1;
+    }
+    SET_BYTES_SENT(r);
+    return n;
+}
+
+API_EXPORT_NONSTD(int) ap_rprintf(request_rec *r, const char *fmt,...)
+{
+    va_list vlist;
+    int n;
+
+    if (r->connection->aborted)
+        return -1;
+
+    va_start(vlist, fmt);
+    n = ap_vbprintf(r->connection->client, fmt, vlist);
+    va_end(vlist);
+
+    if (n < 0) {
+        if (!r->connection->aborted) {
+            ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
+                "client stopped connection before rprintf completed");
+            ap_bsetflag(r->connection->client, B_EOUT, 1);
+            r->connection->aborted = 1;
+        }
+        return -1;
+    }
+    SET_BYTES_SENT(r);
+    return n;
+}
+
+API_EXPORT_NONSTD(int) ap_rvputs(request_rec *r,...)
+{
+    va_list args;
+    int i, j, k;
+    const char *x;
+    BUFF *fb = r->connection->client;
+
+    if (r->connection->aborted)
+        return EOF;
+
+    va_start(args, r);
+    for (k = 0;;) {
+        x = va_arg(args, const char *);
+        if (x == NULL)
+            break;
+        j = strlen(x);
+        i = ap_bwrite(fb, x, j);
+        if (i != j) {
+            va_end(args);
+            if (!r->connection->aborted) {
+                ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
+                    "client stopped connection before rvputs completed");
+                ap_bsetflag(r->connection->client, B_EOUT, 1);
+                r->connection->aborted = 1;
+            }
+            return EOF;
+        }
+        k += i;
+    }
+    va_end(args);
+
+    SET_BYTES_SENT(r);
+    return k;
+}
+
+API_EXPORT(int) ap_rflush(request_rec *r)
+{
+    if (ap_bflush(r->connection->client) < 0) {
+        if (!r->connection->aborted) {
+            ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
+                "client stopped connection before rflush completed");
+            ap_bsetflag(r->connection->client, B_EOUT, 1);
+            r->connection->aborted = 1;
+        }
+        return EOF;
+    }
+    return 0;
+}
+
+/* We should have named this send_canned_response, since it is used for any
+ * response that can be generated by the server from the request record.
+ * This includes all 204 (no content), 3xx (redirect), 4xx (client error),
+ * and 5xx (server error) messages that have not been redirected to another
+ * handler via the ErrorDocument feature.
+ */
+API_EXPORT(void) ap_send_error_response(request_rec *r, int recursive_error)
+{
+    int status = r->status;
+    int idx = ap_index_of_response(status);
+    char *custom_response;
+    const char *location = ap_table_get(r->headers_out, "Location");
+#ifdef CHARSET_EBCDIC
+    /* Error Responses (builtin / string literal / redirection) are TEXT! */
+    ap_bsetflag(r->connection->client, B_EBCDIC2ASCII, r->ebcdic.conv_out = 1);
+#endif
+
+    /*
+     * It's possible that the Location field might be in r->err_headers_out
+     * instead of r->headers_out; use the latter if possible, else the
+     * former.
+     */
+    if (location == NULL) {
+	location = ap_table_get(r->err_headers_out, "Location");
+    }
+    /* We need to special-case the handling of 204 and 304 responses,
+     * since they have specific HTTP requirements and do not include a
+     * message body.  Note that being assbackwards here is not an option.
+     */
+    if (status == HTTP_NOT_MODIFIED) {
+        if (!ap_is_empty_table(r->err_headers_out))
+            r->headers_out = ap_overlay_tables(r->pool, r->err_headers_out,
+                                               r->headers_out);
+        ap_hard_timeout("send 304", r);
+
+        ap_basic_http_header(r);
+        ap_set_keepalive(r);
+
+        ap_table_do((int (*)(void *, const char *, const char *)) ap_send_header_field,
+                    (void *) r, r->headers_out,
+                    "Connection",
+                    "Keep-Alive",
+                    "ETag",
+                    "Content-Location",
+                    "Expires",
+                    "Cache-Control",
+                    "Vary",
+                    "Warning",
+                    "WWW-Authenticate",
+                    "Proxy-Authenticate",
+                    NULL);
+
+        terminate_header(r->connection->client);
+
+        ap_kill_timeout(r);
+        return;
+    }
+
+    if (status == HTTP_NO_CONTENT) {
+        ap_send_http_header(r);
+        ap_finalize_request_protocol(r);
+        return;
+    }
+
+    if (!r->assbackwards) {
+        table *tmp = r->headers_out;
+
+        /* For all HTTP/1.x responses for which we generate the message,
+         * we need to avoid inheriting the "normal status" header fields
+         * that may have been set by the request handler before the
+         * error or redirect, except for Location on external redirects.
+         */
+        r->headers_out = r->err_headers_out;
+        r->err_headers_out = tmp;
+        ap_clear_table(r->err_headers_out);
+
+        if (ap_is_HTTP_REDIRECT(status) || (status == HTTP_CREATED)) {
+            if ((location != NULL) && *location) {
+	        ap_table_setn(r->headers_out, "Location", location);
+            }
+            else {
+                location = "";   /* avoids coredump when printing, below */
+            }
+        }
+
+        r->content_language = NULL;
+        r->content_languages = NULL;
+        r->content_encoding = NULL;
+        r->clength = 0;
+        if (ap_table_get(r->subprocess_env,
+                         "suppress-error-charset") != NULL) {
+            r->content_type = "text/html";
+        }
+        else {
+            r->content_type = "text/html; charset=iso-8859-1";
+        }
+
+        if ((status == METHOD_NOT_ALLOWED) || (status == NOT_IMPLEMENTED))
+            ap_table_setn(r->headers_out, "Allow", make_allow(r));
+
+        ap_send_http_header(r);
+
+        if (r->header_only) {
+            ap_finalize_request_protocol(r);
+            ap_rflush(r);
+            return;
+        }
+    }
+
+#ifdef CHARSET_EBCDIC
+    /* Server-generated response, converted */
+    ap_bsetflag(r->connection->client, B_EBCDIC2ASCII, r->ebcdic.conv_out = 1);
+#endif
+
+    ap_hard_timeout("send error body", r);
+
+    if ((custom_response = ap_response_code_string(r, idx))) {
+        /*
+         * We have a custom response output. This should only be
+         * a text-string to write back. But if the ErrorDocument
+         * was a local redirect and the requested resource failed
+         * for any reason, the custom_response will still hold the
+         * redirect URL. We don't really want to output this URL
+         * as a text message, so first check the custom response
+         * string to ensure that it is a text-string (using the
+         * same test used in ap_die(), i.e. does it start with a ").
+         * If it doesn't, we've got a recursive error, so find
+         * the original error and output that as well.
+         */
+        if (custom_response[0] == '\"') {
+            ap_rputs(custom_response + 1, r);
+            ap_kill_timeout(r);
+            ap_finalize_request_protocol(r);
+            ap_rflush(r);
+            return;
+        }
+        /*
+         * Redirect failed, so get back the original error
+         */
+        while (r->prev && (r->prev->status != HTTP_OK))
+            r = r->prev;
+    }
+    {
+        const char *title = status_lines[idx];
+        const char *h1;
+        const char *error_notes;
+
+        /* Accept a status_line set by a module, but only if it begins
+         * with the 3 digit status code
+         */
+        if (r->status_line != NULL
+            && strlen(r->status_line) > 4       /* long enough */
+            && ap_isdigit(r->status_line[0])
+            && ap_isdigit(r->status_line[1])
+            && ap_isdigit(r->status_line[2])
+            && ap_isspace(r->status_line[3])
+            && ap_isalnum(r->status_line[4])) {
+            title = r->status_line;
+        }
+
+        /* folks decided they didn't want the error code in the H1 text */
+        h1 = &title[4];
+
+        ap_rvputs(r,
+                  DOCTYPE_HTML_2_0
+                  "<HTML><HEAD>\n<TITLE>", title,
+                  "</TITLE>\n</HEAD><BODY>\n<H1>", h1, "</H1>\n",
+                  NULL);
+
+	switch (status) {
+	case HTTP_MOVED_PERMANENTLY:
+	case HTTP_MOVED_TEMPORARILY:
+	case HTTP_TEMPORARY_REDIRECT:
+	    ap_rvputs(r, "The document has moved <A HREF=\"",
+		      ap_escape_html(r->pool, location), "\">here</A>.<P>\n",
+		      NULL);
+	    break;
+	case HTTP_SEE_OTHER:
+	    ap_rvputs(r, "The answer to your request is located <A HREF=\"",
+		      ap_escape_html(r->pool, location), "\">here</A>.<P>\n",
+		      NULL);
+	    break;
+	case HTTP_USE_PROXY:
+	    ap_rvputs(r, "This resource is only accessible "
+		      "through the proxy\n",
+		      ap_escape_html(r->pool, location),
+		      "<BR>\nYou will need to ",
+		      "configure your client to use that proxy.<P>\n", NULL);
+	    break;
+	case HTTP_PROXY_AUTHENTICATION_REQUIRED:
+	case AUTH_REQUIRED:
+	    ap_rputs("This server could not verify that you\n"
+	             "are authorized to access the document\n"
+	             "requested.  Either you supplied the wrong\n"
+	             "credentials (e.g., bad password), or your\n"
+	             "browser doesn't understand how to supply\n"
+	             "the credentials required.<P>\n", r);
+	    break;
+	case BAD_REQUEST:
+	    ap_rputs("Your browser sent a request that "
+	             "this server could not understand.<P>\n", r);
+	    if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
+		ap_rvputs(r, error_notes, "<P>\n", NULL);
+	    }
+	    break;
+	case HTTP_FORBIDDEN:
+	    ap_rvputs(r, "You don't have permission to access ",
+		      ap_escape_html(r->pool, r->uri),
+		      "\non this server.<P>\n", NULL);
+	    break;
+	case NOT_FOUND:
+	    ap_rvputs(r, "The requested URL ",
+		      ap_escape_html(r->pool, r->uri),
+		      " was not found on this server.<P>\n", NULL);
+	    break;
+	case METHOD_NOT_ALLOWED:
+	    ap_rvputs(r, "The requested method ", r->method,
+		      " is not allowed "
+		      "for the URL ", ap_escape_html(r->pool, r->uri),
+		      ".<P>\n", NULL);
+	    break;
+	case NOT_ACCEPTABLE:
+	    ap_rvputs(r,
+		      "An appropriate representation of the "
+		      "requested resource ",
+		      ap_escape_html(r->pool, r->uri),
+		      " could not be found on this server.<P>\n", NULL);
+	    /* fall through */
+	case MULTIPLE_CHOICES:
+	    {
+		const char *list;
+		if ((list = ap_table_get(r->notes, "variant-list")))
+		    ap_rputs(list, r);
+	    }
+	    break;
+	case LENGTH_REQUIRED:
+	    ap_rvputs(r, "A request of the requested method ", r->method,
+		      " requires a valid Content-length.<P>\n", NULL);
+	    if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
+		ap_rvputs(r, error_notes, "<P>\n", NULL);
+	    }
+	    break;
+	case PRECONDITION_FAILED:
+	    ap_rvputs(r, "The precondition on the request for the URL ",
+		      ap_escape_html(r->pool, r->uri),
+		      " evaluated to false.<P>\n", NULL);
+	    break;
+	case HTTP_NOT_IMPLEMENTED:
+	    ap_rvputs(r, ap_escape_html(r->pool, r->method), " to ",
+		      ap_escape_html(r->pool, r->uri),
+		      " not supported.<P>\n", NULL);
+	    if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
+		ap_rvputs(r, error_notes, "<P>\n", NULL);
+	    }
+	    break;
+	case BAD_GATEWAY:
+	    ap_rputs("The proxy server received an invalid" CRLF
+	             "response from an upstream server.<P>" CRLF, r);
+	    if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
+		ap_rvputs(r, error_notes, "<P>\n", NULL);
+	    }
+	    break;
+	case VARIANT_ALSO_VARIES:
+	    ap_rvputs(r, "A variant for the requested resource\n<PRE>\n",
+		      ap_escape_html(r->pool, r->uri),
+		      "\n</PRE>\nis itself a negotiable resource. "
+		      "This indicates a configuration error.<P>\n", NULL);
+	    break;
+	case HTTP_REQUEST_TIME_OUT:
+	    ap_rputs("Server timeout waiting for the HTTP request from the client.\n", r);
+	    break;
+	case HTTP_GONE:
+	    ap_rvputs(r, "The requested resource<BR>",
+		      ap_escape_html(r->pool, r->uri),
+		      "<BR>\nis no longer available on this server ",
+		      "and there is no forwarding address.\n",
+		      "Please remove all references to this resource.\n",
+		      NULL);
+	    break;
+	case HTTP_REQUEST_ENTITY_TOO_LARGE:
+	    ap_rvputs(r, "The requested resource<BR>",
+		      ap_escape_html(r->pool, r->uri), "<BR>\n",
+		      "does not allow request data with ", r->method,
+		      " requests, or the amount of data provided in\n",
+		      "the request exceeds the capacity limit.\n", NULL);
+	    break;
+	case HTTP_REQUEST_URI_TOO_LARGE:
+	    ap_rputs("The requested URL's length exceeds the capacity\n"
+	             "limit for this server.<P>\n", r);
+	    if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
+		ap_rvputs(r, error_notes, "<P>\n", NULL);
+	    }
+	    break;
+	case HTTP_UNSUPPORTED_MEDIA_TYPE:
+	    ap_rputs("The supplied request data is not in a format\n"
+	             "acceptable for processing by this resource.\n", r);
+	    break;
+	case HTTP_RANGE_NOT_SATISFIABLE:
+	    ap_rputs("None of the range-specifier values in the Range\n"
+	             "request-header field overlap the current extent\n"
+	             "of the selected resource.\n", r);
+	    break;
+	case HTTP_EXPECTATION_FAILED:
+	    ap_rvputs(r, "The expectation given in the Expect request-header"
+	              "\nfield could not be met by this server.<P>\n"
+	              "The client sent<PRE>\n    Expect: ",
+	              ap_table_get(r->headers_in, "Expect"), "\n</PRE>\n"
+	              "but we only allow the 100-continue expectation.\n",
+	              NULL);
+	    break;
+	case HTTP_UNPROCESSABLE_ENTITY:
+	    ap_rputs("The server understands the media type of the\n"
+	             "request entity, but was unable to process the\n"
+	             "contained instructions.\n", r);
+	    break;
+	case HTTP_LOCKED:
+	    ap_rputs("The requested resource is currently locked.\n"
+	             "The lock must be released or proper identification\n"
+	             "given before the method can be applied.\n", r);
+	    break;
+	case HTTP_FAILED_DEPENDENCY:
+	    ap_rputs("The method could not be performed on the resource\n"
+	             "because the requested action depended on another\n"
+	             "action and that other action failed.\n", r);
+	    break;
+	case HTTP_INSUFFICIENT_STORAGE:
+	    ap_rputs("The method could not be performed on the resource\n"
+	             "because the server is unable to store the\n"
+	             "representation needed to successfully complete the\n"
+	             "request.  There is insufficient free space left in\n"
+	             "your storage allocation.\n", r);
+	    break;
+	case HTTP_SERVICE_UNAVAILABLE:
+	    ap_rputs("The server is temporarily unable to service your\n"
+	             "request due to maintenance downtime or capacity\n"
+	             "problems. Please try again later.\n", r);
+	    break;
+	case HTTP_GATEWAY_TIME_OUT:
+	    ap_rputs("The proxy server did not receive a timely response\n"
+	             "from the upstream server.\n", r);
+	    break;
+	case HTTP_NOT_EXTENDED:
+	    ap_rputs("A mandatory extension policy in the request is not\n"
+	             "accepted by the server for this resource.\n", r);
+	    break;
+	default:            /* HTTP_INTERNAL_SERVER_ERROR */
+	    /*
+	     * This comparison to expose error-notes could be modified to
+	     * use a configuration directive and export based on that 
+	     * directive.  For now "*" is used to designate an error-notes
+	     * that is totally safe for any user to see (ie lacks paths,
+	     * database passwords, etc.)
+	     */
+	    if (((error_notes = ap_table_get(r->notes, "error-notes")) != NULL)
+		&& (h1 = ap_table_get(r->notes, "verbose-error-to")) != NULL
+		&& (strcmp(h1, "*") == 0)) {
+	        ap_rvputs(r, error_notes, "<P>\n", NULL);
+	    }
+	    else {
+	        ap_rvputs(r, "The server encountered an internal error or\n"
+	             "misconfiguration and was unable to complete\n"
+	             "your request.<P>\n"
+	             "Please contact the server administrator,\n ",
+	             ap_escape_html(r->pool, r->server->server_admin),
+	             " and inform them of the time the error occurred,\n"
+	             "and anything you might have done that may have\n"
+	             "caused the error.<P>\n"
+		     "More information about this error may be available\n"
+		     "in the server error log.<P>\n", NULL);
+	    }
+	 /*
+	  * It would be nice to give the user the information they need to
+	  * fix the problem directly since many users don't have access to
+	  * the error_log (think University sites) even though they can easily
+	  * get this error by misconfiguring an htaccess file.  However, the
+	  * error notes tend to include the real file pathname in this case,
+	  * which some people consider to be a breach of privacy.  Until we
+	  * can figure out a way to remove the pathname, leave this commented.
+	  *
+	  * if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
+	  *     ap_rvputs(r, error_notes, "<P>\n", NULL);
+	  * }
+	  */
+	    break;
+	}
+
+        if (recursive_error) {
+            ap_rvputs(r, "<P>Additionally, a ",
+                      status_lines[ap_index_of_response(recursive_error)],
+                      "\nerror was encountered while trying to use an "
+                      "ErrorDocument to handle the request.\n", NULL);
+        }
+        ap_rputs(ap_psignature("<HR>\n", r), r);
+        ap_rputs("</BODY></HTML>\n", r);
+    }
+    ap_kill_timeout(r);
+    ap_finalize_request_protocol(r);
+    ap_rflush(r);
+}
