about summary refs log tree commit homepage
path: root/lib
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2016-02-25 04:02:36 +0000
committerEric Wong <e@80x24.org>2016-02-25 04:03:08 +0000
commitb44af5d8f2fb106bee9b4720bcf92aed7851bfa8 (patch)
tree566669f3c786cbe8465cb6fba063ad267bd5afd7 /lib
parentda55b58b7205de38c466aca2d452ef67677f1753 (diff)
downloadpublic-inbox-b44af5d8f2fb106bee9b4720bcf92aed7851bfa8.tar.gz
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...
Diffstat (limited to 'lib')
-rw-r--r--lib/PublicInbox/GitHTTPBackend.pm73
1 files changed, 47 insertions, 26 deletions
diff --git a/lib/PublicInbox/GitHTTPBackend.pm b/lib/PublicInbox/GitHTTPBackend.pm
index cba025e7..3cf78579 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;