Permalink
Browse files

RT #54183: Provide handling of SIGPIPE when sending the response to t…

…he client,

in case they've terminated the connection.
  • Loading branch information...
1 parent b234042 commit 984e381b2ec9e56896c4d35d6eb9f3e68c11629c @rjray rjray committed Feb 9, 2010
Showing with 88 additions and 2 deletions.
  1. +11 −2 lib/RPC/XML/Server.pm
  2. +77 −0 t/90_rt54183_sigpipe.t
View
@@ -1675,7 +1675,7 @@ sub process_request
$peeraddr = $conn->peeraddr;
$peerport = $conn->peerport;
$peerhost = $conn->peerhost;
- while ($req = $conn->get_request('headers only'))
+ while ($conn and $req = $conn->get_request('headers only'))
{
if ($req->method eq 'HEAD')
{
@@ -1923,7 +1923,16 @@ sub process_request
$resp->content_length(length $buf);
}
- $conn->send_response($resp);
+ eval {
+ local $SIG{PIPE} = sub { die "Caught SIGPIPE\n"; };
+ $conn->send_response($resp);
+ };
+ if ($@ and $@ =~ /Caught SIGPIPE/)
+ {
+ # Client disconnected, maybe even before we started sending
+ # our response. Either way, $conn is useless now.
+ undef $conn;
+ }
undef $resp;
}
else
@@ -0,0 +1,77 @@
+#!/usr/bin/perl
+
+# http://rt.cpan.org/Ticket/Display.html?id=54183
+#
+# Test that the RPC::XML::Server class can handle SIGPIPE issues
+
+use strict;
+use vars qw($dir $vol $srv $child $port $cli $res);
+use subs qw(start_server stop_server find_port);
+
+use Test::More;
+
+require File::Spec;
+
+require RPC::XML::Server;
+require RPC::XML::Client;
+
+($vol, $dir, undef) = File::Spec->splitpath(File::Spec->rel2abs($0));
+$dir = File::Spec->catpath($vol, $dir, '');
+require File::Spec->catfile($dir, 'util.pl');
+
+if (($port = find_port) == -1)
+{
+ plan skip_all => "No usable port found between 9000 and 10000";
+ exit;
+}
+else
+{
+ plan tests => 4;
+}
+
+$cli = RPC::XML::Client->new("http://localhost:$port");
+
+$srv = RPC::XML::Server->new(host => 'localhost', port => $port);
+$srv->add_method({
+ name => 'test',
+ signature => [ 'string' ],
+ code => sub {
+ my ($server) = @_;
+
+ sleep 3;
+
+ return 'foo';
+ }
+ });
+$child = start_server($srv);
+
+eval {
+ local $SIG{ALRM} = sub { die "alarm\n" };
+ alarm(1);
+ $res = $cli->send_request('test');
+ alarm(0); # Shouldn't reach here
+};
+like($res, qr/alarm/, 'Initial request alarmed-out correctly');
+
+eval {
+ local $SIG{ALRM} = sub { die "alarm\n" };
+ alarm(6);
+ $res = $cli->send_request('test');
+ alarm(0); # Shouldn't reach here
+};
+unlike($res, qr/alarm/, 'Second request did not alarm-out');
+
+ok(ref($res) && $res->value eq 'foo', 'Second request correct value');
+
+eval {
+ local $SIG{ALRM} = sub { die "alarm\n" };
+ alarm(2);
+ $res = $cli->send_request('system.status');
+ alarm(0);
+};
+ok(ref($res) && ref($res->value) eq 'HASH',
+ 'Good system.status return');
+
+stop_server($child);
+
+exit;

0 comments on commit 984e381

Please sign in to comment.