httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Roy T. Fielding" <field...@kiwi.ICS.UCI.EDU>
Subject [PATCH] Handle write errors when no SIGPIPE
Date Sat, 26 Apr 1997 04:07:21 GMT
In message <199704220637.CAA05677@tripod.tripod.com>, Nathan J Kurz writes:
>One would think that when you pushed Stop on the browser the script
>would get a SIGPIPE and die as soon as a buffer was filled and
>written.  Unfortunately, on Solaris 2.5.1 it doesn't ever get that
>signal.  Even if you press Stop immediately, until the server Timeout
>is reached send_fd_length() keeps trying to throw away input as fast
>as your processor will run:
>
>  PID USERNAME PRI NICE  SIZE   RES STATE   TIME   WCPU    CPU COMMAND
>23864 nate     -25    0 2008K 1680K run     3:27 62.73% 62.73% long_push
>23797 nate     -15    0 1744K 1304K sleep   1:54 35.22% 35.04% httpd
>
>So while Sameer's CGI patch might help in some circumstances, and
>while this is probably a Solaris bug, and while there probably aren't
>many CGI's that work like this, it might be worth revisiting the error
>handling in send_fd_length() when bwrite() returns a -1 and errno is
>not EAGAIN. :)

Nathan's comments caused me to revisit the code that I had stared at
for so long looking for an EPIPE.  I don't know why I missed it the first
time, but the below patch will fix this problem.  Note that it is needed
for all systems, since our current code will silently toss data if an
interim write fails for any reason (very bad).  It will also be a huge
load reducer for sites sending large messages to impatient users.

.....Roy


Index: http_protocol.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_protocol.c,v
retrieving revision 1.116
diff -c -r1.116 http_protocol.c
*** http_protocol.c	1997/04/24 23:35:20	1.116
--- http_protocol.c	1997/04/26 03:57:38
***************
*** 1540,1553 ****
          }
          o=0;
  	total_bytes_sent += n;
! 	
!         while(n && !r->connection->aborted) {
!             w=bwrite(r->connection->client, &buf[o], n);
! 	    if(w <= 0)
! 		break;
! 	    reset_timeout(r); /* reset timeout after successful write */
!             n-=w;
! 	    o+=w;
          }
      }
      
--- 1540,1568 ----
          }
          o=0;
  	total_bytes_sent += n;
! 
!         while (n && !r->connection->aborted) {
!             w = bwrite(r->connection->client, &buf[o], n);
!             if (w > 0) {
!                 reset_timeout(r); /* reset timeout after successful write */
!                 n-=w;
!                 o+=w;
!             }
!             else if (w < 0) {
!                 if (r->connection->aborted)
!                     break;
!                 else if (errno == EAGAIN || errno == EINTR)
!                     continue;
!                 else {
!                     log_unixerr("send body lost connection to",
!                                 get_remote_host(r->connection,
!                                     r->per_dir_config, REMOTE_NAME),
!                                 NULL, r->server);
!                     bsetflag(r->connection->client, B_EOUT, 1);
!                     r->connection->aborted = 1;
!                     break;
!                 }
!             }
          }
      }
      
Index: buff.c
===================================================================
RCS file: /export/home/cvs/apache/src/buff.c,v
retrieving revision 1.24
diff -c -r1.24 buff.c
*** buff.c	1997/04/21 20:29:07	1.24
--- buff.c	1997/04/26 03:57:39
***************
*** 99,109 ****
--- 99,113 ----
  static void
  doerror(BUFF *fb, int err)
  {
+     int errsave = errno;  /* Save errno to prevent overwriting it below */
+ 
      if (err == B_RD)
  	fb->flags |= B_RDERR;
      else
  	fb->flags |= B_WRERR;
      if (fb->error != NULL) (*fb->error)(fb, err, fb->error_data);
+ 
+     errno = errsave;
  }
  
  /* Buffering routines */

Mime
View raw message