]> granicus.if.org Git - apache/blobdiff - modules/http/http_core.c
adjust remaining modules to use the new handler hook method (Alan Edwards)
[apache] / modules / http / http_core.c
index c5d32e4f05f41ca85915599348df398a9e47417e..312bca727f7926190ceeb2721e682589e4cac607 100644 (file)
  * University of Illinois, Urbana-Champaign.
  */
 
-#define CORE_PRIVATE
-#include "ap_config.h"
+#include "apr.h"
 #include "apr_strings.h"
 #include "apr_lib.h"
+#include "apr_fnmatch.h"
+#include "apr_thread_proc.h"    /* for RLIMIT stuff */
+
+#if APR_HAVE_SYS_UIO_H
+#include <sys/uio.h>            /* for iovec */
+#endif
+
+#define CORE_PRIVATE
+#include "ap_config.h"
 #include "httpd.h"
 #include "http_config.h"
 #include "http_core.h"
 #include "http_log.h"
 #include "rfc1413.h"
 #include "util_md5.h"
-#include "apr_fnmatch.h"
 #include "http_connection.h"
 #include "ap_buckets.h"
 #include "util_filter.h"
 #include "util_ebcdic.h"
 #include "mpm.h"
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
+
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif
 #include <strings.h>
 #endif
 
-/* Make sure we don't write less than 4096 bytes at any one time.
- */
-#define MIN_SIZE_TO_WRITE  9000
-
-/* Allow Apache to use ap_mmap */
-#ifdef USE_MMAP_FILES
-#include "apr_mmap.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 /* SUNOS4 */
-#endif /* MMAP_THRESHOLD */
-#ifndef MMAP_LIMIT
-#define MMAP_LIMIT              (4*1024*1024)
-#endif
-#endif /* USE_MMAP_FILES */
-
 /* LimitXMLRequestBody handling */
 #define AP_LIMIT_UNSET                  ((long) -1)
 #define AP_DEFAULT_LIMIT_XML_BODY       ((size_t)1000000)
@@ -186,7 +162,7 @@ static void *create_core_dir_config(apr_pool_t *a, char *dir)
     conf->add_default_charset = ADD_DEFAULT_CHARSET_UNSET;
     conf->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME;
 
-    conf->filters = apr_make_array(a, 2, sizeof(void *));
+    conf->output_filters = apr_make_array(a, 2, sizeof(void *));
     conf->input_filters = apr_make_array(a, 2, sizeof(void *));
     return (void *)conf;
 }
@@ -327,7 +303,8 @@ static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv)
            conf->add_default_charset_name = new->add_default_charset_name;
        }
     }
-    conf->filters = apr_append_arrays(a, base->filters, new->filters);
+    conf->output_filters = apr_append_arrays(a, base->output_filters, 
+                                             new->output_filters);
     conf->input_filters = apr_append_arrays(a, base->input_filters,
                                             new->input_filters);
 
@@ -606,7 +583,8 @@ char *ap_response_code_string(request_rec *r, int error_index)
 /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
 static apr_inline void do_double_reverse (conn_rec *conn)
 {
-    struct hostent *hptr;
+    apr_sockaddr_t *sa;
+    apr_status_t rv;
 
     if (conn->double_reverse) {
        /* already done */
@@ -617,17 +595,17 @@ static apr_inline void do_double_reverse (conn_rec *conn)
        conn->double_reverse = -1;
        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;
-           }
-       }
+    rv = apr_getaddrinfo(&sa, conn->remote_host, APR_UNSPEC, 0, 0, conn->pool);
+    if (rv == APR_SUCCESS) {
+        while (sa) {
+            if (sa->ipaddr_len == conn->remote_addr->ipaddr_len &&
+                !memcmp(sa->ipaddr_ptr, conn->remote_addr->ipaddr_ptr,
+                        sa->ipaddr_len)) {
+                conn->double_reverse = 1;
+                return;
+            }
+            sa = sa->next;
+        }
     }
     conn->double_reverse = -1;
 }
@@ -635,8 +613,6 @@ static apr_inline void do_double_reverse (conn_rec *conn)
 AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config,
                                            int type)
 {
-    struct in_addr *iaddr;
-    struct hostent *hptr;
     int hostname_lookups;
 
     /* If we haven't checked the host name, and we want to */
@@ -657,10 +633,10 @@ AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config,
        && conn->remote_host == NULL
        && (type == REMOTE_DOUBLE_REV
            || hostname_lookups != HOSTNAME_LOOKUP_OFF)) {
-       iaddr = &(conn->remote_addr.sin_addr);
-       hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET);
-       if (hptr != NULL) {
-           conn->remote_host = apr_pstrdup(conn->pool, (void *)hptr->h_name);
+        apr_sockaddr_t *remote_addr;
+
+        apr_get_sockaddr(&remote_addr, APR_REMOTE, conn->client_socket);
+       if (apr_getnameinfo(&conn->remote_host, remote_addr, 0) == APR_SUCCESS) {
            ap_str_tolower(conn->remote_host);
           
            if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) {
@@ -727,7 +703,7 @@ AP_DECLARE(const char *) ap_get_remote_logname(request_rec *r)
  * 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
+ * reverse lookup on the local IP address of the connection 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...
@@ -746,30 +722,24 @@ AP_DECLARE(const char *) ap_get_server_name(request_rec *r)
     }
     if (d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
         if (conn->local_host == NULL) {
-           struct in_addr *iaddr;
-           struct hostent *hptr;
-           iaddr = &(conn->local_addr.sin_addr);
-           hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr),
-                                AF_INET);
-           if (hptr != NULL) {
-               conn->local_host = apr_pstrdup(conn->pool,
-                                             (void *)hptr->h_name);
-               ap_str_tolower(conn->local_host);
-           }
-           else {
-               conn->local_host = apr_pstrdup(conn->pool,
-                                             r->server->server_hostname);
-           }
-       }
+            apr_sockaddr_t *local_addr;
+
+            apr_get_sockaddr(&local_addr, APR_LOCAL, conn->client_socket);
+            if (apr_getnameinfo(&conn->local_host, local_addr, 0) != APR_SUCCESS)
+                conn->local_host = apr_pstrdup(conn->pool, r->server->server_hostname);
+            else {
+                ap_str_tolower(conn->local_host);
+            }
+        }
        return conn->local_host;
     }
     /* default */
     return r->server->server_hostname;
 }
 
-AP_DECLARE(unsigned) ap_get_server_port(const request_rec *r)
+AP_DECLARE(apr_port_t) ap_get_server_port(const request_rec *r)
 {
-    unsigned port;
+    apr_port_t port;
     core_dir_config *d =
       (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
     
@@ -777,8 +747,12 @@ AP_DECLARE(unsigned) ap_get_server_port(const request_rec *r)
 
     if (d->use_canonical_name == USE_CANONICAL_NAME_OFF
        || d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
-        return r->hostname ? ntohs(r->connection->local_addr.sin_port)
-                          : port;
+        if (r->hostname) {
+            apr_sockaddr_t *localsa;
+
+            apr_get_sockaddr(&localsa, APR_LOCAL, r->connection->client_socket);
+            apr_get_port(&port, localsa);
+        }
     }
     /* default */
     return port;
@@ -1219,9 +1193,9 @@ static const char *set_document_root(cmd_parms *cmd, void *dummy,
     }
 
     arg = ap_os_canonical_filename(cmd->pool, arg);
-    if (/* TODO: ap_configtestonly && ap_docrootcheck && */ !ap_is_directory(arg)) {
+    if (/* TODO: ap_configtestonly && ap_docrootcheck && */ !ap_is_directory(cmd->pool, arg)) {
        if (cmd->server->is_virtual) {
-           ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
+           ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, cmd->pool,
                          "Warning: DocumentRoot [%s] does not exist",
                         arg);
        }
@@ -1905,7 +1879,7 @@ static const char *add_filter(cmd_parms *cmd, void *dummy, const char *arg)
     core_dir_config *conf = dummy;
     char **newfilter;
     
-    newfilter = (char **)apr_push_array(conf->filters);
+    newfilter = (char **)apr_push_array(conf->output_filters);
     *newfilter = apr_pstrdup(cmd->pool, arg);
     return NULL;
 }
@@ -2020,7 +1994,7 @@ static const char *set_server_root(cmd_parms *cmd, void *dummy,
 
     arg = ap_os_canonical_filename(cmd->pool, arg);
 
-    if (!ap_is_directory(arg)) {
+    if (!ap_is_directory(cmd->pool, arg)) {
         return "ServerRoot must be a valid directory";
     }
     ap_server_root = arg;
@@ -2514,7 +2488,7 @@ static const char *set_interpreter_source(cmd_parms *cmd, core_dir_config *d,
 #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,
+static const char *no_set_limit(cmd_parms *cmd, void *conf_,
                                 const char *arg, const char *arg2)
 {
     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, cmd->server,
@@ -2562,13 +2536,14 @@ static const char *set_limit_nproc(cmd_parms *cmd, void *conf_,
 }
 #endif
 
-static apr_status_t writev_it_all(apr_socket_t *s, struct iovec *vec, int nvec, 
+static apr_status_t writev_it_all(apr_socket_t *s,
+                                  struct iovec *vec, int nvec,
                                   apr_size_t len, apr_size_t *nbytes)
 {
     apr_size_t bytes_written = 0;
     apr_status_t rv;
-    apr_ssize_t n = len;
-    apr_ssize_t i = 0;
+    apr_size_t n = len;
+    apr_size_t i = 0;
 
     *nbytes = 0;
 
@@ -2578,6 +2553,7 @@ static apr_status_t writev_it_all(apr_socket_t *s, struct iovec *vec, int nvec,
         bytes_written += n;
         if (rv != APR_SUCCESS)
             return rv;
+        *nbytes += n;
 
         /* If the write did not complete, adjust the iovecs and issue
          * apr_sendv again
@@ -2601,6 +2577,91 @@ static apr_status_t writev_it_all(apr_socket_t *s, struct iovec *vec, int nvec,
 
     return APR_SUCCESS;
 }
+
+/* sendfile_it_all()
+ *  send the entire file using sendfile()
+ *  handle partial writes
+ *  return only when all bytes have been sent or an error is encountered.
+ */
+
+#if APR_HAS_SENDFILE
+static apr_status_t sendfile_it_all(conn_rec   *c, 
+                                    apr_file_t *fd,
+                                    apr_hdtr_t *hdtr, 
+                                    apr_off_t   file_offset,
+                                    apr_size_t  file_bytes_left, 
+                                    apr_size_t  total_bytes_left,
+                                    apr_int32_t flags)
+{
+    apr_status_t rv;
+    apr_int32_t timeout = 0;
+
+    AP_DEBUG_ASSERT((apr_getsocketopt(c->client_socket, APR_SO_TIMEOUT, 
+                       &timeout) == APR_SUCCESS) && 
+                     timeout > 0);  /* socket must be in timeout mode */ 
+    do {
+        apr_size_t tmplen = file_bytes_left;
+        
+        rv = apr_sendfile(c->client_socket, fd, hdtr, &file_offset, &tmplen, 
+                          flags);
+        total_bytes_left -= tmplen;
+        if (!total_bytes_left || rv != APR_SUCCESS) {
+            return rv;        /* normal case & error exit */ 
+        }
+
+        AP_DEBUG_ASSERT(total_bytes_left > 0 && tmplen > 0);
+        
+        /* partial write, oooh noooo... 
+         * Skip over any header data which was written
+         */
+        while (tmplen && hdtr->numheaders) {
+            if (tmplen >= hdtr->headers[0].iov_len) {
+                tmplen -= hdtr->headers[0].iov_len;
+                --hdtr->numheaders;
+                ++hdtr->headers;
+            }
+            else {
+                char *iov_base = (char *)hdtr->headers[0].iov_base;
+
+                hdtr->headers[0].iov_len -= tmplen;
+                iov_base += tmplen;
+                hdtr->headers[0].iov_base = iov_base;
+                tmplen = 0;
+            }
+        }
+
+        /* Skip over any file data which was written */
+
+        if (tmplen <= file_bytes_left) {
+            file_offset += tmplen;
+            file_bytes_left -= tmplen;
+            continue; 
+        }
+        tmplen -= file_bytes_left;
+        file_bytes_left = 0;
+        file_offset = 0;
+        
+        /* Skip over any trailer data which was written */
+        
+        while (tmplen && hdtr->numtrailers) {
+            if (tmplen >= hdtr->trailers[0].iov_len) {
+                tmplen -= hdtr->trailers[0].iov_len;
+                --hdtr->numtrailers;
+                ++hdtr->trailers;
+            }
+            else {
+                char *iov_base = (char *)hdtr->trailers[0].iov_base;
+
+                hdtr->trailers[0].iov_len -= tmplen;
+                iov_base += tmplen;
+                hdtr->trailers[0].iov_base = iov_base;
+                tmplen = 0;
+            }
+        }
+    } while (1);
+}
+#endif
+        
 /*
  * send_the_file()
  * Sends the contents of file fd along with header/trailer bytes, if any,
@@ -2630,7 +2691,7 @@ static apr_status_t send_the_file(conn_rec *c, apr_file_t *fd,
         for (i = 0; i < hdtr->numheaders; i++) {
             sendlen += hdtr->headers[i].iov_len;
         }
-        rv = writev_it_all(c->client->bsock, hdtr->headers, hdtr->numheaders,
+        rv = writev_it_all(c->client_socket, hdtr->headers, hdtr->numheaders,
                            sendlen, &bytes_sent);
         if (rv == APR_SUCCESS)
             *nbytes += bytes_sent;     /* track total bytes sent */
@@ -2649,7 +2710,7 @@ static apr_status_t send_the_file(conn_rec *c, apr_file_t *fd,
         rv = apr_read(fd, buffer, &sendlen);
         while (rv == APR_SUCCESS && sendlen) {
             bytes_sent = sendlen;
-            rv = apr_send(c->client->bsock, &buffer[o], &bytes_sent);
+            rv = apr_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 */
@@ -2668,7 +2729,7 @@ static apr_status_t send_the_file(conn_rec *c, apr_file_t *fd,
         for (i = 0; i < hdtr->numtrailers; i++) {
             sendlen += hdtr->trailers[i].iov_len;
         }
-        rv = writev_it_all(c->client->bsock, hdtr->trailers, hdtr->numtrailers,
+        rv = writev_it_all(c->client_socket, hdtr->trailers, hdtr->numtrailers,
                            sendlen, &bytes_sent);
         if (rv == APR_SUCCESS)
             *nbytes += bytes_sent;
@@ -2910,24 +2971,14 @@ AP_DECLARE_NONSTD(int) ap_core_translate(request_rec *r)
 
 static int do_nothing(request_rec *r) { return OK; }
 
-/*
- * 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;
+    ap_bucket_brigade *bb;
+    ap_bucket *e;
+    core_dir_config *d;
+    int errstatus;
     apr_file_t *fd = NULL;
     apr_status_t status;
-#ifdef USE_MMAP_FILES
-    apr_mmap_t *mm = NULL;
-#endif
     /* XXX if/when somebody writes a content-md5 filter we either need to
      *     remove this support or coordinate when to use the filter vs.
      *     when to use this code
@@ -2935,18 +2986,29 @@ static int default_handler(request_rec *r)
      *     support fairly closely (unlike 1.3, we don't handle computing md5
      *     when the charset is translated).
      */
-    int bld_content_md5 = 
-        (d->content_md5 & 1) && r->output_filters->frec->ftype != AP_FTYPE_CONTENT;
+    int bld_content_md5;
 
-    /* This handler has no use for a request body (yet), but we still
-     * need to read and discard it if the client sent one.
+    /*
+     * The old way of doing handlers meant that this handler would
+     * match literally anything - this way will require handler to
+     * have a / in the middle, which probably captures the original
+     * intent, but may cause problems at first - Ben 7th Jan 01
      */
+    if(strcmp(r->handler,"default-handler")
+       && ap_strcmp_match(r->handler,"*/*"))
+       return DECLINED;
+
+    d = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+                                               &core_module);
+    bld_content_md5 = (d->content_md5 & 1)
+      && r->output_filters->frec->ftype != AP_FTYPE_CONTENT;
+
+    ap_allow_methods(r, MERGE_ALLOW, "GET", "OPTIONS", "POST", NULL);
+
     if ((errstatus = ap_discard_request_body(r)) != OK) {
         return errstatus;
     }
-
-    ap_allow_methods(r, MERGE_ALLOW, "GET", "OPTIONS", NULL);
-
+    
     if (r->method_number == M_INVALID) {
        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
                    "Invalid method in request %s", r->the_request);
@@ -2965,11 +3027,12 @@ static int default_handler(request_rec *r)
                      : r->filename);
        return HTTP_NOT_FOUND;
     }
-    if (r->method_number != M_GET) {
+    
+    if (r->method_number != M_GET && r->method_number != M_POST) {
         return HTTP_METHOD_NOT_ALLOWED;
     }
        
-    if ((status = apr_open(&fd, r->filename, APR_READ | APR_BINARY, 0, r->pool)) != APR_SUCCESS) {
+    if ((status = apr_open(&fd, r->filename, APR_READ | APR_BINARY, 0, r->connection->pool)) != APR_SUCCESS) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
                     "file permissions deny server access: %s", r->filename);
         return HTTP_FORBIDDEN;
@@ -2978,130 +3041,57 @@ static int default_handler(request_rec *r)
     ap_set_last_modified(r);
     ap_set_etag(r);
     apr_table_setn(r->headers_out, "Accept-Ranges", "bytes");
-    if (((errstatus = ap_meets_conditions(r)) != OK)
-       || (errstatus = ap_set_content_length(r, r->finfo.size))) {
+    ap_set_content_length(r, r->finfo.size); 
+    if ((errstatus = ap_meets_conditions(r)) != OK) {
         apr_close(fd);
         return errstatus;
     }
 
-#ifdef USE_MMAP_FILES
-    if ((r->finfo.size >= MMAP_THRESHOLD)
-       && (r->finfo.size < MMAP_LIMIT)
-       && (!r->header_only || bld_content_md5)) {
-       /* we need to protect ourselves in case we die while we've got the
-        * file mmapped */
-        apr_status_t status;
-        if ((status = apr_mmap_create(&mm, fd, 0, r->finfo.size, r->pool)) != APR_SUCCESS) {
-           ap_log_rerror(APLOG_MARK, APLOG_CRIT, status, r,
-                        "default_handler: mmap failed: %s", r->filename);
-           mm = NULL;
-       }
-    }
-    else {
-       mm = NULL;
+    if (bld_content_md5) {
+        apr_table_setn(r->headers_out, "Content-MD5",
+                       ap_md5digest(r->pool, fd));
     }
 
-    if (mm == NULL) {
-#endif
-
-        if (bld_content_md5) {
-#ifdef APACHE_XLATE
-           apr_table_setn(r->headers_out, "Content-MD5",
-                           ap_md5digest(r->pool, fd, NULL));
-#else
-           apr_table_setn(r->headers_out, "Content-MD5",
-                           ap_md5digest(r->pool, fd));
-#endif /* APACHE_XLATE */
-       }
+    bb = ap_brigade_create(r->pool);
+    e = ap_bucket_create_file(fd, 0, r->finfo.size);
 
-       rangestatus = ap_set_byterange(r);
+    AP_BRIGADE_INSERT_HEAD(bb, e);
+    e = ap_bucket_create_eos();
+    AP_BRIGADE_INSERT_TAIL(bb, e);
 
-       ap_send_http_header(r);
-       
-       if (!r->header_only) {
-            apr_size_t length = r->finfo.size;
-            apr_off_t  offset = 0;
-            apr_size_t nbytes = 0;
-
-           if (!rangestatus) {
-               ap_send_fd(fd, r, offset, length, &nbytes);
-           }
-           else {
-               while (ap_each_byterange(r, &offset, &length)) {
-                    if ((status = ap_send_fd(fd, r, offset, length, &nbytes)) != APR_SUCCESS) {
-                       ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
-                                 "error byteserving file: %s", r->filename);
-                       return HTTP_INTERNAL_SERVER_ERROR;
-                   }
-               }
-           }
-       }
-
-#ifdef USE_MMAP_FILES
-    }
-    else {
-       unsigned char *addr;
-        apr_mmap_offset((void**)&addr, mm ,0);
-
-       if (bld_content_md5) {
-           apr_md5_ctx_t context;
-           
-           apr_MD5Init(&context);
-           apr_MD5Update(&context, addr, (unsigned int)r->finfo.size);
-           apr_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.size);
-           }
-           else {
-               apr_off_t offset;
-               apr_size_t length;
-               while (ap_each_byterange(r, &offset, &length)) {
-                   ap_send_mmap(mm, r, offset, length);
-               }
-           }
-       }
-    }
-#endif
-
-    apr_close(fd);
-    return OK;
+    return ap_pass_brigade(r->output_filters, bb);
 }
-/* Buffer filter 
- * This is a relatively simple filter to coalesce many small buckets into 
- * one large bucket. This implementation of buffer_filter will only coalesce
- * a single contiguous string of coalesable buckets. It will not coalesce 
- * multiple non-contiguous buckets. 
- * 
- * For example, if a brigade contains 10 small buckets followed by a 
- * large bucket (or a pipe or file bucket) followed by more small buckets, 
- * only the first 10 buckets will be coalesced.
+
+/*
+ * coalesce_filter()
+ * This is a simple filter to coalesce many small buckets into one large
+ * bucket. 
+ *
+ * Note:
+ * This implementation of coalesce_filter will only coalesce a single
+ * contiguous string of coalesable buckets. It will not coalesce multiple
+ * non-contiguous buckets. For example, if a brigade contains 10 small 
+ * buckets followed by a large bucket (or a pipe or file bucket) followed 
+ * by more small buckets, only the first 10 buckets will be coalesced.
  */
-typedef struct BUFFER_FILTER_CTX {
+typedef struct COALESCE_FILTER_CTX {
     char *buf;           /* Start of buffer */
     char *cur;           /* Pointer to next location to write */
-    apr_ssize_t cnt;     /* Number of bytes put in buf */
-    apr_ssize_t avail;   /* Number of bytes available in the buf */
-} buffer_filter_ctx_t;
-#define FILTER_BUFF_SIZE 8192
+    apr_size_t cnt;     /* Number of bytes put in buf */
+    apr_size_t avail;   /* Number of bytes available in the buf */
+} coalesce_filter_ctx_t;
 #define MIN_BUCKET_SIZE 200
-static apr_status_t buffer_filter(ap_filter_t *f, ap_bucket_brigade *b)
+static apr_status_t coalesce_filter(ap_filter_t *f, ap_bucket_brigade *b)
 {
     apr_status_t rv;
     apr_pool_t *p = f->r->pool;
     ap_bucket *e, *insert_before = NULL, *destroy_me = NULL;
-    buffer_filter_ctx_t *ctx = f->ctx;
+    coalesce_filter_ctx_t *ctx = f->ctx;
     int pass_the_brigade = 0, insert_first = 0;
 
     if (ctx == NULL) {
-        f->ctx = ctx = apr_pcalloc(p, sizeof(buffer_filter_ctx_t));
-        ctx->avail = FILTER_BUFF_SIZE;
+        f->ctx = ctx = apr_pcalloc(p, sizeof(coalesce_filter_ctx_t));
+        ctx->avail = AP_MIN_BYTES_TO_WRITE;
     }
 
     if (ctx->cnt) {
@@ -3122,8 +3112,8 @@ static apr_status_t buffer_filter(ap_filter_t *f, ap_bucket_brigade *b)
         }
         else {
             const char *str;
-            apr_ssize_t n;
-            rv = ap_bucket_read(e, &str, &n, 0);
+            apr_size_t n;
+            rv = ap_bucket_read(e, &str, &n, AP_BLOCK_READ);
             if (rv != APR_SUCCESS) {
                 /* XXX: log error */
                 return rv;
@@ -3131,7 +3121,7 @@ static apr_status_t buffer_filter(ap_filter_t *f, ap_bucket_brigade *b)
             if ((n < MIN_BUCKET_SIZE) && (n < ctx->avail)) {
                 /* Coalesce this bucket into the buffer */
                 if (ctx->buf == NULL) {
-                    ctx->buf = apr_palloc(p, FILTER_BUFF_SIZE);
+                    ctx->buf = apr_palloc(p, AP_MIN_BYTES_TO_WRITE);
                     ctx->cur = ctx->buf;
                     ctx->cnt = 0;
                 }
@@ -3174,13 +3164,12 @@ static apr_status_t buffer_filter(ap_filter_t *f, ap_bucket_brigade *b)
     }
 
     if (pass_the_brigade) {
-        /* Insert ctx->buf into the correct spotin the brigade */
+        /* Insert ctx->buf into the correct spot in the brigade */
+        e = ap_bucket_create_pool(ctx->buf, ctx->cnt, p);
         if (insert_first) {
-            e = ap_bucket_create_transient(ctx->buf, ctx->cnt);
             AP_BRIGADE_INSERT_HEAD(b, e);
         } 
         else if (insert_before) {
-            e = ap_bucket_create_transient(ctx->buf, ctx->cnt);
             AP_BUCKET_INSERT_BEFORE(e, insert_before);
             AP_BUCKET_REMOVE(insert_before);
             ap_bucket_destroy(insert_before);
@@ -3195,7 +3184,7 @@ static apr_status_t buffer_filter(ap_filter_t *f, ap_bucket_brigade *b)
         if (ctx) {
             ctx->cur = ctx->buf;
             ctx->cnt = 0;
-            ctx->avail = FILTER_BUFF_SIZE;
+            ctx->avail = AP_MIN_BYTES_TO_WRITE;
         }
     }
     else {
@@ -3204,7 +3193,7 @@ static apr_status_t buffer_filter(ap_filter_t *f, ap_bucket_brigade *b)
             ap_bucket_destroy(insert_before);
         }
         /* The brigade should be empty now because all the buckets
-         * were coalesced into the buffer_filter buf
+         * were coalesced into the coalesce_filter buf
          */
     }
 
@@ -3215,6 +3204,8 @@ static apr_status_t buffer_filter(ap_filter_t *f, ap_bucket_brigade *b)
  */
 static apr_status_t chunk_filter(ap_filter_t *f, ap_bucket_brigade *b)
 {
+#define ASCII_CRLF  "\015\012"
+#define ASCII_ZERO  "\060"
     ap_bucket_brigade *more = NULL;
     ap_bucket *e;
     apr_status_t rv;
@@ -3233,9 +3224,9 @@ static apr_status_t chunk_filter(ap_filter_t *f, ap_bucket_brigade *b)
            else if (e->length == -1) {
                 /* unknown amount of data (e.g. a pipe) */
                const char *data;
-               apr_ssize_t len;
+               apr_size_t len;
 
-               rv = ap_bucket_read(e, &data, &len, 1);
+               rv = ap_bucket_read(e, &data, &len, AP_BLOCK_READ);
                if (rv != APR_SUCCESS) {
                    return rv;
                }
@@ -3279,6 +3270,7 @@ static apr_status_t chunk_filter(ap_filter_t *f, ap_bucket_brigade *b)
             /* XXX might be nice to have APR_OFF_T_FMT_HEX */
             hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr),
                                    "%qx" CRLF, (apr_uint64_t)bytes);
+            ap_xlate_proto_to_ascii(chunk_hdr, hdr_len);
             e = ap_bucket_create_transient(chunk_hdr, hdr_len);
             AP_BRIGADE_INSERT_HEAD(b, e);
 
@@ -3286,7 +3278,7 @@ static apr_status_t chunk_filter(ap_filter_t *f, ap_bucket_brigade *b)
              * Insert the end-of-chunk CRLF before the EOS bucket, or
              * appended to the brigade
              */
-            e = ap_bucket_create_immortal(CRLF, 2);
+            e = ap_bucket_create_immortal(ASCII_CRLF, 2);
             if (eos != NULL) {
                 AP_BUCKET_INSERT_BEFORE(eos, e);
             }
@@ -3310,7 +3302,7 @@ static apr_status_t chunk_filter(ap_filter_t *f, ap_bucket_brigade *b)
          */
         if (eos != NULL) {
             /* XXX: (2) trailers ... does not yet exist */
-            e = ap_bucket_create_immortal("0" CRLF /* <trailers> */ CRLF, 5);
+            e = ap_bucket_create_immortal(ASCII_ZERO ASCII_CRLF /* <trailers> */ ASCII_CRLF, 5);
             AP_BUCKET_INSERT_BEFORE(eos, e);
         }
 
@@ -3324,20 +3316,13 @@ static apr_status_t chunk_filter(ap_filter_t *f, ap_bucket_brigade *b)
     return APR_SUCCESS;
 }
 
-/* This function only understands a length of AP_GET_ANY_AMOUNT.  It will
- * ignore length values and always return the entire brigade.  This is
- * pretty safe to do, because we know there always needs to be an intervening
- * filter just above this that will only make requests for AP_GET_ANY_AMOUNT
- */
-static int core_input_filter(ap_filter_t *f, ap_bucket_brigade *b, apr_ssize_t length)
+static int core_input_filter(ap_filter_t *f, ap_bucket_brigade *b, ap_input_mode_t mode)
 {
-    apr_socket_t *csock = NULL;
     ap_bucket *e;
     
     if (!f->ctx) {    /* If we haven't passed up the socket yet... */
         f->ctx = (void *)1;
-        ap_bpop_socket(&csock, f->c->client);
-        e = ap_bucket_create_socket(csock);
+        e = ap_bucket_create_socket(f->c->client_socket);
         AP_BRIGADE_INSERT_TAIL(b, e);
         return APR_SUCCESS;
     }
@@ -3358,22 +3343,22 @@ typedef struct CORE_OUTPUT_FILTER_CTX {
     ap_bucket_brigade *b;
 } core_output_filter_ctx_t;
 #define MAX_IOVEC_TO_WRITE 16
-static int core_output_filter(ap_filter_t *f, ap_bucket_brigade *b)
+static apr_status_t core_output_filter(ap_filter_t *f, ap_bucket_brigade *b)
 {
     apr_status_t rv;
     ap_bucket_brigade *more = NULL;
-    apr_ssize_t bytes_sent = 0, nbytes;
+    apr_size_t bytes_sent = 0, nbytes;
     ap_bucket *e;
     conn_rec *c = f->c;
     core_output_filter_ctx_t *ctx = f->ctx;
 
-    apr_ssize_t nvec = 0;
-    apr_ssize_t nvec_trailers= 0;
+    apr_size_t nvec = 0;
+    apr_size_t nvec_trailers= 0;
     struct iovec vec[MAX_IOVEC_TO_WRITE];
     struct iovec vec_trailers[MAX_IOVEC_TO_WRITE];
 
     apr_file_t *fd = NULL;
-    apr_ssize_t flen = 0;
+    apr_size_t flen = 0;
     apr_off_t foffset = 0;
 
     if (ctx == NULL) {
@@ -3386,20 +3371,12 @@ static int core_output_filter(ap_filter_t *f, ap_bucket_brigade *b)
         ctx->b = NULL;
     }
 
-    /* Hijack any bytes in BUFF and prepend it to the brigade. */
-    if (c->client->outcnt) {
-        e = ap_bucket_create_heap(c->client->outbase,
-                                  c->client->outcnt, 1, NULL);
-        c->client->outcnt = 0;
-        AP_BRIGADE_INSERT_HEAD(b, e);
-    }
-
     /* Iterate over the brigade collecting iovecs */
     while (b) {
         nbytes = 0; /* in case more points to another brigade */
         more = NULL;
         AP_BRIGADE_FOREACH(e, b) {
-            if (AP_BUCKET_IS_EOS(e)) {
+            if (AP_BUCKET_IS_EOS(e) || AP_BUCKET_IS_FLUSH(e)) {
                 break;
             }
             else if (AP_BUCKET_IS_FILE(e)) {
@@ -3411,8 +3388,8 @@ static int core_output_filter(ap_filter_t *f, ap_bucket_brigade *b)
             }
             else {
                 const char *str;
-                apr_ssize_t n;
-                rv = ap_bucket_read(e, &str, &n, 0);
+                apr_size_t n;
+                rv = ap_bucket_read(e, &str, &n, AP_BLOCK_READ);
                 if (n) {
                     nbytes += n;
                     if (!fd) {
@@ -3441,7 +3418,17 @@ static int core_output_filter(ap_filter_t *f, ap_bucket_brigade *b)
         /* Completed iterating over the brigades, now determine if we want to
          * buffer the brigade or send the brigade out on the network
          */
-        if (!fd && (!more) && (nbytes < MIN_SIZE_TO_WRITE) && !AP_BUCKET_IS_EOS(e) && !AP_BUCKET_IS_FLUSH(e)) {
+        if ((!fd && (!more) && (nbytes < AP_MIN_BYTES_TO_WRITE) && !AP_BUCKET_IS_FLUSH(e))
+            || (AP_BUCKET_IS_EOS(e) && c->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 (AP_BUCKET_IS_EOS(e)) {
+                AP_BUCKET_REMOVE(e);
+                ap_bucket_destroy(e);
+            }
             ap_save_brigade(f, &ctx->b, &b);
             return APR_SUCCESS;
         }
@@ -3465,14 +3452,15 @@ static int core_output_filter(ap_filter_t *f, ap_bucket_brigade *b)
                 /* Prepare the socket to be reused */
                 flags |= APR_SENDFILE_DISCONNECT_SOCKET;
             }
-            nbytes = flen;
-            rv = apr_sendfile(c->client->bsock, 
-                              fd,       /* The file to send */
-                              &hdtr,    /* Header and trailer iovecs */
-                              &foffset, /* Offset in file to begin sending from */
-                              &nbytes,
-                              flags);
-            bytes_sent = nbytes;
+            rv = sendfile_it_all(c,             /* the connection            */
+                                 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 send_the_file() to
              * loop on apr_read/apr_send to send the file. Our Windows binary 
@@ -3492,7 +3480,7 @@ static int core_output_filter(ap_filter_t *f, ap_bucket_brigade *b)
 #endif
         }
         else {
-            rv = writev_it_all(c->client->bsock
+            rv = writev_it_all(c->client_socket
                                vec, nvec, 
                                nbytes, &bytes_sent);
         }
@@ -3513,12 +3501,6 @@ static int core_output_filter(ap_filter_t *f, ap_bucket_brigade *b)
     return APR_SUCCESS;
 }
 
-static const handler_rec core_handlers[] = {
-{ "*/*", default_handler },
-{ "default-handler", default_handler },
-{ NULL, NULL }
-};
-
 static void core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
 {
     ap_init_bucket_types(pconf);
@@ -3546,9 +3528,9 @@ static void core_insert_filter(request_rec *r)
     core_dir_config *conf = (core_dir_config *)
                             ap_get_module_config(r->per_dir_config,
                                                   &core_module); 
-    char **items = (char **)conf->filters->elts;
+    char **items = (char **)conf->output_filters->elts;
 
-    for (i = 0; i < conf->filters->nelts; i++) {
+    for (i = 0; i < conf->output_filters->nelts; i++) {
         char *foobar = items[i];
         ap_add_output_filter(foobar, NULL, r, r->connection);
     }
@@ -3572,6 +3554,7 @@ static void register_hooks(void)
     ap_hook_http_method(core_method,NULL,NULL,AP_HOOK_REALLY_LAST);
     ap_hook_default_port(core_port,NULL,NULL,AP_HOOK_REALLY_LAST);
     ap_hook_open_logs(core_open_logs,NULL,NULL,AP_HOOK_MIDDLE);
+    ap_hook_handler(default_handler,NULL,NULL,AP_HOOK_REALLY_LAST);
     /* FIXME: I suspect we can eliminate the need for these - Ben */
     ap_hook_type_checker(do_nothing,NULL,NULL,AP_HOOK_REALLY_LAST);
     ap_hook_access_checker(do_nothing,NULL,NULL,AP_HOOK_REALLY_LAST);
@@ -3580,14 +3563,21 @@ static void register_hooks(void)
      * filters
      */
     ap_hook_insert_filter(core_insert_filter, NULL, NULL, AP_HOOK_MIDDLE);
-    ap_register_input_filter("HTTP_IN", http_filter, AP_FTYPE_CONNECTION);
-    ap_register_input_filter("DECHUNK", dechunk_filter, AP_FTYPE_CONNECTION + 1);
-    ap_register_input_filter("CORE_IN", core_input_filter, AP_FTYPE_CONNECTION);
-    ap_register_output_filter("CORE", core_output_filter, AP_FTYPE_CONNECTION + 1);
+
+    ap_register_input_filter("HTTP_IN", ap_http_filter, AP_FTYPE_CONNECTION);
+    ap_register_input_filter("DECHUNK", ap_dechunk_filter, AP_FTYPE_TRANSCODE);
+    ap_register_input_filter("CORE_IN", core_input_filter, AP_FTYPE_NETWORK);
+    ap_register_output_filter("HTTP_HEADER", ap_http_header_filter, 
+                              AP_FTYPE_HTTP_HEADER);
+    ap_register_output_filter("CONTENT_LENGTH", ap_content_length_filter, 
+                              AP_FTYPE_HTTP_HEADER);
+    ap_register_output_filter("BYTERANGE", ap_byterange_filter, 
+                              AP_FTYPE_HTTP_HEADER);
+    ap_register_output_filter("CORE", core_output_filter, AP_FTYPE_NETWORK);
     ap_register_output_filter("SUBREQ_CORE", ap_sub_req_output_filter, 
                               AP_FTYPE_CONTENT);
-    ap_register_output_filter("CHUNK", chunk_filter, AP_FTYPE_CONNECTION);
-    ap_register_output_filter("BUFFER", buffer_filter, AP_FTYPE_CONNECTION);
+    ap_register_output_filter("CHUNK", chunk_filter, AP_FTYPE_TRANSCODE);
+    ap_register_output_filter("COALESCE", coalesce_filter, AP_FTYPE_CONTENT);
 }
 
 AP_DECLARE_DATA module core_module = {
@@ -3597,6 +3587,5 @@ AP_DECLARE_DATA module core_module = {
     create_core_server_config, /* create per-server config structure */
     merge_core_server_configs, /* merge per-server config structures */
     core_cmds,                 /* command apr_table_t */
-    core_handlers,             /* handlers */
     register_hooks             /* register hooks */
 };