"Roy T. Fielding" <[EMAIL PROTECTED]> writes:

> > I'm sure there's a great reason for setting B_EOUT flag here, but it
> > sure does suck if you have data waiting to be sent to the client since
> > setting B_EOUT convinces ap_bclose() not to write any more data.
> 
> It is only set when the connection is aborted or the fd is gone,
> both indicating that we can't write any more data.  I think you
> need to figure out why the conditional above it is false and
> then fix the root of the problem.  My guess is that
> 
>    r->connection->aborted
> 
> is being set incorrectly somewhere.

r->connection->aborted isn't being set.

We skip the lingering close path and because ap_read_request() returns
NULL (i.e., r is NULL when we see whether to do lingering close).  But
current_conn is still valid and current_conn->aborted isn't set.

  The client is doing this:

  write lastfd "GET /silly?send_chunks HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n"
  shutdown lastfd 1
  read the response

Here is how Apache interacts with this client:

read(3, "GET /silly?send_chunks HTTP/1.1\r"..., 4096) = 52
write(3, "HTTP/1.1 200 OK\r\nDate: Sat, 19 O"..., 152) = 152
writev(3, [{"1400f\r\n", 7}, {"IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII"...,
       81935}, {"\r\n", 2}], 3) = 81944
write(3, "1  \r\nI\r\n", 8)             = 8
select(4, [3], NULL, NULL, {0, 0})      = 1 (in [3], left {0, 0})
select(4, [3], NULL, NULL, {0, 0})      = 1 (in [3], left {0, 0})
read(3, "", 4096)                       = 0
close(3)

Here is another patch which respects the aborted flag and makes a
semi-gratuitous cleanup so that there is only one set of code for
this.

Index: src/main/http_main.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/main/http_main.c,v
retrieving revision 1.594
diff -u -r1.594 http_main.c
--- src/main/http_main.c        1 Oct 2002 14:24:23 -0000       1.594
+++ src/main/http_main.c        19 Oct 2002 11:32:12 -0000
@@ -4178,6 +4178,34 @@
     ap_server_config_defines   = ap_make_array(pcommands, 1, sizeof(char *));
 }
 
+/*
+ * Close the connection, being careful to send out whatever is still
+ * in our buffers.  If possible, try to avoid a hard close until the
+ * client has ACKed our FIN and/or has stopped sending us data.
+ */
+static void close_connection(request_rec *r, BUFF *conn_io, int aborted)
+{
+#ifdef NO_LINGCLOSE
+    ap_bclose(conn_io);        /* just close it */
+#else
+    if (r && r->connection
+        && !r->connection->aborted
+        && r->connection->client
+        && (r->connection->client->fd >= 0)) {
+        lingering_close(r);
+    }
+    else {
+        if (aborted) {
+            /* we've already hit an error doing I/O with client, so
+             * don't try to write any buffered data during ap_bclose()
+             */
+            ap_bsetflag(conn_io, B_EOUT, 1);
+        }
+        ap_bclose(conn_io);
+    }
+#endif /* NO_LINGCLOSE */
+}
+
 #ifndef MULTITHREAD
 /*****************************************************************
  * Child process main loop.
@@ -4646,28 +4674,7 @@
            usr1_just_die = 1;
            signal(SIGUSR1, usr1_handler);
        }
-
-       /*
-        * Close the connection, being careful to send out whatever is still
-        * in our buffers.  If possible, try to avoid a hard close until the
-        * client has ACKed our FIN and/or has stopped sending us data.
-        */
-
-#ifdef NO_LINGCLOSE
-       ap_bclose(conn_io);     /* just close it */
-#else
-       if (r && r->connection
-           && !r->connection->aborted
-           && r->connection->client
-           && (r->connection->client->fd >= 0)) {
-
-           lingering_close(r);
-       }
-       else {
-           ap_bsetflag(conn_io, B_EOUT, 1);
-           ap_bclose(conn_io);
-       }
-#endif
+        close_connection(r, conn_io, current_conn && current_conn->aborted);
     }
 }
 
@@ -5954,28 +5961,8 @@
            ap_sync_scoreboard_image();
        }
 
-       /*
-        * Close the connection, being careful to send out whatever is still
-        * in our buffers.  If possible, try to avoid a hard close until the
-        * client has ACKed our FIN and/or has stopped sending us data.
-        */
        ap_kill_cleanups_for_socket(ptrans, csd);
-
-#ifdef NO_LINGCLOSE
-       ap_bclose(conn_io);     /* just close it */
-#else
-       if (r && r->connection
-           && !r->connection->aborted
-           && r->connection->client
-           && (r->connection->client->fd >= 0)) {
-
-           lingering_close(r);
-       }
-       else {
-           ap_bsetflag(conn_io, B_EOUT, 1);
-           ap_bclose(conn_io);
-       }
-#endif
+        close_connection(r, conn_io, current_conn && current_conn->aborted);
     }
     ap_destroy_pool(ptrans);
     (void) ap_update_child_status(child_num, SERVER_DEAD, NULL);

Thanks for your response!

-- 
Jeff Trawick | [EMAIL PROTECTED]
Born in Roswell... married an alien...

Reply via email to