Skip to content

Commit e4c9538

Browse files
peffgitster
authored andcommitted
send-pack: complain about "expecting report" with --helper-status
When pushing to a server which erroneously omits the final ref-status report, the client side should complain about the refs for which we didn't receive the status (because we can't just assume they were updated). This works over most transports like ssh, but for http we'll print a very misleading "Everything up-to-date". It works for ssh because send-pack internally sets the status of each ref to REF_STATUS_EXPECTING_REPORT, and then if the server doesn't tell us about a particular ref, it will stay at that value. When we print the final status table, we'll see that we're still on EXPECTING_REPORT and complain then. But for http, we go through remote-curl, which invokes send-pack with "--stateless-rpc --helper-status". The latter option causes send-pack to return a machine-readable list of ref statuses to the remote helper. But ever since its inception in de1a2fd (Smart push over HTTP: client side, 2009-10-30), the send-pack code has simply omitted mention of any ref which ended up in EXPECTING_REPORT. In the remote helper, we then take the absence of any status report from send-pack to mean that the ref was not even something we tried to send, and thus it prints "Everything up-to-date". Fortunately it does detect the eventual non-zero exit from send-pack, and propagates that in its own non-zero exit code. So at least a careful script invoking "git push" would notice the failure. But sending the misleading message on stderr is certainly confusing for humans (not to mention the machine-readable "push --porcelain" output, though again, any careful script should be checking the exit code from push, too). Nobody seems to have noticed because the server in this instance has to be misbehaving: it has promised to support the ref-status capability (otherwise the client will not set EXPECTING_REPORT at all), but didn't send us any. If the connection were simply cut, then send-pack would complain about getting EOF while trying to read the status. But if the server actually sends a flush packet (i.e., saying "now you have all of the ref statuses" without actually sending any), then the client ends up in this confused situation. The fix is simple: we should return an error message from "send-pack --helper-status", just like we would for any other error per-ref error condition (in the test I included, the server simply omits all ref status responses, but a more insidious version of this would skip only some of them). Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent af6d1d6 commit e4c9538

File tree

5 files changed

+31
-0
lines changed

5 files changed

+31
-0
lines changed

builtin/send-pack.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ static void print_helper_status(struct ref *ref)
8787
break;
8888

8989
case REF_STATUS_EXPECTING_REPORT:
90+
res = "error";
91+
msg = "expecting report";
92+
break;
93+
9094
default:
9195
continue;
9296
}

t/lib-httpd.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ prepare_httpd() {
131131
cp "$TEST_PATH"/passwd "$HTTPD_ROOT_PATH"
132132
install_script incomplete-length-upload-pack-v2-http.sh
133133
install_script incomplete-body-upload-pack-v2-http.sh
134+
install_script error-no-report.sh
134135
install_script broken-smart-http.sh
135136
install_script error-smart-http.sh
136137
install_script error.sh

t/lib-httpd/apache.conf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ Alias /auth/dumb/ www/auth/dumb/
119119
</LocationMatch>
120120
ScriptAlias /smart/incomplete_length/git-upload-pack incomplete-length-upload-pack-v2-http.sh/
121121
ScriptAlias /smart/incomplete_body/git-upload-pack incomplete-body-upload-pack-v2-http.sh/
122+
ScriptAlias /smart/no_report/git-receive-pack error-no-report.sh/
122123
ScriptAliasMatch /error_git_upload_pack/(.*)/git-upload-pack error.sh/
123124
ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
124125
ScriptAlias /broken_smart/ broken-smart-http.sh/
@@ -134,6 +135,9 @@ ScriptAliasMatch /one_time_perl/(.*) apply-one-time-perl.sh/$1
134135
<Files incomplete-body-upload-pack-v2-http.sh>
135136
Options ExecCGI
136137
</Files>
138+
<Files error-no-report.sh>
139+
Options ExecCGI
140+
</Files>
137141
<Files broken-smart-http.sh>
138142
Options ExecCGI
139143
</Files>

t/lib-httpd/error-no-report.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
echo "Content-Type: application/x-git-receive-pack-result"
2+
echo
3+
printf '0013\001000eunpack ok\n'
4+
printf '0015\002skipping report\n'
5+
printf '0009\0010000'
6+
printf '0000'

t/t5541-http-push-smart.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,4 +509,20 @@ test_expect_success 'colorize errors/hints' '
509509
test_i18ngrep ! "^hint: " decoded
510510
'
511511

512+
test_expect_success 'report error server does not provide ref status' '
513+
git init "$HTTPD_DOCUMENT_ROOT_PATH/no_report" &&
514+
git -C "$HTTPD_DOCUMENT_ROOT_PATH/no_report" config http.receivepack true &&
515+
test_must_fail git push --porcelain \
516+
$HTTPD_URL_USER_PASS/smart/no_report \
517+
HEAD:refs/tags/will-fail >actual &&
518+
test_must_fail git -C "$HTTPD_DOCUMENT_ROOT_PATH/no_report" \
519+
rev-parse --verify refs/tags/will-fail &&
520+
cat >expect <<-EOF &&
521+
To $HTTPD_URL/smart/no_report
522+
! HEAD:refs/tags/will-fail [remote rejected] (expecting report)
523+
Done
524+
EOF
525+
test_cmp expect actual
526+
'
527+
512528
test_done

0 commit comments

Comments
 (0)