]> 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 62539738bc0eb80d26f2f2b4e5f5cde38b8240c5..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_BYTES_TO_WRITE  9000
-
 /* LimitXMLRequestBody handling */
 #define AP_LIMIT_UNSET                  ((long) -1)
 #define AP_DEFAULT_LIMIT_XML_BODY       ((size_t)1000000)
@@ -582,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 */
@@ -593,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;
 }
@@ -631,8 +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)) {
-       if (apr_get_hostname(&conn->remote_host, APR_REMOTE, conn->client_socket)
-            == APR_SUCCESS){
+        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) {
@@ -699,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...
@@ -718,10 +722,14 @@ 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) {
-            if (apr_get_hostname(&conn->local_host, APR_LOCAL, conn->client_socket) != APR_SUCCESS)
+            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
+            else {
                 ap_str_tolower(conn->local_host);
+            }
         }
        return conn->local_host;
     }
@@ -739,8 +747,12 @@ AP_DECLARE(apr_port_t) 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) {
-        if (r->hostname)
-           apr_get_port(&port, APR_LOCAL, r->connection->client_socket);
+        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;
@@ -1181,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);
        }
@@ -1982,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;
@@ -2524,7 +2536,8 @@ 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;
@@ -2564,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,
@@ -2877,8 +2975,7 @@ static int default_handler(request_rec *r)
 {
     ap_bucket_brigade *bb;
     ap_bucket *e;
-    core_dir_config *d =
-           (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
+    core_dir_config *d;
     int errstatus;
     apr_file_t *fd = NULL;
     apr_status_t status;
@@ -2889,8 +2986,22 @@ 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;
+
+    /*
+     * 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);
 
@@ -2930,7 +3041,7 @@ 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");
-    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;
@@ -2980,7 +3091,7 @@ static apr_status_t coalesce_filter(ap_filter_t *f, ap_bucket_brigade *b)
 
     if (ctx == NULL) {
         f->ctx = ctx = apr_pcalloc(p, sizeof(coalesce_filter_ctx_t));
-        ctx->avail = MIN_BYTES_TO_WRITE;
+        ctx->avail = AP_MIN_BYTES_TO_WRITE;
     }
 
     if (ctx->cnt) {
@@ -3010,7 +3121,7 @@ static apr_status_t coalesce_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, MIN_BYTES_TO_WRITE);
+                    ctx->buf = apr_palloc(p, AP_MIN_BYTES_TO_WRITE);
                     ctx->cur = ctx->buf;
                     ctx->cnt = 0;
                 }
@@ -3073,7 +3184,7 @@ static apr_status_t coalesce_filter(ap_filter_t *f, ap_bucket_brigade *b)
         if (ctx) {
             ctx->cur = ctx->buf;
             ctx->cnt = 0;
-            ctx->avail = MIN_BYTES_TO_WRITE;
+            ctx->avail = AP_MIN_BYTES_TO_WRITE;
         }
     }
     else {
@@ -3307,7 +3418,7 @@ static apr_status_t 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_BYTES_TO_WRITE) && !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
@@ -3341,14 +3452,15 @@ static apr_status_t 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_socket, 
-                              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 
@@ -3389,12 +3501,6 @@ static apr_status_t 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);
@@ -3448,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);
@@ -3480,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 */
 };