]> git.ipfire.org Git - thirdparty/public-inbox.git/commitdiff
repoobrowse: explicit EOF handling for git async callback
authorEric Wong <e@80x24.org>
Sat, 4 Mar 2017 03:52:29 +0000 (03:52 +0000)
committerEric Wong <e@80x24.org>
Sat, 4 Mar 2017 03:52:29 +0000 (03:52 +0000)
We need to ensure we've fully-drained the pipe before
signalling EOF to the callback, since pipelining may
not be the best choice with detachable processes
in the future.

lib/PublicInbox/Git.pm
lib/PublicInbox/GitAsync.pm
lib/PublicInbox/RepoGitRaw.pm
lib/PublicInbox/RepoGitSrc.pm
t/git_async.t

index 6a7b109f11d7deb0a1f7f90e3551f87772c22bb3..893df71eb2b3ccb4a6b19c8822ba2c963377e69f 100644 (file)
@@ -253,10 +253,10 @@ sub cat_async_compat ($$$) {
        $self->{out}->print($obj."\n") or fail($self, "write error: $!");
        my $in = $self->{in};
        my $info = async_info_compat($in);
+       my (undef, $type, $left) = @$info;
        $cb->($info);
-       return if scalar(@$info) != 3; # missing
+       return if $info->[1] eq 'missing';
        my $max = 8192;
-       my $left = $info->[2];
        my ($buf, $r);
        while ($left > 0) {
                $r = read($in, $buf, $left > $max ? $max : $left);
@@ -267,6 +267,7 @@ sub cat_async_compat ($$$) {
        $r = read($in, $buf, 1);
        defined($r) or fail($self, "read failed: $!");
        fail($self, 'newline missing after blob') if ($r != 1 || $buf ne "\n");
+       $cb->(0);
 }
 
 sub check_async {
index 8369978c3356383ea92cf9ff552738c007b47bae..24e0bf3bdeda541274ced9d314bfeb8641439372 100644 (file)
@@ -65,7 +65,7 @@ take_job:
                }
                $cb->($info); # $info may 0 (EOF, or undef, $cb will see $!)
                return $self->close unless $info;
-               if ($check || (scalar(@$info) != 3)) {
+               if ($check || $info->[1] eq 'missing') {
                        # do not monopolize the event loop if we're drained:
                        return if ${$self->{rbuf}} eq '';
                        goto take_job;
@@ -89,6 +89,7 @@ final_hunk:
                my $lf = chop $$rbuf;
                $lf eq "\n" or die "BUG: missing LF (got $lf)";
                $cb->($rbuf);
+               $cb->(0);
 
                return if $buf eq '';
                goto take_job;
index 858034a37b1113a2223821f2b08ef39d1d947146..717ca71fdde89a280c255a9da2bc74cc04a99beb 100644 (file)
@@ -36,15 +36,17 @@ sub git_raw_check_res ($$$) {
                my $buf = '';
                $req->{-repo}->{git}->cat_async($req->{env}, $hex, sub {
                        my ($r) = @_;
-                       return if ref($r) ne 'SCALAR';
-                       $buf .= $$r;
-                       return if bytes::length($buf) < $size;
-                       $ct ||= index($buf, "\0") >= 0 ?
-                                       'application/octet-stream' :
-                                       'text/plain; charset=UTF-8';
-                       $res->([200, ['Content-Type', $ct,
-                                       'Content-Length', $size ],
-                               [ $buf ]]);
+                       if (ref($r) eq 'SCALAR') {
+                               $buf .= $$r;
+                       } elsif ($r == 0) {
+                               return if bytes::length($buf) < $size;
+                               $ct ||= index($buf, "\0") >= 0 ?
+                                               'application/octet-stream' :
+                                               'text/plain; charset=UTF-8';
+                               $res->([200, ['Content-Type', $ct,
+                                               'Content-Length', $size ],
+                                       [ $buf ]]);
+                       }
                });
        }
 }
index 67de86ee8888063cd4e86b31569489c8e99f42a5..5104877302679a000b44ee7c0700336fd68c999b 100644 (file)
@@ -154,18 +154,17 @@ sub git_blob_show {
                return if $ref eq 'ARRAY'; # redundant info
                if ($ref eq 'SCALAR') {
                        $buf .= $$r;
-                       if (bytes::length($buf) == $size) {
-                               my $fh = $res->($self->rt(200, 'html'));
-                               my $sed = git_blob_sed($req, $hex, $size);
-                               $fh->write($sed->($buf));
-                               $fh->write($sed->(undef));
-                               $fh->close;
-                       }
-                       return;
+               } elsif (!defined $r) {
+                       my $cb = $res or return;
+                       $res = undef;
+                       $cb->($self->rt(500, 'plain', "Error\n"));
+               } elsif ($r == 0) {
+                       my $fh = $res->($self->rt(200, 'html'));
+                       my $sed = git_blob_sed($req, $hex, $size);
+                       $fh->write($sed->($buf));
+                       $fh->write($sed->(undef));
+                       $fh->close;
                }
-               my $cb = $res or return;
-               $res = undef;
-               $cb->($self->rt(500, 'plain', "Error\n"));
        });
 }
 
index 4f7e4ebe9ba67a1339d7653f4cd672156ce8d106..ffe2b1a262ecee39c72ce92fcf0e9a989e2c727e 100644 (file)
@@ -117,6 +117,7 @@ my $dir = "$tmpdir/git.git";
        }
        my @info;
        my $str = '';
+       my $eof_seen = 0;
        $git->cat_async_compat('HEAD:foo.txt', sub {
                my $ref = $_[0];
                my $t = ref $ref;
@@ -124,10 +125,13 @@ my $dir = "$tmpdir/git.git";
                        push @info, $ref;
                } elsif ($t eq 'SCALAR') {
                        $str .= $$ref;
+               } elsif ($ref == 0) {
+                       $eof_seen++;
                } else {
                        fail "fail type: $t";
                }
        });
+       is($eof_seen, 1, 'EOF seen once');
        is_deeply(\@info, [ [ 'bf4f17855632367a160bef055fc8ba4675d10e6b',
                               'blob', 18 ]], 'info matches compat');
        is($str, "-----\nhello\nworld\n", 'data matches compat');