]> granicus.if.org Git - apache/commitdiff
Add partial write support for apr_sendfile to core_output_filter.
authorGreg Ames <gregames@apache.org>
Mon, 20 Nov 2000 22:39:17 +0000 (22:39 +0000)
committerGreg Ames <gregames@apache.org>
Mon, 20 Nov 2000 22:39:17 +0000 (22:39 +0000)
Big .jpg's ( >70K or so) were being truncated on Linux.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@87041 13f79535-47bb-0310-9956-ffa450edef68

modules/http/http_core.c

index 62539738bc0eb80d26f2f2b4e5f5cde38b8240c5..ffcf660fbeea3838df46ed94e50ea908d02306ae 100644 (file)
@@ -2564,6 +2564,85 @@ 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_ssize_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 {
+                hdtr->headers[0].iov_len -= tmplen;
+       (char *) hdtr->headers[0].iov_base += tmplen;
+                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 {
+                hdtr->trailers[0].iov_len -= tmplen;
+        (char *)hdtr->trailers[0].iov_base += tmplen;
+                tmplen = 0;
+            }
+        }
+    } while (1);
+}
+#endif
+        
 /*
  * send_the_file()
  * Sends the contents of file fd along with header/trailer bytes, if any,
@@ -3341,14 +3420,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