From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-2.8 required=3.0 tests=ALL_TRUSTED,AWL,BAYES_00 shortcircuit=no autolearn=unavailable version=3.3.2 X-Original-To: meta@public-inbox.org Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 0F64D63381C for ; Thu, 25 Feb 2016 04:02:42 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 2/3] git-http-backend: start refactoring to use callback Date: Thu, 25 Feb 2016 04:02:36 +0000 Message-Id: <20160225040237.29014-3-e@80x24.org> In-Reply-To: <20160225040237.29014-1-e@80x24.org> References: <20160225040237.29014-1-e@80x24.org> List-Id: Designing for asynchronous, non-blocking operations makes adapting for synchronous, blocking operation easy. Going the other way around is not easy, so do it now and allow us to be more easily adapted for non-blocking use in the next commit... --- lib/PublicInbox/GitHTTPBackend.pm | 73 +++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/lib/PublicInbox/GitHTTPBackend.pm b/lib/PublicInbox/GitHTTPBackend.pm index cba025e..3cf7857 100644 --- a/lib/PublicInbox/GitHTTPBackend.pm +++ b/lib/PublicInbox/GitHTTPBackend.pm @@ -178,34 +178,55 @@ sub serve_smart { my @cmd = qw(git http-backend); exec(@cmd) or die 'exec `' . join(' ', @cmd). "' failed: $!\n"; } - $wpipe = undef; - $in = undef; - my @h; - my $code = 200; - { - local $/ = "\r\n"; - while (defined(my $line = <$rpipe>)) { - if ($line =~ /\AStatus:\s*(\d+)/) { - $code = $1; - } else { - chomp $line; - last if $line eq ''; - push @h, split(/:\s*/, $line, 2); - } + $wpipe = $in = undef; + $rpipe->blocking(0); + $buf = ''; + my $vin; + vec($vin, fileno($rpipe), 1) = 1; + my ($fh, $res); + my $fail = sub { + my ($e) = @_; + if ($e eq 'EAGAIN') { + select($vin, undef, undef, undef); + } else { + $rpipe = undef; + $fh->close if $fh; + $err->print('git http-backend error: ', $e, "\n"); } - } - return if $code == 403; - sub { - my ($cb) = @_; - my $fh = $cb->([ $code, \@h ]); - while (1) { - my $r = sysread($rpipe, $buf, 8192); - die "$!\n" unless defined $r; - last if ($r == 0); - $fh->write($buf); + }; + my $cb = sub { + my $r = sysread($rpipe, $buf, 8192, length($buf)); + return $fail->($!{EAGAIN} ? 'EAGAIN' : $!) unless defined $r; + if ($r == 0) { # EOF + $rpipe = undef; + $fh->close if $fh; + return; } - $fh->close; - } + if ($fh) { # stream body from git-http-backend to HTTP client + $fh->write($buf); + $buf = ''; + } elsif ($buf =~ s/\A(.*?)\r?\n\r?\n//s) { # parse headers + my $h = $1; + my $code = 200; + my @h; + foreach my $l (split(/\r?\n/, $h)) { + my ($k, $v) = split(/:\s*/, $l, 2); + if ($k =~ /\AStatus\z/i) { + $code = int($v); + } else { + push @h, $k, $v; + } + } + # write response header: + $fh = $res->([ $code, \@h ]); + $fh->write($buf); + $buf = ''; + } # else { keep reading ... } + }; + sub { + ($res) = @_; + while ($rpipe) { $cb->() } + }; } 1; -- EW