about summary refs log tree commit homepage
path: root/lib
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2016-03-07 08:10:54 +0000
committerEric Wong <e@80x24.org>2016-04-05 18:58:27 +0000
commit4e49ab58f0ea6b32e9610a990c5bfe21900dc73b (patch)
tree8572c4ffa2c7c4a9047611c5330190297029c41e /lib
parent541b8a4e14c471d4746bfda597691155dae0f960 (diff)
downloadpublic-inbox-4e49ab58f0ea6b32e9610a990c5bfe21900dc73b.tar.gz
We broke this fallback when we became more callback driven
and a test will come in the next commit.

However, our dumb cloning is still subject to scheduling
monopolization when serving gigantic packs.  Scheduling
will be fixed at a later time.

Fixes: b44af5d8f2fb ("git-http-backend: start refactoring to use callback")
Diffstat (limited to 'lib')
-rw-r--r--lib/PublicInbox/GitHTTPBackend.pm36
1 files changed, 28 insertions, 8 deletions
diff --git a/lib/PublicInbox/GitHTTPBackend.pm b/lib/PublicInbox/GitHTTPBackend.pm
index 50bb4331..989dac7f 100644
--- a/lib/PublicInbox/GitHTTPBackend.pm
+++ b/lib/PublicInbox/GitHTTPBackend.pm
@@ -34,8 +34,15 @@ sub serve {
         if ($service =~ /\Agit-\w+-pack\z/ || $path =~ /\Agit-\w+-pack\z/) {
                 my $ok = serve_smart($cgi, $git, $path);
                 return $ok if $ok;
+                # fall through to dumb HTTP...
         }
+        serve_dumb($cgi, $git, $path);
+}
+
+sub serve_dumb {
+        my ($cgi, $git, $path) = @_;
 
+        # serve dumb HTTP...
         my $type;
         if ($path =~ /\A(?:$BIN)\z/o) {
                 $type = 'application/octet-stream';
@@ -123,7 +130,6 @@ sub prepare_range {
         ($code, $len);
 }
 
-# returns undef if 403 so it falls back to dumb HTTP
 sub serve_smart {
         my ($cgi, $git, $path) = @_;
         my $env = $cgi->{env};
@@ -158,7 +164,8 @@ sub serve_smart {
         my $git_dir = $git->{git_dir};
         $env{GIT_HTTP_EXPORT_ALL} = '1';
         $env{PATH_TRANSLATED} = "$git_dir/$path";
-        my %rdr = ( 0 => fileno($in), 1 => fileno($wpipe) );
+        my %rdr = ( 0 => fileno($in), 1 => fileno($wpipe),
+                        2 => $git->err_begin );
         my $pid = spawn([qw(git http-backend)], \%env, \%rdr);
         unless (defined $pid) {
                 $err->print("error spawning: $!\n");
@@ -202,7 +209,8 @@ sub serve_smart {
                 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
+                } elsif (defined $res && $buf =~ s/\A(.*?)\r\n\r\n//s) {
+                        # parse headers
                         my $h = $1;
                         my $code = 200;
                         my @h;
@@ -214,11 +222,23 @@ sub serve_smart {
                                         push @h, $k, $v;
                                 }
                         }
-                        # write response header:
-                        $fh = $res->([ $code, \@h ]);
-                        $res = undef;
-                        $fh->write($buf);
-                        $buf = '';
+                        # incredibly convoluted, ugh...
+                        if ($code == 403) {
+                                my $d = serve_dumb($cgi, $git, $path);
+                                if (ref($d) eq 'ARRAY') { # 404
+                                        $res->($d);
+                                } else {
+                                        $d->($res);
+                                }
+                                $res = undef;
+                                $end->();
+                        } else {
+                                # write response header:
+                                $fh = $res->([ $code, \@h ]);
+                                $res = undef;
+                                $fh->write($buf);
+                                $buf = '';
+                        }
                 } # else { keep reading ... }
         };
         if (my $async = $env->{'pi-httpd.async'}) {