]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/GitHTTPBackend.pm
Merge remote-tracking branch 'origin/inboxdir'
[public-inbox.git] / lib / PublicInbox / GitHTTPBackend.pm
index 57944a06be1365426cbec24a39d3e6f3ebed55fb..ec8e651699f4d3e521489483e7d337055fd0b75e 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2016-2018 all contributors <meta@public-inbox.org>
+# Copyright (C) 2016-2019 all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 
 # when no endpoints match, fallback to this and serve a static file
@@ -12,6 +12,7 @@ use HTTP::Date qw(time2str);
 use HTTP::Status qw(status_message);
 use Plack::Util;
 use PublicInbox::Qspawn;
+use PublicInbox::Tmpfile;
 
 # 32 is same as the git-daemon connection limit
 my $default_limiter = PublicInbox::Qspawn::Limiter->new(32);
@@ -51,8 +52,8 @@ sub serve {
 
        # Documentation/technical/http-protocol.txt in git.git
        # requires one and exactly one query parameter:
-       if ($env->{QUERY_STRING} =~ /\Aservice=git-\w+-pack\z/ ||
-                               $path =~ /\Agit-\w+-pack\z/) {
+       if ($env->{QUERY_STRING} =~ /\Aservice=git-[A-Za-z0-9_]+-pack\z/ ||
+                               $path =~ /\Agit-[A-Za-z0-9_]+-pack\z/) {
                my $ok = serve_smart($env, $git, $path);
                return $ok if $ok;
        }
@@ -67,7 +68,7 @@ sub err ($@) {
 
 sub drop_client ($) {
        if (my $io = $_[0]->{'psgix.io'}) {
-               $io->close; # this is Danga::Socket::close
+               $io->close; # this is PublicInbox::DS::close
        }
 }
 
@@ -90,7 +91,7 @@ sub static_result ($$$$) {
        my $len = $size;
        my $code = 200;
        push @$h, 'Content-Type', $type;
-       if (($env->{HTTP_RANGE} || '') =~ /\bbytes=(\d*)-(\d*)\z/) {
+       if (($env->{HTTP_RANGE} || '') =~ /\bbytes=([0-9]*)-([0-9]*)\z/) {
                ($code, $len) = prepare_range($env, $in, $h, $1, $2, $size);
                if ($code == 416) {
                        push @$h, 'Content-Range', "bytes */$size";
@@ -203,7 +204,7 @@ sub serve_smart {
        $env{PATH_TRANSLATED} = "$git->{git_dir}/$path";
        my $rdr = input_prepare($env) or return r(500);
        my $qsp = PublicInbox::Qspawn->new([qw(git http-backend)], \%env, $rdr);
-       $qsp->psgi_return($env, $limiter, sub {
+       $qsp->psgi_return($env, $limiter, sub { # parse_hdr
                my ($r, $bref) = @_;
                my $res = parse_cgi_headers($r, $bref) or return; # incomplete
                $res->[0] == 403 ? serve_dumb($env, $git, $path) : $res;
@@ -218,7 +219,8 @@ sub input_prepare {
        if (defined $fd && $fd >= 0) {
                return { 0 => $fd };
        }
-       open(my $in, '+>', undef);
+       my $id = "git-http.input.$env->{REMOTE_ADDR}:$env->{REMOTE_PORT}";
+       my $in = tmpfile($id);
        unless (defined $in) {
                err($env, "could not open temporary file: $!");
                return;
@@ -231,18 +233,16 @@ sub input_prepare {
                        return;
                }
                last if $r == 0;
-               my $off = 0;
-               while ($r > 0) {
-                       my $w = syswrite($in, $buf, $r, $off);
-                       if (defined $w) {
-                               $r -= $w;
-                               $off += $w;
-                       } else {
-                               err($env, "error writing temporary file: $!");
-                               return;
-                       }
+               unless (print $in $buf) {
+                       err($env, "error writing temporary file: $!");
+                       return;
                }
        }
+       # ensure it's visible to git-http-backend(1):
+       unless ($in->flush) {
+               err($env, "error writing temporary file: $!");
+               return;
+       }
        unless (defined(sysseek($in, 0, SEEK_SET))) {
                err($env, "error seeking temporary file: $!");
                return;
@@ -260,7 +260,7 @@ sub parse_cgi_headers {
        foreach my $l (split(/\r?\n/, $h)) {
                my ($k, $v) = split(/:\s*/, $l, 2);
                if ($k =~ /\AStatus\z/i) {
-                       ($code) = ($v =~ /\b(\d+)\b/);
+                       ($code) = ($v =~ /\b([0-9]+)\b/);
                } else {
                        push @h, $k, $v;
                }