Ok, here's a patch for trunk that works with all test cases. I've put in
most of the changes from wrowe's patch at
http://people.apache.org/~wrowe/working.patch as well.
>From what I can gather on the OS X man page (yay weasel-words! now you
can't hold me accountable if I'm wrong), writev() will either send
everything and return the number of bytes sent, or send nothing, return
-1, and set errno. I guess we won't have to deal with incomplete writes
for the headers and trailers.
The only problems I see now are that the code is kind of ugly and
non-blocking I/O sticks in the loop instead of returning right away.
Geoff
Index: sendrecv.c
===================================================================
--- sendrecv.c (revision 651698)
+++ sendrecv.c (working copy)
@@ -413,7 +413,8 @@
apr_off_t nbytes = 0;
apr_off_t bytes_to_send = *len;
apr_size_t header_bytes_written = 0;
- int rv;
+ int rv = 0;
+ int sent_headers = 0;
/* Ignore flags for now. */
flags = 0;
@@ -436,17 +437,24 @@
return arv;
}
}
-
- if (hdtr->numheaders) {
- rv = writev(sock->socketdes,
- hdtr->headers,
- hdtr->numheaders);
- if (rv > 0) {
- header_bytes_written = rv;
- rv = 0;
+
+ if (!sent_headers) {
+ if (hdtr->numheaders) {
+ rv = writev(sock->socketdes,
+ hdtr->headers,
+ hdtr->numheaders);
+ if (rv > 0) {
+ header_bytes_written = rv;
+ sent_headers = 1;
+ rv = 0;
+ }
}
+ else {
+ sent_headers = 1;
+ }
}
- else if (bytes_to_send) {
+
+ if (bytes_to_send && sent_headers) {
/* We won't dare call sendfile() if we don't have
* header or file bytes to send because nbytes == 0
* means send the remaining file to EOF.
@@ -464,12 +472,13 @@
if (errno == EAGAIN) {
if (sock->timeout > 0) {
sock->options |= APR_INCOMPLETE_WRITE;
+ rv = 0;
}
/* BSD's sendfile can return -1/EAGAIN even if it
* sent bytes. Sanitize the result so we get normal EAGAIN
* semantics w.r.t. bytes sent.
*/
- if (nbytes) {
+ else if (nbytes) {
/* normal exit for a big file & non-blocking io */
(*len) = nbytes + header_bytes_written;
return APR_SUCCESS;
@@ -486,27 +495,21 @@
}
}
}
- else {
+
+ if (sent_headers && !bytes_to_send) {
/* just trailer bytes... use writev()
*/
rv = writev(sock->socketdes,
hdtr->trailers,
hdtr->numtrailers);
if (rv > 0) {
- nbytes = rv;
+ nbytes += rv;
rv = 0;
}
- else {
- nbytes = 0;
- }
}
- if ((rv == -1) && (errno == EAGAIN)
- && (sock->timeout > 0)) {
- apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0);
- if (arv != APR_SUCCESS) {
- *len = 0;
- return arv;
- }
+
+ if ((rv == -1) && (errno == EAGAIN) && (sock->timeout > 0)) {
+ sock->options |= APR_INCOMPLETE_WRITE;
}
} while (rv == -1 && (errno == EINTR || errno == EAGAIN));