You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by "Roy T. Fielding" <fi...@kiwi.ics.uci.edu> on 1999/03/07 17:31:49 UTC

[PATCH] always ignore SIGPIPE

>I'd be interested in hearing if I have missed some easier solution to
>the problem and/or if there are plans to ignore SIGPIPE in Apache and
>in what version number that might happen.

This has been on my list of things to do for a long time, so here
is a patch to do it.  Since this is a touchy change, I'll wait for
some votes before committing.

....Roy


Index: main/http_main.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/main/http_main.c,v
retrieving revision 1.424
diff -u -r1.424 http_main.c
--- http_main.c	1999/02/22 16:50:25	1.424
+++ http_main.c	1999/03/07 16:27:25
@@ -1021,10 +1021,9 @@
 static APACHE_TLS int volatile alarm_pending = 0;
 
 static void timeout(int sig)
-{				/* Also called on SIGPIPE */
+{
     void *dirconf;
 
-    signal(SIGPIPE, SIG_IGN);	/* Block SIGPIPE */
     if (alarms_blocked) {
 	alarm_pending = 1;
 	return;
@@ -1042,20 +1041,10 @@
     else
 	dirconf = current_conn->server->lookup_defaults;
     if (!current_conn->keptalive) {
-	if (sig == SIGPIPE) {
-	    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO,
-			current_conn->server,
-			"[client %s] stopped connection before %s completed",
-			current_conn->remote_ip,
-			timeout_name ? timeout_name : "request");
-	}
-	else {
-	    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO,
-			current_conn->server,
-			"[client %s] %s timed out",
-			current_conn->remote_ip,
-			timeout_name ? timeout_name : "request");
-	}
+	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO,
+		     current_conn->server, "[client %s] %s timed out",
+		     current_conn->remote_ip,
+		     timeout_name ? timeout_name : "request");
     }
 
     if (timeout_req) {
@@ -2757,6 +2746,11 @@
     if (sigaction(SIGXFSZ, &sa, NULL) < 0)
 	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGXFSZ)");
 #endif
+#ifdef SIGPIPE
+    sa.sa_handler = SIG_IGN;
+    if (sigaction(SIGPIPE, &sa, NULL) < 0)
+	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGPIPE)");
+#endif
 
     /* we want to ignore HUPs and USR1 while we're busy processing one */
     sigaddset(&sa.sa_mask, SIGHUP);
@@ -2796,6 +2790,10 @@
 #ifdef SIGUSR1
     signal(SIGUSR1, restart);
 #endif /* SIGUSR1 */
+#ifdef SIGPIPE
+    signal(SIGPIPE, SIG_IGN);
+#endif /* SIGPIPE */
+
 #endif
 }
 
@@ -3578,8 +3576,7 @@
     (void) ap_update_child_status(my_child_num, SERVER_READY, (request_rec *) NULL);
 
     /*
-     * Setup the jump buffers so that we can return here after
-     * a signal or a timeout (yeah, I know, same thing).
+     * Setup the jump buffers so that we can return here after a timeout 
      */
     ap_setjmp(jmpbuffer);
 #ifndef OS2
@@ -3587,7 +3584,6 @@
     signal(SIGURG, timeout);
 #endif
 #endif
-    signal(SIGPIPE, timeout);
     signal(SIGALRM, alrm_handler);
 
 #ifdef OS2
@@ -4907,8 +4903,7 @@
     (void) ap_update_child_status(child_num, SERVER_READY, (request_rec *) NULL);
 
     /*
-     * Setup the jump buffers so that we can return here after
-     * a signal or a timeout (yeah, I know, same thing).
+     * Setup the jump buffers so that we can return here after a timeout.
      */
 #if defined(USE_LONGJMP)
     setjmp(jmpbuffer);
@@ -4927,16 +4922,14 @@
 	 * (Re)initialize this child to a pre-connection state.
 	 */
 
-	ap_set_callback_and_alarm(NULL, 0);	/* Cancel any outstanding alarms. */
-	timeout_req = NULL;	/* No request in progress */
+	ap_set_callback_and_alarm(NULL, 0); /* Cancel any outstanding alarms */
+	timeout_req = NULL;                 /* No request in progress */
 	current_conn = NULL;
-#ifdef SIGPIPE
-	signal(SIGPIPE, timeout);
-#endif
 
 	ap_clear_pool(ptrans);
 
-	(void) ap_update_child_status(child_num, SERVER_READY, (request_rec *) NULL);
+	(void) ap_update_child_status(child_num, SERVER_READY,
+	                              (request_rec *) NULL);
 
 	/* Get job from the job list. This will block until a job is ready.
 	 * If -1 is returned then the main thread wants us to exit.
Index: modules/proxy/proxy_http.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/modules/proxy/proxy_http.c,v
retrieving revision 1.62
diff -u -r1.62 proxy_http.c
--- proxy_http.c	1999/02/07 20:48:32	1.62
+++ proxy_http.c	1999/03/07 16:27:26
@@ -352,7 +352,7 @@
     }
 
     ap_bputs(CRLF, f);
-/* send the request data, if any. N.B. should we trap SIGPIPE ? */
+/* send the request data, if any. */
 
     if (ap_should_client_block(r)) {
 	while ((i = ap_get_client_block(r, buffer, sizeof buffer)) > 0)
Index: modules/standard/mod_cgi.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/modules/standard/mod_cgi.c,v
retrieving revision 1.88
diff -u -r1.88 mod_cgi.c
--- mod_cgi.c	1999/01/01 19:05:08	1.88
+++ mod_cgi.c	1999/03/07 16:27:26
@@ -440,16 +440,10 @@
     }
 
     /* Transfer any put/post args, CERN style...
-     * Note that if a buggy script fails to read everything we throw
-     * at it, or a buggy client sends too much, we get a SIGPIPE, so
-     * we have to ignore SIGPIPE while doing this.  CERN does the same
-     * (and in fact, they pretty nearly guarantee themselves a SIGPIPE
-     * on every invocation by chasing the real client data with a
-     * spurious newline).
+     * Note that we already ignore SIGPIPE in the core server.
      */
 
     if (ap_should_client_block(r)) {
-	void (*handler) (int);
 	int dbsize, len_read;
 
 	if (conf->logname) {
@@ -458,9 +452,6 @@
 	}
 
 	ap_hard_timeout("copy script args", r);
-#ifdef SIGPIPE
-	handler = signal(SIGPIPE, SIG_IGN);
-#endif
 
 	while ((len_read =
 		ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN)) > 0) {
@@ -485,7 +476,6 @@
 	}
 
 	ap_bflush(script_out);
-	signal(SIGPIPE, handler);
 
 	ap_kill_timeout(r);
     }

Re: [PATCH] always ignore SIGPIPE

Posted by "Frank D. Cringle" <fd...@cliwe.ping.de>.
"Roy T. Fielding" <fi...@kiwi.ics.uci.edu> writes:
> >I'd be interested in hearing if I have missed some easier solution to
> >the problem and/or if there are plans to ignore SIGPIPE in Apache and
> >in what version number that might happen.
> 
> This has been on my list of things to do for a long time, so here
> is a patch to do it.  Since this is a touchy change, I'll wait for
> some votes before committing.

I tried out this patch with a mod_perl script that produces output
slowly, so that I can abort the connection before it completes.
r->connection->aborted did not get set and the script continued to
run, oblivious of the fact that its output was going nowhere.

Most callers of ap_bwrite() in http_protocol.c check that the write
was successful and set r->connection->aborted if not.  mod_perl's
writes go via ap_rwrite(), and that routine does not check the
return value from ap_bwrite().  It does pass it up to the caller, but
mod_perl does not does not make the information available as a
success/failure return value to callers of its Apache::print method.

I would suggest that r->connection->aborted should be set if the
ap_bwrite() call in ap_rwrite() fails.  Also, Apache::print should
return 1/0 instead of undef and mod_perl should provide an option to
automatically kill the script if a print fails (further discussion of
these latter 2 points on the mod_perl list).

-- 
Frank Cringle,      fdc@cliwe.ping.de
voice: (+49 2304) 467101; fax: 943357

Re: [PATCH] always ignore SIGPIPE

Posted by Dean Gaudet <dg...@arctic.org>.

On Sun, 7 Mar 1999, Roy T. Fielding wrote:

> >I'd be interested in hearing if I have missed some easier solution to
> >the problem and/or if there are plans to ignore SIGPIPE in Apache and
> >in what version number that might happen.
> 
> This has been on my list of things to do for a long time, so here
> is a patch to do it.  Since this is a touchy change, I'll wait for
> some votes before committing.

+1 on concept -- it's been something I was thinking about too. 

Dean