Merge branch 'jt/tighten-fetch-proto-v2-response'
authorJunio C Hamano <gitster@pobox.com>
Tue, 13 Nov 2018 13:37:22 +0000 (22:37 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 13 Nov 2018 13:37:22 +0000 (22:37 +0900)
"git fetch" was a bit loose in parsing resposes from the other side
when talking over the protocol v2.

* jt/tighten-fetch-proto-v2-response:
fetch-pack: be more precise in parsing v2 response

fetch-pack.c
t/t5702-protocol-v2.sh
index b3ed7121bc86805e87e909ff995eb8b439a2f995..9691046e6445837beefde3d8ae5e842063842575 100644 (file)
@@ -1248,6 +1248,18 @@ static int process_acks(struct fetch_negotiator *negotiator,
            reader->status != PACKET_READ_DELIM)
                die(_("error processing acks: %d"), reader->status);
 
+       /*
+        * If an "acknowledgments" section is sent, a packfile is sent if and
+        * only if "ready" was sent in this section. The other sections
+        * ("shallow-info" and "wanted-refs") are sent only if a packfile is
+        * sent. Therefore, a DELIM is expected if "ready" is sent, and a FLUSH
+        * otherwise.
+        */
+       if (received_ready && reader->status != PACKET_READ_DELIM)
+               die(_("expected packfile to be sent after 'ready'"));
+       if (!received_ready && reader->status != PACKET_READ_FLUSH)
+               die(_("expected no other sections to be sent after no 'ready'"));
+
        /* return 0 if no common, 1 if there are common, or 2 if ready */
        return received_ready ? 2 : (received_ack ? 1 : 0);
 }
index 6ab8dea8cd896f5c7656755c89cee9759804bef9..0f2b09ebb8d6625b527ccc771c4725d2a314d4ee 100755 (executable)
@@ -537,6 +537,56 @@ test_expect_success 'push with http:// and a config of v2 does not request v2' '
        ! grep "git< version 2" log
 '
 
+test_expect_success 'when server sends "ready", expect DELIM' '
+       rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child &&
+
+       git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
+       test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" one &&
+
+       git clone "$HTTPD_URL/smart/http_parent" http_child &&
+
+       test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" two &&
+
+       # After "ready" in the acknowledgments section, pretend that a FLUSH
+       # (0000) was sent instead of a DELIM (0001).
+       printf "/ready/,$ s/0001/0000/" \
+               >"$HTTPD_ROOT_PATH/one-time-sed" &&
+
+       test_must_fail git -C http_child -c protocol.version=2 \
+               fetch "$HTTPD_URL/one_time_sed/http_parent" 2> err &&
+       test_i18ngrep "expected packfile to be sent after .ready." err
+'
+
+test_expect_success 'when server does not send "ready", expect FLUSH' '
+       rm -rf "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" http_child log &&
+
+       git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" &&
+       test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" one &&
+
+       git clone "$HTTPD_URL/smart/http_parent" http_child &&
+
+       test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" two &&
+
+       # Create many commits to extend the negotiation phase across multiple
+       # requests, so that the server does not send "ready" in the first
+       # request.
+       for i in $(test_seq 1 32)
+       do
+               test_commit -C http_child c$i
+       done &&
+
+       # After the acknowledgments section, pretend that a DELIM
+       # (0001) was sent instead of a FLUSH (0000).
+       printf "/acknowledgments/,$ s/0000/0001/" \
+               >"$HTTPD_ROOT_PATH/one-time-sed" &&
+
+       test_must_fail env GIT_TRACE_PACKET="$(pwd)/log" git -C http_child \
+               -c protocol.version=2 \
+               fetch "$HTTPD_URL/one_time_sed/http_parent" 2> err &&
+       grep "fetch< acknowledgments" log &&
+       ! grep "fetch< ready" log &&
+       test_i18ngrep "expected no other sections to be sent after no .ready." err
+'
 
 stop_httpd