about summary refs log tree commit homepage
path: root/lib/PublicInbox/GitHTTPBackend.pm
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2016-02-25 04:02:35 +0000
committerEric Wong <e@80x24.org>2016-02-25 04:03:07 +0000
commitda55b58b7205de38c466aca2d452ef67677f1753 (patch)
tree0bcf24bd5705fd3fad4196431bb4a8e759ff57c2 /lib/PublicInbox/GitHTTPBackend.pm
parent57cbe47ad5e935f5071e37b07c0a2bdcc91beea0 (diff)
downloadpublic-inbox-da55b58b7205de38c466aca2d452ef67677f1753.tar.gz
This allows us to stream the output to the client without buffering
everything up-front.  Next, we'll let Danga::Socket (or AE in the
future) wait for readability.
Diffstat (limited to 'lib/PublicInbox/GitHTTPBackend.pm')
-rw-r--r--lib/PublicInbox/GitHTTPBackend.pm23
1 files changed, 11 insertions, 12 deletions
diff --git a/lib/PublicInbox/GitHTTPBackend.pm b/lib/PublicInbox/GitHTTPBackend.pm
index 562c290e..cba025e7 100644
--- a/lib/PublicInbox/GitHTTPBackend.pm
+++ b/lib/PublicInbox/GitHTTPBackend.pm
@@ -132,9 +132,9 @@ sub serve_smart {
         my $buf;
         my $in;
         my $err = $env->{'psgi.errors'};
-        if (fileno($input) >= 0) { # FIXME untested
+        if (fileno($input) >= 0) {
                 $in = $input;
-        } else {
+        } else { # FIXME untested
                 $in = IO::File->new_tmpfile;
                 while (1) {
                         my $r = $input->read($buf, 8192);
@@ -148,7 +148,11 @@ sub serve_smart {
                 $in->flush;
                 $in->sysseek(0, SEEK_SET);
         }
-        my $out = IO::File->new_tmpfile;
+        my ($rpipe, $wpipe);
+        unless (pipe($rpipe, $wpipe)) {
+                $err->print('error creating pipe', $!, "\n");
+                return r(500);
+        }
         my $pid = fork; # TODO: vfork under Linux...
         unless (defined $pid) {
                 $err->print('error forking: ', $!, "\n");
@@ -170,22 +174,17 @@ sub serve_smart {
                 $ENV{GIT_HTTP_EXPORT_ALL} = '1';
                 $ENV{PATH_TRANSLATED} = "$git->{git_dir}/$path";
                 dup2(fileno($in), 0) or die "redirect stdin failed: $!\n";
-                dup2(fileno($out), 1) or die "redirect stdout failed: $!\n";
+                dup2(fileno($wpipe), 1) or die "redirect stdout failed: $!\n";
                 my @cmd = qw(git http-backend);
                 exec(@cmd) or die 'exec `' . join(' ', @cmd). "' failed: $!\n";
         }
-
-        if (waitpid($pid, 0) != $pid) {
-                $err->print("git http-backend ($git->{git_dir}): ", $?, "\n");
-                return r(500);
-        }
+        $wpipe = undef;
         $in = undef;
-        $out->seek(0, SEEK_SET);
         my @h;
         my $code = 200;
         {
                 local $/ = "\r\n";
-                while (defined(my $line = <$out>)) {
+                while (defined(my $line = <$rpipe>)) {
                         if ($line =~ /\AStatus:\s*(\d+)/) {
                                 $code = $1;
                         } else {
@@ -200,7 +199,7 @@ sub serve_smart {
                 my ($cb) = @_;
                 my $fh = $cb->([ $code, \@h ]);
                 while (1) {
-                        my $r = $out->read($buf, 8192);
+                        my $r = sysread($rpipe, $buf, 8192);
                         die "$!\n" unless defined $r;
                         last if ($r == 0);
                         $fh->write($buf);