]> granicus.if.org Git - apache/blobdiff - server/core.c
switch to APR 1.0 API (which is still in flux)
[apache] / server / core.c
index bff8cb4ad2fef4f6d11143cf1453543f231faa73..e5f5ef0da71d35a41adfe46d7b753d775f9d4ba2 100644 (file)
@@ -1,7 +1,7 @@
 /* ====================================================================
  * The Apache Software License, Version 1.1
  *
- * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
+ * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
  * reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -79,7 +79,6 @@
 #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 "http_connection.h"
 #include "apr_buckets.h"
@@ -144,7 +143,6 @@ static void *create_core_dir_config(apr_pool_t *a, char *dir)
     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
@@ -181,6 +179,8 @@ static void *create_core_dir_config(apr_pool_t *a, char *dir)
     conf->etag_remove = ETAG_UNSET;
 
     conf->enable_mmap = ENABLE_MMAP_UNSET;
+    conf->enable_sendfile = ENABLE_SENDFILE_UNSET;
+    conf->allow_encoded_slashes = 0;
 
     return (void *)conf;
 }
@@ -322,10 +322,6 @@ static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv)
         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;
     }
@@ -447,6 +443,12 @@ static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv)
         conf->enable_mmap = new->enable_mmap;
     }
 
+    if (new->enable_sendfile != ENABLE_SENDFILE_UNSET) {
+        conf->enable_sendfile = new->enable_sendfile;
+    }
+
+    conf->allow_encoded_slashes = new->allow_encoded_slashes;
+    
     return (void*)conf;
 }
 
@@ -466,6 +468,10 @@ static void *create_core_server_config(apr_pool_t *a, server_rec *s)
     conf->sec_dir = apr_array_make(a, 40, sizeof(ap_conf_vector_t *));
     conf->sec_url = apr_array_make(a, 40, sizeof(ap_conf_vector_t *));
 
+    /* recursion stopper */
+    conf->redirect_limit = 0; /* 0 == unset */
+    conf->subreq_limit = 0;
+
     return (void *)conf;
 }
 
@@ -489,6 +495,14 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
     conf->sec_dir = apr_array_append(p, base->sec_dir, virt->sec_dir);
     conf->sec_url = apr_array_append(p, base->sec_url, virt->sec_url);
 
+    conf->redirect_limit = virt->redirect_limit
+                           ? virt->redirect_limit
+                           : base->redirect_limit;
+
+    conf->subreq_limit = virt->subreq_limit
+                         ? virt->subreq_limit
+                         : base->subreq_limit;
+
     return conf;
 }
 
@@ -822,24 +836,22 @@ AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config,
     }
 }
 
+/*
+ * Optional function coming from mod_ident, used for looking up ident user
+ */
+static APR_OPTIONAL_FN_TYPE(ap_ident_lookup) *ident_lookup;
+
 AP_DECLARE(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;
+    if (ident_lookup) {
+        return ident_lookup(r);
     }
+
+    return NULL;
 }
 
 /* There are two options regarding what the "name" of a server is.  The
@@ -885,6 +897,23 @@ AP_DECLARE(const char *) ap_get_server_name(request_rec *r)
     return r->server->server_hostname;
 }
 
+/*
+ * Get the current server name from the request for the purposes
+ * of using in a URL.  If the server name is an IPv6 literal
+ * address, it will be returned in URL format (e.g., "[fe80::1]").
+ */
+static const char *get_server_name_for_url(request_rec *r)
+{
+    const char *plain_server_name = ap_get_server_name(r);
+
+#if APR_HAVE_IPV6
+    if (ap_strchr_c(plain_server_name, ':')) { /* IPv6 literal? */
+        return apr_psprintf(r->pool, "[%s]", plain_server_name);
+    }
+#endif
+    return plain_server_name;
+}
+
 AP_DECLARE(apr_port_t) ap_get_server_port(const request_rec *r)
 {
     apr_port_t port;
@@ -925,7 +954,7 @@ AP_DECLARE(char *) ap_construct_url(apr_pool_t *p, const char *uri,
                                     request_rec *r)
 {
     unsigned port = ap_get_server_port(r);
-    const char *host = ap_get_server_name(r);
+    const char *host = get_server_name_for_url(r);
 
     if (ap_is_default_port(port, r)) {
         return apr_pstrcat(p, ap_http_method(r), "://", host, uri, NULL);
@@ -1084,8 +1113,10 @@ static const char *set_document_root(cmd_parms *cmd, void *dummy,
         return err;
     }
 
+    /* Make it absolute, relative to ServerRoot */
+    arg = ap_server_root_relative(cmd->pool, arg);
+
     /* TODO: ap_configtestonly && ap_docrootcheck && */
-    /* XXX Shouldn't this be relative to ServerRoot ??? */
     if (apr_filepath_merge((char**)&conf->ap_document_root, NULL, arg,
                            APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS
         || !ap_is_directory(cmd->pool, arg)) {
@@ -1196,6 +1227,13 @@ static const char *set_override(cmd_parms *cmd, void *d_, const char *l)
         return err;
     }
 
+    /* Throw a warning if we're in <Location> or <Files> */
+    if (ap_check_cmd_context(cmd, NOT_IN_LOCATION | NOT_IN_FILES)) {
+        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
+                     "Useless use of AllowOverride in line %d.",
+                     cmd->directive->line_num);
+    }
+
     d->override = OR_NONE;
     while (l[0]) {
         w = ap_getword_conf(cmd->pool, &l);
@@ -1458,6 +1496,29 @@ static const char *set_enable_mmap(cmd_parms *cmd, void *d_,
     return NULL;
 }
 
+static const char *set_enable_sendfile(cmd_parms *cmd, void *d_,
+                                   const char *arg)
+{
+    core_dir_config *d = d_;
+    const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
+
+    if (err != NULL) {
+        return err;
+    }
+
+    if (strcasecmp(arg, "on") == 0) {
+        d->enable_sendfile = ENABLE_SENDFILE_ON;
+    }
+    else if (strcasecmp(arg, "off") == 0) {
+        d->enable_sendfile = ENABLE_SENDFILE_OFF;
+    }
+    else {
+        return "parameter must be 'on' or 'off'";
+    }
+
+    return NULL;
+}
+
 static const char *satisfy(cmd_parms *cmd, void *c_, const char *arg)
 {
     core_dir_config *c = c_;
@@ -1607,8 +1668,9 @@ static const char *dirsection(cmd_parms *cmd, void *mconfig, const char *arg)
         /*
          * Ensure that the pathname is canonical, and append the trailing /
          */
-        if (apr_filepath_merge(&newpath, NULL, cmd->path,
-                               APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS) {
+        apr_status_t rv = apr_filepath_merge(&newpath, NULL, cmd->path,
+                                             APR_FILEPATH_TRUENAME, cmd->pool);
+        if (rv != APR_SUCCESS && rv != APR_EPATHWILD) {
             return apr_pstrcat(cmd->pool, "<Directory \"", cmd->path,
                                "\"> path is invalid.", NULL);
         }
@@ -2045,7 +2107,7 @@ static const char *set_timeout(cmd_parms *cmd, void *dummy, const char *arg)
     return NULL;
 }
 
-static const char *set_idcheck(cmd_parms *cmd, void *d_, int arg)
+static const char *set_allow2f(cmd_parms *cmd, void *d_, int arg)
 {
     core_dir_config *d = d_;
     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
@@ -2054,7 +2116,7 @@ static const char *set_idcheck(cmd_parms *cmd, void *d_, int arg)
         return err;
     }
 
-    d->do_rfc1413 = arg != 0;
+    d->allow_encoded_slashes = arg != 0;
     return NULL;
 }
 
@@ -2163,7 +2225,7 @@ static const char *include_config (cmd_parms *cmd, void *dummy,
 {
     ap_directive_t *conftree = NULL;
     const char* conffile = ap_server_root_relative(cmd->pool, name);
-    
+
     if (!conffile) {
         return apr_pstrcat(cmd->pool, "Invalid Include path ", 
                            name, NULL);
@@ -2237,15 +2299,19 @@ AP_DECLARE(const char *) ap_psignature(const char *prefix, request_rec *r)
     apr_snprintf(sport, sizeof sport, "%u", (unsigned) ap_get_server_port(r));
 
     if (conf->server_signature == srv_sig_withmail) {
-        return apr_pstrcat(r->pool, prefix, "<address>" AP_SERVER_BASEVERSION
+        return apr_pstrcat(r->pool, prefix, "<address>", 
+                           ap_get_server_version(),
                            " Server at <a href=\"mailto:",
                            r->server->server_admin, "\">",
-                           ap_get_server_name(r), "</a> Port ", sport,
+                           ap_escape_html(r->pool, ap_get_server_name(r)),
+                           "</a> Port ", sport,
                            "</address>\n", NULL);
     }
 
-    return apr_pstrcat(r->pool, prefix, "<address>" AP_SERVER_BASEVERSION
-                       " Server at ", ap_get_server_name(r), " Port ", sport,
+    return apr_pstrcat(r->pool, prefix, "<address>", ap_get_server_version(),
+                       " Server at ",
+                       ap_escape_html(r->pool, ap_get_server_name(r)),
+                       " Port ", sport,
                        "</address>\n", NULL);
 }
 
@@ -2262,18 +2328,6 @@ static const char *set_authname(cmd_parms *cmd, void *mconfig,
     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*/
-
 /*
  * Handle a request to include the server's OS platform in the Server
  * response header field (the ServerTokens directive).  Unfortunately
@@ -2286,9 +2340,11 @@ static char *server_version = NULL;
 static int version_locked = 0;
 
 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_MAJOR,        /* eg: Apache/2 */
+    SrvTk_MINOR,        /* eg. Apache/2.0 */
+    SrvTk_MINIMAL,      /* eg: Apache/2.0.41 */
+    SrvTk_OS,           /* eg: Apache/2.0.41 (UNIX) */
+    SrvTk_FULL,         /* eg: Apache/2.0.41 (UNIX) PHP/4.2.2 FooBar/1.2b */
     SrvTk_PRODUCT_ONLY  /* eg: Apache */
 };
 static enum server_token_type ap_server_tokens = SrvTk_FULL;
@@ -2339,9 +2395,15 @@ static void ap_set_version(apr_pool_t *pconf)
     if (ap_server_tokens == SrvTk_PRODUCT_ONLY) {
         ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT);
     }
-    else if (ap_server_tokens == SrvTk_MIN) {
+    else if (ap_server_tokens == SrvTk_MINIMAL) {
         ap_add_version_component(pconf, AP_SERVER_BASEVERSION);
     }
+    else if (ap_server_tokens == SrvTk_MINOR) {
+        ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MINORREVISION);
+    }
+    else if (ap_server_tokens == SrvTk_MAJOR) {
+        ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MAJORVERSION);
+    }
     else {
         ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ")");
     }
@@ -2368,7 +2430,13 @@ static const char *set_serv_tokens(cmd_parms *cmd, void *dummy,
         ap_server_tokens = SrvTk_OS;
     }
     else if (!strcasecmp(arg, "Min") || !strcasecmp(arg, "Minimal")) {
-        ap_server_tokens = SrvTk_MIN;
+        ap_server_tokens = SrvTk_MINIMAL;
+    }
+    else if (!strcasecmp(arg, "Major")) {
+        ap_server_tokens = SrvTk_MAJOR;
+    }
+    else if (!strcasecmp(arg, "Minor") ) {
+        ap_server_tokens = SrvTk_MINOR;
     }
     else if (!strcasecmp(arg, "Prod") || !strcasecmp(arg, "ProductOnly")) {
         ap_server_tokens = SrvTk_PRODUCT_ONLY;
@@ -2559,11 +2627,135 @@ static const char *set_limit_nproc(cmd_parms *cmd, void *conf_,
 }
 #endif
 
+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 recursion limit must be greater than zero.";
+    }
+    if (limit < 4) {
+        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, 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 recursion limit must be greater than zero.";
+        }
+        if (limit < 4) {
+            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
+                         "Limiting the subrequest depth to a very low level may"
+                         " cause normal requests to fail.");
+        }
+    }
+
+    conf->subreq_limit = limit;
+
+    return NULL;
+}
+
+static void log_backtrace(const request_rec *r)
+{
+    const request_rec *top = r;
+
+    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, 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, 0, 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, 0, r,
+                          "subrequested from r->uri = %s",
+                          top->uri ? top->uri : "(unexpectedly NULL)");
+        }
+    }
+}
+
+/*
+ * check whether redirect limit is reached
+ */
+AP_DECLARE(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->redirect_limit
+                 ? conf->redirect_limit
+                 : AP_DEFAULT_MAX_INTERNAL_REDIRECTS;
+    int slimit = conf->subreq_limit
+                 ? conf->subreq_limit
+                 : AP_DEFAULT_MAX_SUBREQ_DEPTH;
+
+
+    while (top->prev || top->main) {
+        if (top->prev) {
+            if (++redirects >= rlimit) {
+                /* uuh, too much. */
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, 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 (++subreqs >= slimit) {
+                /* uuh, too much. */
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, 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;
+}
+
 static const char *add_ct_output_filters(cmd_parms *cmd, void *conf_,
                                          const char *arg, const char *arg2)
 {
     core_dir_config *conf = conf_;
-    ap_filter_rec_t *old, *new;
+    ap_filter_rec_t *old, *new = NULL;
+    const char *filter_name;
 
     if (!conf->ct_output_filters) {
         conf->ct_output_filters = apr_hash_make(cmd->pool);
@@ -2572,30 +2764,47 @@ static const char *add_ct_output_filters(cmd_parms *cmd, void *conf_,
     else {
         old = (ap_filter_rec_t*) apr_hash_get(conf->ct_output_filters, arg2,
                                               APR_HASH_KEY_STRING);
+        /* find last entry */
+        if (old) {
+            while (old->next) {
+                old = old->next;
+            }
+        }
     }
 
-    new = apr_pcalloc(cmd->pool, sizeof(ap_filter_rec_t));
-    new->name = apr_pstrdup(cmd->pool, arg);
+    while (*arg &&
+           (filter_name = ap_getword(cmd->pool, &arg, ';')) &&
+           strcmp(filter_name, "")) {
+        new = apr_pcalloc(cmd->pool, sizeof(ap_filter_rec_t));
+        new->name = filter_name;
 
-    /* We found something, so let's append it.  */
-    if (old) {
-        new->next = old;
+        /* We found something, so let's append it.  */
+        if (old) {
+            old->next = new;
+        }
+        else {
+            apr_hash_set(conf->ct_output_filters, arg2,
+                         APR_HASH_KEY_STRING, new);
+        }
+        old = new;
     }
 
-    apr_hash_set(conf->ct_output_filters, arg2, APR_HASH_KEY_STRING, new);
-
+    if (!new) {
+        return "invalid filter name";
+    }
+    
     return NULL;
 }
 /* 
- * Insert filters requested by the AddOutputFiltersByType 
+ * Insert filters requested by the AddOutputFilterByType 
  * configuration directive. We cannot add filters based 
  * on content-type until after the handler has started 
- * to run. Only then do we reliabily know the content-type.
+ * to run. Only then do we reliably know the content-type.
  */
 void ap_add_output_filters_by_type(request_rec *r)
 {
     core_dir_config *conf;
-    const char *ctype, *ctypes;
+    const char *ctype;
 
     conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
                                                    &core_module);
@@ -2608,10 +2817,9 @@ void ap_add_output_filters_by_type(request_rec *r)
         return;
     }
 
-    ctypes = r->content_type;
-
-    /* We must be able to handle decorated content-types.  */
-    while (*ctypes && (ctype = ap_getword(r->pool, &ctypes, ';'))) {
+    /* remove c-t decoration */
+    ctype = ap_field_noparam(r->pool, r->content_type);
+    if (ctype) {
         ap_filter_rec_t *ct_filter;
         ct_filter = apr_hash_get(conf->ct_output_filters, ctype,
                                  APR_HASH_KEY_STRING);
@@ -2637,7 +2845,7 @@ static apr_status_t writev_it_all(apr_socket_t *s,
 
     /* XXX handle checking for non-blocking socket */
     while (bytes_written != len) {
-        rv = apr_sendv(s, vec + i, nvec - i, &n);
+        rv = apr_socket_sendv(s, vec + i, nvec - i, &n);
         bytes_written += n;
         if (rv != APR_SUCCESS)
             return rv;
@@ -2645,7 +2853,7 @@ static apr_status_t writev_it_all(apr_socket_t *s,
         *nbytes += n;
 
         /* If the write did not complete, adjust the iovecs and issue
-         * apr_sendv again
+         * apr_socket_sendv again
          */
         if (bytes_written < len) {
             /* Skip over the vectors that have already been written */
@@ -2682,22 +2890,27 @@ static apr_status_t sendfile_it_all(core_net_rec *c,
                                     apr_off_t   file_offset,
                                     apr_size_t  file_bytes_left,
                                     apr_size_t  total_bytes_left,
+                                    apr_size_t  *bytes_sent,
                                     apr_int32_t flags)
 {
     apr_status_t rv;
 #ifdef AP_DEBUG
-    apr_int32_t timeout = 0;
+    apr_interval_time_t timeout = 0;
 #endif
 
-    AP_DEBUG_ASSERT((apr_getsocketopt(c->client_socket, APR_SO_TIMEOUT,
-                                      &timeout) == APR_SUCCESS)
+    AP_DEBUG_ASSERT((apr_socket_timeout_get(c->client_socket, &timeout) 
+                         == APR_SUCCESS)
                     && timeout > 0);  /* socket must be in timeout mode */
 
+    /* Reset the bytes_sent field */
+    *bytes_sent = 0;
+
     do {
         apr_size_t tmplen = file_bytes_left;
 
-        rv = apr_sendfile(c->client_socket, fd, hdtr, &file_offset, &tmplen,
-                          flags);
+        rv = apr_socket_sendfile(c->client_socket, fd, hdtr, &file_offset, &tmplen,
+                                 flags);
+        *bytes_sent += tmplen;
         total_bytes_left -= tmplen;
         if (!total_bytes_left || rv != APR_SUCCESS) {
             return rv;        /* normal case & error exit */
@@ -2806,7 +3019,7 @@ static apr_status_t emulate_sendfile(core_net_rec *c, apr_file_t *fd,
         rv = apr_file_read(fd, buffer, &sendlen);
         while (rv == APR_SUCCESS && sendlen) {
             bytes_sent = sendlen;
-            rv = apr_send(c->client_socket, &buffer[o], &bytes_sent);
+            rv = apr_socket_send(c->client_socket, &buffer[o], &bytes_sent);
             if (rv == APR_SUCCESS) {
                 sendlen -= bytes_sent; /* sendlen != bytes_sent ==> partial write */
                 o += bytes_sent;       /* o is where we are in the buffer */
@@ -2909,6 +3122,8 @@ AP_INIT_RAW_ARGS("FileETag", set_etag_bits, NULL, OR_FILEINFO,
   "Specify components used to construct a file's ETag"),
 AP_INIT_TAKE1("EnableMMAP", set_enable_mmap, NULL, OR_FILEINFO,
   "Controls whether memory-mapping may be used to read files"),
+AP_INIT_TAKE1("EnableSendfile", set_enable_sendfile, NULL, OR_FILEINFO,
+  "Controls whether sendfile may be used to transmit files"),
 
 /* Old server config file commands */
 
@@ -2936,8 +3151,6 @@ AP_INIT_TAKE1("ServerPath", set_serverpath, NULL, RSRC_CONF,
   "The pathname the server can be reached at"),
 AP_INIT_TAKE1("Timeout", set_timeout, NULL, RSRC_CONF,
   "Timeout duration (sec)"),
-AP_INIT_FLAG("IdentityCheck", set_idcheck, NULL, RSRC_CONF|ACCESS_CONF,
-  "Enable identd (RFC 1413) user lookups - SLOW"),
 AP_INIT_FLAG("ContentDigest", set_content_md5, NULL, OR_OPTIONS,
   "whether or not to send a Content-MD5 header with each request"),
 AP_INIT_TAKE1("UseCanonicalName", set_use_canonical_name, NULL,
@@ -2952,10 +3165,6 @@ AP_INIT_TAKE1("LogLevel", set_loglevel, NULL, RSRC_CONF,
   "Level of verbosity in error logging"),
 AP_INIT_TAKE1("NameVirtualHost", ap_set_name_virtual_host, NULL, RSRC_CONF,
   "A numeric IP address:port, or the name of a host"),
-#ifdef _OSD_POSIX
-AP_INIT_TAKE1("BS2000Account", set_bs2000_account, NULL, RSRC_CONF,
-  "Name of server User's bs2000 logon account name"),
-#endif
 AP_INIT_TAKE1("ServerTokens", set_serv_tokens, NULL, RSRC_CONF,
   "Determine tokens displayed in the Server: header - Min(imal), OS or Full"),
 AP_INIT_TAKE1("LimitRequestLine", set_limit_req_line, NULL, RSRC_CONF,
@@ -2998,6 +3207,10 @@ AP_INIT_TAKE12("RLimitNPROC", no_set_limit, NULL,
    OR_ALL, "soft/hard limits for max number of processes per uid"),
 #endif
 
+/* internal recursion stopper */
+AP_INIT_TAKE12("LimitInternalRecursion", set_recursion_limit, NULL, RSRC_CONF,
+              "maximum recursion depth of internal redirects and subrequests"),
+
 AP_INIT_TAKE1("ForceType", ap_set_string_slot_lower,
        (void *)APR_OFFSETOF(core_dir_config, mime_type), OR_FILEINFO,
      "a mime type that overrides other configured type"),
@@ -3013,6 +3226,8 @@ AP_INIT_TAKE1("SetInputFilter", ap_set_string_slot,
 AP_INIT_ITERATE2("AddOutputFilterByType", add_ct_output_filters,
        (void *)APR_OFFSETOF(core_dir_config, ct_output_filters), OR_FILEINFO,
      "output filter name followed by one or more content-types"),
+AP_INIT_FLAG("AllowEncodedSlashes", set_allow2f, NULL, RSRC_CONF,
+             "Allow URLs containing '/' encoded as '%2F'"),
 
 /*
  * These are default configuration directives that mpms can/should
@@ -3020,31 +3235,31 @@ AP_INIT_ITERATE2("AddOutputFilterByType", add_ct_output_filters,
  * #defined them in mpm.h.
  */
 #ifdef AP_MPM_WANT_SET_PIDFILE
-AP_INIT_TAKE1("PidFile",  ap_mpm_set_pidfile, NULL, RSRC_CONF, \
+AP_INIT_TAKE1("PidFile",  ap_mpm_set_pidfile, NULL, RSRC_CONF,
               "A file for logging the server process ID"),
 #endif
 #ifdef AP_MPM_WANT_SET_SCOREBOARD
-AP_INIT_TAKE1("ScoreBoardFile", ap_mpm_set_scoreboard, NULL, RSRC_CONF, \
+AP_INIT_TAKE1("ScoreBoardFile", ap_mpm_set_scoreboard, NULL, RSRC_CONF,
               "A file for Apache to maintain runtime process management information"),
 #endif
 #ifdef AP_MPM_WANT_SET_LOCKFILE
-AP_INIT_TAKE1("LockFile",  ap_mpm_set_lockfile, NULL, RSRC_CONF, \
+AP_INIT_TAKE1("LockFile",  ap_mpm_set_lockfile, NULL, RSRC_CONF,
               "The lockfile used when Apache needs to lock the accept() call"),
 #endif
 #ifdef AP_MPM_WANT_SET_MAX_REQUESTS
-AP_INIT_TAKE1("MaxRequestsPerChild", ap_mpm_set_max_requests, NULL, RSRC_CONF,\
+AP_INIT_TAKE1("MaxRequestsPerChild", ap_mpm_set_max_requests, NULL, RSRC_CONF,
               "Maximum number of requests a particular child serves before dying."),
 #endif
 #ifdef AP_MPM_WANT_SET_COREDUMPDIR
-AP_INIT_TAKE1("CoreDumpDirectory", ap_mpm_set_coredumpdir, NULL, RSRC_CONF, \
+AP_INIT_TAKE1("CoreDumpDirectory", ap_mpm_set_coredumpdir, NULL, RSRC_CONF,
               "The location of the directory Apache changes to before dumping core"),
 #endif
 #ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
-AP_INIT_TAKE1("AcceptMutex", ap_mpm_set_accept_lock_mech, NULL, RSRC_CONF, \
+AP_INIT_TAKE1("AcceptMutex", ap_mpm_set_accept_lock_mech, NULL, RSRC_CONF,
               ap_valid_accept_mutex_string),
 #endif
 #ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
-AP_INIT_TAKE1("MaxMemFree", ap_mpm_set_max_mem_free, NULL, RSRC_CONF,\
+AP_INIT_TAKE1("MaxMemFree", ap_mpm_set_max_mem_free, NULL, RSRC_CONF,
               "Maximum number of 1k blocks a particular childs allocator may hold."),
 #endif
 { NULL }
@@ -3076,9 +3291,16 @@ AP_DECLARE_NONSTD(int) ap_core_translate(request_rec *r)
         && !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')) {
-        if (apr_filepath_merge(&r->filename, conf->ap_document_root,
-                               r->uri + r->server->pathlen,
+            || r->uri[r->server->pathlen] == '\0')) 
+    {
+        /* skip all leading /'s (e.g. http://localhost///foo) 
+         * so we are looking at only the relative path.
+         */
+        char *path = r->uri + r->server->pathlen;
+        while (*path == '/') {
+            ++path;
+        }
+        if (apr_filepath_merge(&r->filename, conf->ap_document_root, path,
                                APR_FILEPATH_TRUENAME
                              | APR_FILEPATH_SECUREROOT, r->pool)
                     != APR_SUCCESS) {
@@ -3092,8 +3314,14 @@ AP_DECLARE_NONSTD(int) ap_core_translate(request_rec *r)
          * /'s in a row.  This happens under windows when the document
          * root ends with a /
          */
-        if (apr_filepath_merge(&r->filename, conf->ap_document_root,
-                               r->uri + ((*(r->uri) == '/') ? 1 : 0),
+        /* skip all leading /'s (e.g. http://localhost///foo) 
+         * so we are looking at only the relative path.
+         */
+        char *path = r->uri;
+        while (*path == '/') {
+            ++path;
+        }
+        if (apr_filepath_merge(&r->filename, conf->ap_document_root, path,
                                APR_FILEPATH_TRUENAME
                              | APR_FILEPATH_SECUREROOT, r->pool)
                     != APR_SUCCESS) {
@@ -3222,8 +3450,34 @@ static int default_handler(request_rec *r)
             return HTTP_NOT_FOUND;
         }
 
-        if ((status = apr_file_open(&fd, r->filename, APR_READ | APR_BINARY, 0,
-                                    r->pool)) != APR_SUCCESS) {
+        /* We understood the (non-GET) method, but it might not be legal for
+           this particular resource. Check to see if the 'deliver_script'
+           flag is set. If so, then we go ahead and deliver the file since
+           it isn't really content (only GET normally returns content).
+
+           Note: based on logic further above, the only possible non-GET
+           method at this point is POST. In the future, we should enable
+           script delivery for all methods.  */
+        if (r->method_number != M_GET) {
+            core_request_config *req_cfg;
+
+            req_cfg = ap_get_module_config(r->request_config, &core_module);
+            if (!req_cfg->deliver_script) {
+                /* The flag hasn't been set for this request. Punt. */
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                              "This resource does not accept the %s method.",
+                              r->method);
+                return HTTP_METHOD_NOT_ALLOWED;
+            }
+        }
+
+
+        if ((status = apr_file_open(&fd, r->filename, APR_READ | APR_BINARY
+#if APR_HAS_SENDFILE
+                            | ((d->enable_sendfile == ENABLE_SENDFILE_OFF) 
+                                                ? 0 : APR_SENDFILE_ENABLED)
+#endif
+                                    , 0, r->pool)) != APR_SUCCESS) {
             ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
                           "file permissions deny server access: %s", r->filename);
             return HTTP_FORBIDDEN;
@@ -3245,8 +3499,9 @@ static int default_handler(request_rec *r)
         }
 
         bb = apr_brigade_create(r->pool, c->bucket_alloc);
-#if APR_HAS_LARGE_FILES
-        if (r->finfo.size > AP_MAX_SENDFILE) {
+#if APR_HAS_SENDFILE && APR_HAS_LARGE_FILES
+        if ((d->enable_sendfile != ENABLE_SENDFILE_OFF) &&
+            (r->finfo.size > AP_MAX_SENDFILE)) {
             /* APR_HAS_LARGE_FILES issue; must split into mutiple buckets,
              * no greater than MAX(apr_size_t), and more granular than that
              * in case the brigade code/filters attempt to read it directly.
@@ -3293,31 +3548,34 @@ static int default_handler(request_rec *r)
     }
 }
 
+typedef struct net_time_filter_ctx {
+    apr_socket_t *csd;
+    int           first_line;
+} net_time_filter_ctx_t;
 static int net_time_filter(ap_filter_t *f, apr_bucket_brigade *b,
                            ap_input_mode_t mode, apr_read_type_e block,
                            apr_off_t readbytes)
 {
+    net_time_filter_ctx_t *ctx = f->ctx;
     int keptalive = f->c->keepalive == AP_CONN_KEEPALIVE;
-    apr_socket_t *csd = ap_get_module_config(f->c->conn_config, &core_module);
-    int *first_line = f->ctx;
 
-    if (!f->ctx) {
-        f->ctx = first_line = apr_palloc(f->r->pool, sizeof(*first_line));
-        *first_line = 1;
+    if (!ctx) {
+        f->ctx = ctx = apr_palloc(f->r->pool, sizeof(*ctx));
+        ctx->first_line = 1;
+        ctx->csd = ap_get_module_config(f->c->conn_config, &core_module);        
     }
 
     if (mode != AP_MODE_INIT && mode != AP_MODE_EATCRLF) {
-        if (*first_line) {
-            apr_setsocketopt(csd, APR_SO_TIMEOUT,
-                             (int)(keptalive
-                      ? f->c->base_server->keep_alive_timeout
-                      : f->c->base_server->timeout));
-            *first_line = 0;
+        if (ctx->first_line) {
+            apr_socket_timeout_set(ctx->csd, 
+                                   keptalive
+                                      ? f->c->base_server->keep_alive_timeout
+                                      : f->c->base_server->timeout);
+            ctx->first_line = 0;
         }
         else {
             if (keptalive) {
-                apr_setsocketopt(csd, APR_SO_TIMEOUT,
-                                 (int)(f->c->base_server->timeout));
+                apr_socket_timeout_set(ctx->csd, f->c->base_server->timeout);
             }
         }
     }
@@ -3393,6 +3651,19 @@ static int core_input_filter(ap_filter_t *f, apr_bucket_brigade *b,
         return APR_EOF;
     }
 
+    if (mode == AP_MODE_GETLINE) {
+        /* we are reading a single LF line, e.g. the HTTP headers */
+        rv = apr_brigade_split_line(b, ctx->b, block, HUGE_STRING_LEN);
+        /* We should treat EAGAIN here the same as we do for EOF (brigade is
+         * empty).  We do this by returning whatever we have read.  This may
+         * or may not be bogus, but is consistent (for now) with EOF logic.
+         */
+        if (APR_STATUS_IS_EAGAIN(rv)) {
+            rv = APR_SUCCESS;
+        }
+        return rv;
+    }
+
     /* ### AP_MODE_PEEK is a horrific name for this mode because we also
      * eat any CRLFs that we see.  That's not the obvious intention of
      * this mode.  Determine whether anyone actually uses this or not. */
@@ -3435,6 +3706,7 @@ static int core_input_filter(ap_filter_t *f, apr_bucket_brigade *b,
             /* FIXME: Is this the right thing to do in the core? */
             apr_bucket_delete(e);
         }
+        return APR_SUCCESS;
     }
 
     /* If mode is EXHAUSTIVE, we want to just read everything until the end
@@ -3527,22 +3799,8 @@ static int core_input_filter(ap_filter_t *f, apr_bucket_brigade *b,
 
         /* Take what was originally there and place it back on ctx->b */
         APR_BRIGADE_CONCAT(ctx->b, newbb);
-
-        return APR_SUCCESS;
-    }
-
-    /* we are reading a single LF line, e.g. the HTTP headers */
-    rv = apr_brigade_split_line(b, ctx->b, block, HUGE_STRING_LEN);
-
-    /* We should treat EAGAIN here the same as we do for EOF (brigade is
-     * empty).  We do this by returning whatever we have read.  This may
-     * or may not be bogus, but is consistent (for now) with EOF logic.
-     */
-    if (APR_STATUS_IS_EAGAIN(rv)) {
-        rv = APR_SUCCESS;
     }
-
-    return rv;
+    return APR_SUCCESS;
 }
 
 /* Default filter.  This filter should almost always be used.  Its only job
@@ -3551,12 +3809,20 @@ static int core_input_filter(ap_filter_t *f, apr_bucket_brigade *b,
  */
 #define MAX_IOVEC_TO_WRITE 16
 
+/* Optional function coming from mod_logio, used for logging of output
+ * traffic
+ */
+static APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *logio_add_bytes_out;
+
 static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b)
 {
     apr_status_t rv;
+    apr_bucket_brigade *more;
     conn_rec *c = f->c;
     core_net_rec *net = f->ctx;
     core_output_filter_ctx_t *ctx = net->out_ctx;
+    apr_read_type_e eblock = APR_NONBLOCK_READ;
+    apr_pool_t *input_pool = b->p;
 
     if (ctx == NULL) {
         ctx = apr_pcalloc(c->pool, sizeof(*ctx));
@@ -3577,9 +3843,6 @@ static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b)
         apr_bucket *last_e = NULL; /* initialized for debugging */
         apr_bucket *e;
 
-        /* tail of brigade if we need another pass */
-        apr_bucket_brigade *more = NULL;
-
         /* one group of iovecs per pass over the brigade */
         apr_size_t nvec = 0;
         apr_size_t nvec_trailers = 0;
@@ -3596,6 +3859,9 @@ static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b)
          */
         apr_bucket *last_merged_bucket = NULL;
 
+        /* tail of brigade if we need another pass */
+        more = NULL;
+
         /* Iterate over the brigade: collect iovecs and/or a file */
         APR_BRIGADE_FOREACH(e, b) {
             /* keep track of the last bucket processed */
@@ -3604,7 +3870,9 @@ static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b)
                 break;
             }
             if (APR_BUCKET_IS_FLUSH(e)) {
-                more = apr_brigade_split(b, APR_BUCKET_NEXT(e));
+                if (e != APR_BRIGADE_LAST(b)) {
+                    more = apr_brigade_split(b, APR_BUCKET_NEXT(e));
+                }
                 break;
             }
 
@@ -3632,7 +3900,16 @@ static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b)
                 const char *str;
                 apr_size_t n;
 
-                rv = apr_bucket_read(e, &str, &n, APR_BLOCK_READ);
+                rv = apr_bucket_read(e, &str, &n, eblock);
+                if (APR_STATUS_IS_EAGAIN(rv)) {
+                    /* send what we have so far since we shouldn't expect more
+                     * output for a while...  next time we read, block
+                     */
+                    more = apr_brigade_split(b, e);
+                    eblock = APR_BLOCK_READ;
+                    break;
+                }
+                eblock = APR_NONBLOCK_READ;
                 if (n) {
                     if (!fd) {
                         if (nvec == MAX_IOVEC_TO_WRITE) {
@@ -3744,78 +4021,76 @@ static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b)
         }
 
 
-        /* Completed iterating over the brigades, now determine if we want
+        /* Completed iterating over the brigade, now determine if we want
          * to buffer the brigade or send the brigade out on the network.
          *
-         * Save if:
+         * Save if we haven't accumulated enough bytes to send, and:
          *
          *   1) we didn't see a file, we don't have more passes over the
-         *      brigade to perform, we haven't accumulated enough bytes to
-         *      send, AND we didn't stop at a FLUSH bucket.
-         *      (IOW, we will save away plain old bytes)
+         *      brigade to perform,  AND we didn't stop at a FLUSH bucket.
+         *      (IOW, we will save plain old bytes such as HTTP headers)
          * or
          *   2) we hit the EOS and have a keep-alive connection
          *      (IOW, this response is a bit more complex, but we save it
          *       with the hope of concatenating with another response)
          */
-        if ((!fd && !more
-             && (nbytes + flen < AP_MIN_BYTES_TO_WRITE)
-             && !APR_BUCKET_IS_FLUSH(last_e))
-            || (nbytes + flen < AP_MIN_BYTES_TO_WRITE 
-                && APR_BUCKET_IS_EOS(last_e)
-                && c->keepalive == AP_CONN_KEEPALIVE)) {
+        if (nbytes + flen < AP_MIN_BYTES_TO_WRITE
+            && ((!fd && !more && !APR_BUCKET_IS_FLUSH(last_e))
+                || (APR_BUCKET_IS_EOS(last_e)
+                    && c->keepalive == AP_CONN_KEEPALIVE))) {
 
             /* NEVER save an EOS in here.  If we are saving a brigade with
              * an EOS bucket, then we are doing keepalive connections, and
              * we want to process to second request fully.
              */
             if (APR_BUCKET_IS_EOS(last_e)) {
-                apr_bucket *bucket = NULL;
-                /* If we are in here, then this request is a keepalive.  We
-                 * need to be certain that any data in a bucket is valid
-                 * after the request_pool is cleared.
-                 */
-                if (ctx->b == NULL) {
-                    ctx->b = apr_brigade_create(net->c->pool,
-                                                net->c->bucket_alloc);
-                }
-
-                APR_BRIGADE_FOREACH(bucket, b) {
-                    const char *str;
-                    apr_size_t n;
-
-                    rv = apr_bucket_read(bucket, &str, &n, APR_BLOCK_READ);
-
-                    /* This apr_brigade_write does not use a flush function
-                       because we assume that we will not write enough data
-                       into it to cause a flush. However, if we *do* write
-                       "too much", then we could end up with transient
-                       buckets which would suck. This works for now, but is
-                       a bit shaky if changes are made to some of the
-                       buffering sizes. Let's do an assert to prevent
-                       potential future problems... */
-                    AP_DEBUG_ASSERT(AP_MIN_BYTES_TO_WRITE <=
-                                    APR_BUCKET_BUFF_SIZE);
-                    if (rv != APR_SUCCESS) {
-                        ap_log_error(APLOG_MARK, APLOG_ERR, rv, c->base_server,
-                                     "core_output_filter: Error reading from bucket.");
-                        return HTTP_INTERNAL_SERVER_ERROR;
+                apr_bucket *bucket;
+                int file_bucket_saved = 0;
+                apr_bucket_delete(last_e);
+                for (bucket = APR_BRIGADE_FIRST(b);
+                     bucket != APR_BRIGADE_SENTINEL(b);
+                     bucket = APR_BUCKET_NEXT(bucket)) {
+
+                    /* Do a read on each bucket to pull in the
+                     * data from pipe and socket buckets, so
+                     * that we don't leave their file descriptors
+                     * open indefinitely.  Do the same for file
+                     * buckets, with one exception: allow the
+                     * first file bucket in the brigade to remain
+                     * a file bucket, so that we don't end up
+                     * doing an mmap+memcpy every time a client
+                     * requests a <8KB file over a keepalive
+                     * connection.
+                     */
+                    if (APR_BUCKET_IS_FILE(bucket) && !file_bucket_saved) {
+                        file_bucket_saved = 1;
+                    }
+                    else {
+                        const char *buf;
+                        apr_size_t len = 0;
+                        rv = apr_bucket_read(bucket, &buf, &len,
+                                             APR_BLOCK_READ);
+                        if (rv != APR_SUCCESS) {
+                            ap_log_error(APLOG_MARK, APLOG_ERR, rv,
+                                         c->base_server, "core_output_filter:"
+                                         " Error reading from bucket.");
+                            return HTTP_INTERNAL_SERVER_ERROR;
+                        }
                     }
-
-                    apr_brigade_write(ctx->b, NULL, NULL, str, n);
                 }
-
-                apr_brigade_destroy(b);
             }
-            else {
-                ap_save_brigade(f, &ctx->b, &b, c->pool);
+            if (!ctx->deferred_write_pool) {
+                apr_pool_create(&ctx->deferred_write_pool, c->pool);
             }
+            ap_save_brigade(f, &ctx->b, &b, ctx->deferred_write_pool);
 
             return APR_SUCCESS;
         }
 
         if (fd) {
             apr_hdtr_t hdtr;
+            apr_size_t bytes_sent;
+
 #if APR_HAS_SENDFILE
             apr_int32_t flags = 0;
 #endif
@@ -3832,45 +4107,77 @@ static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b)
             }
 
 #if APR_HAS_SENDFILE
-            if (c->keepalive == AP_CONN_CLOSE && APR_BUCKET_IS_EOS(last_e)) {
-                /* Prepare the socket to be reused */
-                flags |= APR_SENDFILE_DISCONNECT_SOCKET;
-            }
+            if (apr_file_flags_get(fd) & APR_SENDFILE_ENABLED) {
 
-            rv = sendfile_it_all(net,      /* the network information   */
-                                 fd,       /* the file to send          */
-                                 &hdtr,    /* header and trailer iovecs */
-                                 foffset,  /* offset in the file to begin
-                                              sending from              */
-                                 flen,     /* length of file            */
-                                 nbytes + flen, /* total length including
-                                                   headers                */
-                                 flags);   /* apr_sendfile flags        */
-
-            /* If apr_sendfile() returns APR_ENOTIMPL, call emulate_sendfile().
-             * emulate_sendfile() is useful to enable the same Apache binary
-             * distribution to support Windows NT/2000 (supports TransmitFile)
-             * and Win95/98 (do not support TransmitFile)
-             */
-            if (rv == APR_ENOTIMPL)
+                if (c->keepalive == AP_CONN_CLOSE && APR_BUCKET_IS_EOS(last_e)) {
+                    /* Prepare the socket to be reused */
+                    flags |= APR_SENDFILE_DISCONNECT_SOCKET;
+                }
+
+                rv = sendfile_it_all(net,      /* the network information   */
+                                     fd,       /* the file to send          */
+                                     &hdtr,    /* header and trailer iovecs */
+                                     foffset,  /* offset in the file to begin
+                                                  sending from              */
+                                     flen,     /* length of file            */
+                                     nbytes + flen, /* total length including
+                                                       headers              */
+                                     &bytes_sent,   /* how many bytes were
+                                                       sent                 */
+                                     flags);   /* apr_sendfile flags        */
+
+                if (logio_add_bytes_out && bytes_sent > 0)
+                    logio_add_bytes_out(c, bytes_sent);
+            }
+            else
 #endif
             {
-                apr_size_t unused_bytes_sent;
                 rv = emulate_sendfile(net, fd, &hdtr, foffset, flen,
-                                      &unused_bytes_sent);
+                                      &bytes_sent);
+
+                if (logio_add_bytes_out && bytes_sent > 0)
+                    logio_add_bytes_out(c, bytes_sent);
             }
 
             fd = NULL;
         }
         else {
-            apr_size_t unused_bytes_sent;
+            apr_size_t bytes_sent;
 
             rv = writev_it_all(net->client_socket,
                                vec, nvec,
-                               nbytes, &unused_bytes_sent);
+                               nbytes, &bytes_sent);
+
+            if (logio_add_bytes_out && bytes_sent > 0)
+                logio_add_bytes_out(c, bytes_sent);
         }
 
         apr_brigade_destroy(b);
+        
+        /* drive cleanups for resources which were set aside 
+         * this may occur before or after termination of the request which
+         * created the resource
+         */
+        if (ctx->deferred_write_pool) {
+            if (more && more->p == ctx->deferred_write_pool) {
+                /* "more" belongs to the deferred_write_pool,
+                 * which is about to be cleared.
+                 */
+                if (APR_BRIGADE_EMPTY(more)) {
+                    more = NULL;
+                }
+                else {
+                    /* uh oh... change more's lifetime 
+                     * to the input brigade's lifetime 
+                     */
+                    apr_bucket_brigade *tmp_more = more;
+                    more = NULL;
+                    ap_save_brigade(f, &more, &tmp_more, input_pool);
+                }
+            }
+            apr_pool_clear(ctx->deferred_write_pool);  
+        }
+
         if (rv != APR_SUCCESS) {
             ap_log_error(APLOG_MARK, APLOG_INFO, rv, c->base_server,
                          "core_output_filter: writing data to the network");
@@ -3878,9 +4185,8 @@ static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b)
             if (more)
                 apr_brigade_destroy(more);
 
-            if (APR_STATUS_IS_ECONNABORTED(rv)
-                || APR_STATUS_IS_ECONNRESET(rv)
-                || APR_STATUS_IS_EPIPE(rv)) {
+            /* No need to check for SUCCESS, we did that above. */
+            if (!APR_STATUS_IS_EAGAIN(rv)) {
                 c->aborted = 1;
             }
 
@@ -3900,17 +4206,14 @@ static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b)
 
 static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
 {
+    logio_add_bytes_out = APR_RETRIEVE_OPTIONAL_FN(ap_logio_add_bytes_out);
+    ident_lookup = APR_RETRIEVE_OPTIONAL_FN(ap_ident_lookup);
+
     ap_set_version(pconf);
     ap_setup_make_content_type(pconf);
     return OK;
 }
 
-static int core_open_logs(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
-{
-    ap_open_logs(s, plog);
-    return OK;
-}
-
 static void core_insert_filter(request_rec *r)
 {
     core_dir_config *conf = (core_dir_config *)
@@ -3975,6 +4278,10 @@ static int core_create_req(request_rec *r)
     req_cfg = apr_pcalloc(r->pool, sizeof(core_request_config) +
                           sizeof(void *) * num_request_notes);
     req_cfg->notes = (void **)((char *)req_cfg + sizeof(core_request_config));
+
+    /* ### temporarily enable script delivery as the default */
+    req_cfg->deliver_script = 1;
+
     if (r->main) {
         core_request_config *main_req_cfg = (core_request_config *)
             ap_get_module_config(r->main->request_config, &core_module);
@@ -4011,7 +4318,7 @@ static conn_rec *core_create_conn(apr_pool_t *ptrans, server_rec *server,
     conn_rec *c = (conn_rec *) apr_pcalloc(ptrans, sizeof(conn_rec));
 
     c->sbh = sbh;
-    (void) ap_update_child_status(c->sbh, SERVER_BUSY_READ, (request_rec *) NULL);
+    (void)ap_update_child_status(c->sbh, SERVER_BUSY_READ, (request_rec *)NULL);
 
     /* Got a connection structure, so initialize what fields we can
      * (the rest are zeroed out by pcalloc).
@@ -4084,7 +4391,7 @@ static void register_hooks(apr_pool_t *p)
     ap_hook_post_config(core_post_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
     ap_hook_translate_name(ap_core_translate,NULL,NULL,APR_HOOK_REALLY_LAST);
     ap_hook_map_to_storage(core_map_to_storage,NULL,NULL,APR_HOOK_REALLY_LAST);
-    ap_hook_open_logs(core_open_logs,NULL,NULL,APR_HOOK_MIDDLE);
+    ap_hook_open_logs(ap_open_logs,NULL,NULL,APR_HOOK_REALLY_FIRST);
     ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST);
     /* FIXME: I suspect we can eliminate the need for these do_nothings - Ben */
     ap_hook_type_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);