Browse Source
Push passes to another commands, as described in https://public-inbox.org/git/20171129032214.GB32345@sigill.intra.peff.net/ As it gets complicated to correctly track the data length, instead transfer the data through parent process and cut the pipe as the specified length is reached. Do it only when CONTENT_LENGTH is set, otherwise pass the input directly to the forked commands. Add tests for cases: * CONTENT_LENGTH is set, script's stdin has more data, with all combinations of variations: fetch or push, plain or compressed body, correct or truncated input. * CONTENT_LENGTH is specified to a value which does not fit into ssize_t. Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Max Kirillov <max@max630.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
Max Kirillov
6 years ago
committed by
Junio C Hamano
4 changed files with 223 additions and 2 deletions
@ -0,0 +1,155 @@
@@ -0,0 +1,155 @@
|
||||
#!/bin/sh |
||||
|
||||
test_description='test git-http-backend respects CONTENT_LENGTH' |
||||
. ./test-lib.sh |
||||
|
||||
test_lazy_prereq GZIP 'gzip --version' |
||||
|
||||
verify_http_result() { |
||||
# some fatal errors still produce status 200 |
||||
# so check if there is the error message |
||||
if grep 'fatal:' act.err |
||||
then |
||||
return 1 |
||||
fi |
||||
|
||||
if ! grep "Status" act.out >act |
||||
then |
||||
printf "Status: 200 OK\r\n" >act |
||||
fi |
||||
printf "Status: $1\r\n" >exp && |
||||
test_cmp exp act |
||||
} |
||||
|
||||
test_http_env() { |
||||
handler_type="$1" |
||||
request_body="$2" |
||||
shift |
||||
env \ |
||||
CONTENT_TYPE="application/x-git-$handler_type-pack-request" \ |
||||
QUERY_STRING="/repo.git/git-$handler_type-pack" \ |
||||
PATH_TRANSLATED="$PWD/.git/git-$handler_type-pack" \ |
||||
GIT_HTTP_EXPORT_ALL=TRUE \ |
||||
REQUEST_METHOD=POST \ |
||||
"$TEST_DIRECTORY"/t5562/invoke-with-content-length.pl \ |
||||
"$request_body" git http-backend >act.out 2>act.err |
||||
} |
||||
|
||||
ssize_b100dots() { |
||||
# hardcoded ((size_t) SSIZE_MAX) + 1 |
||||
case "$(build_option sizeof-size_t)" in |
||||
8) echo 9223372036854775808;; |
||||
4) echo 2147483648;; |
||||
*) die "Unexpected ssize_t size: $(build_option sizeof-size_t)";; |
||||
esac |
||||
} |
||||
|
||||
test_expect_success 'setup' ' |
||||
export HTTP_CONTENT_ENCODING="identity" && |
||||
git config http.receivepack true && |
||||
test_commit c0 && |
||||
test_commit c1 && |
||||
hash_head=$(git rev-parse HEAD) && |
||||
hash_prev=$(git rev-parse HEAD~1) && |
||||
printf "want %s" "$hash_head" | packetize >fetch_body && |
||||
printf 0000 >>fetch_body && |
||||
printf "have %s" "$hash_prev" | packetize >>fetch_body && |
||||
printf done | packetize >>fetch_body && |
||||
test_copy_bytes 10 <fetch_body >fetch_body.trunc && |
||||
hash_next=$(git commit-tree -p HEAD -m next HEAD^{tree}) && |
||||
printf "%s %s refs/heads/newbranch\\0report-status\\n" "$_z40" "$hash_next" | packetize >push_body && |
||||
printf 0000 >>push_body && |
||||
echo "$hash_next" | git pack-objects --stdout >>push_body && |
||||
test_copy_bytes 10 <push_body >push_body.trunc && |
||||
: >empty_body |
||||
' |
||||
|
||||
test_expect_success GZIP 'setup, compression related' ' |
||||
gzip -c fetch_body >fetch_body.gz && |
||||
test_copy_bytes 10 <fetch_body.gz >fetch_body.gz.trunc && |
||||
gzip -c push_body >push_body.gz && |
||||
test_copy_bytes 10 <push_body.gz >push_body.gz.trunc |
||||
' |
||||
|
||||
test_expect_success 'fetch plain' ' |
||||
test_http_env upload fetch_body && |
||||
verify_http_result "200 OK" |
||||
' |
||||
|
||||
test_expect_success 'fetch plain truncated' ' |
||||
test_http_env upload fetch_body.trunc && |
||||
! verify_http_result "200 OK" |
||||
' |
||||
|
||||
test_expect_success 'fetch plain empty' ' |
||||
test_http_env upload empty_body && |
||||
! verify_http_result "200 OK" |
||||
' |
||||
|
||||
test_expect_success GZIP 'fetch gzipped' ' |
||||
test_env HTTP_CONTENT_ENCODING="gzip" test_http_env upload fetch_body.gz && |
||||
verify_http_result "200 OK" |
||||
' |
||||
|
||||
test_expect_success GZIP 'fetch gzipped truncated' ' |
||||
test_env HTTP_CONTENT_ENCODING="gzip" test_http_env upload fetch_body.gz.trunc && |
||||
! verify_http_result "200 OK" |
||||
' |
||||
|
||||
test_expect_success GZIP 'fetch gzipped empty' ' |
||||
test_env HTTP_CONTENT_ENCODING="gzip" test_http_env upload empty_body && |
||||
! verify_http_result "200 OK" |
||||
' |
||||
|
||||
test_expect_success GZIP 'push plain' ' |
||||
test_when_finished "git branch -D newbranch" && |
||||
test_http_env receive push_body && |
||||
verify_http_result "200 OK" && |
||||
git rev-parse newbranch >act.head && |
||||
echo "$hash_next" >exp.head && |
||||
test_cmp act.head exp.head |
||||
' |
||||
|
||||
test_expect_success 'push plain truncated' ' |
||||
test_http_env receive push_body.trunc && |
||||
! verify_http_result "200 OK" |
||||
' |
||||
|
||||
test_expect_success 'push plain empty' ' |
||||
test_http_env receive empty_body && |
||||
! verify_http_result "200 OK" |
||||
' |
||||
|
||||
test_expect_success GZIP 'push gzipped' ' |
||||
test_when_finished "git branch -D newbranch" && |
||||
test_env HTTP_CONTENT_ENCODING="gzip" test_http_env receive push_body.gz && |
||||
verify_http_result "200 OK" && |
||||
git rev-parse newbranch >act.head && |
||||
echo "$hash_next" >exp.head && |
||||
test_cmp act.head exp.head |
||||
' |
||||
|
||||
test_expect_success GZIP 'push gzipped truncated' ' |
||||
test_env HTTP_CONTENT_ENCODING="gzip" test_http_env receive push_body.gz.trunc && |
||||
! verify_http_result "200 OK" |
||||
' |
||||
|
||||
test_expect_success GZIP 'push gzipped empty' ' |
||||
test_env HTTP_CONTENT_ENCODING="gzip" test_http_env receive empty_body && |
||||
! verify_http_result "200 OK" |
||||
' |
||||
|
||||
test_expect_success 'CONTENT_LENGTH overflow ssite_t' ' |
||||
NOT_FIT_IN_SSIZE=$(ssize_b100dots) && |
||||
env \ |
||||
CONTENT_TYPE=application/x-git-upload-pack-request \ |
||||
QUERY_STRING=/repo.git/git-upload-pack \ |
||||
PATH_TRANSLATED="$PWD"/.git/git-upload-pack \ |
||||
GIT_HTTP_EXPORT_ALL=TRUE \ |
||||
REQUEST_METHOD=POST \ |
||||
CONTENT_LENGTH="$NOT_FIT_IN_SSIZE" \ |
||||
git http-backend </dev/zero >/dev/null 2>err && |
||||
grep "fatal:.*CONTENT_LENGTH" err |
||||
' |
||||
|
||||
test_done |
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/perl |
||||
use 5.008; |
||||
use strict; |
||||
use warnings; |
||||
|
||||
my $body_filename = $ARGV[0]; |
||||
my @command = @ARGV[1 .. $#ARGV]; |
||||
|
||||
# read data |
||||
my $body_size = -s $body_filename; |
||||
$ENV{"CONTENT_LENGTH"} = $body_size; |
||||
open(my $body_fh, "<", $body_filename) or die "Cannot open $body_filename: $!"; |
||||
my $body_data; |
||||
defined read($body_fh, $body_data, $body_size) or die "Cannot read $body_filename: $!"; |
||||
close($body_fh); |
||||
|
||||
my $exited = 0; |
||||
$SIG{"CHLD"} = sub { |
||||
$exited = 1; |
||||
}; |
||||
|
||||
# write data |
||||
my $pid = open(my $out, "|-", @command); |
||||
{ |
||||
# disable buffering at $out |
||||
my $old_selected = select; |
||||
select $out; |
||||
$| = 1; |
||||
select $old_selected; |
||||
} |
||||
print $out $body_data or die "Cannot write data: $!"; |
||||
|
||||
sleep 60; # is interrupted by SIGCHLD |
||||
if (!$exited) { |
||||
close($out); |
||||
die "Command did not exit after reading whole body"; |
||||
} |
Loading…
Reference in new issue