Merge branch 'jt/accept-capability-advertisement-when-fetching-from-void'
authorJunio C Hamano <gitster@pobox.com>
Wed, 21 Sep 2016 22:15:17 +0000 (15:15 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 21 Sep 2016 22:15:18 +0000 (15:15 -0700)
JGit can show a fake ref "capabilities^{}" to "git fetch" when it
does not advertise any refs, but "git fetch" was not prepared to
see such an advertisement. When the other side disconnects without
giving any ref advertisement, we used to say "there may not be a
repository at that URL", but we may have seen other advertisement
like "shallow" and ".have" in which case we definitely know that a
repository is there. The code to detect this case has also been
updated.

* jt/accept-capability-advertisement-when-fetching-from-void:
connect: advertized capability is not a ref
connect: tighten check for unexpected early hang up
tests: move test_lazy_prereq JGIT to test-lib.sh

connect.c
t/t5310-pack-bitmaps.sh
t/t5512-ls-remote.sh
t/test-lib.sh
index 722dc3fc546056be199f5d6a59c556833be58286..7224b5ecc79beebe3182b301bdf0e661f6a246fd 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -43,9 +43,9 @@ int check_ref_type(const struct ref *ref, int flags)
        return check_ref(ref->name, flags);
 }
 
-static void die_initial_contact(int got_at_least_one_head)
+static void die_initial_contact(int unexpected)
 {
-       if (got_at_least_one_head)
+       if (unexpected)
                die("The remote end hung up upon initial contact");
        else
                die("Could not read from remote repository.\n\n"
@@ -115,10 +115,18 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
                              struct sha1_array *shallow_points)
 {
        struct ref **orig_list = list;
-       int got_at_least_one_head = 0;
+
+       /*
+        * A hang-up after seeing some response from the other end
+        * means that it is unexpected, as we know the other end is
+        * willing to talk to us.  A hang-up before seeing any
+        * response does not necessarily mean an ACL problem, though.
+        */
+       int saw_response;
+       int got_dummy_ref_with_capabilities_declaration = 0;
 
        *list = NULL;
-       for (;;) {
+       for (saw_response = 0; ; saw_response = 1) {
                struct ref *ref;
                struct object_id old_oid;
                char *name;
@@ -131,7 +139,7 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
                                  PACKET_READ_GENTLE_ON_EOF |
                                  PACKET_READ_CHOMP_NEWLINE);
                if (len < 0)
-                       die_initial_contact(got_at_least_one_head);
+                       die_initial_contact(saw_response);
 
                if (!len)
                        break;
@@ -165,13 +173,25 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
                        continue;
                }
 
+               if (!strcmp(name, "capabilities^{}")) {
+                       if (saw_response)
+                               die("protocol error: unexpected capabilities^{}");
+                       if (got_dummy_ref_with_capabilities_declaration)
+                               die("protocol error: multiple capabilities^{}");
+                       got_dummy_ref_with_capabilities_declaration = 1;
+                       continue;
+               }
+
                if (!check_ref(name, flags))
                        continue;
+
+               if (got_dummy_ref_with_capabilities_declaration)
+                       die("protocol error: unexpected ref after capabilities^{}");
+
                ref = alloc_ref(buffer + GIT_SHA1_HEXSZ + 1);
                oidcpy(&ref->old_oid, &old_oid);
                *list = ref;
                list = &ref->next;
-               got_at_least_one_head = 1;
        }
 
        annotate_refs_with_symref_info(*orig_list);
index 3893afd687986ec7ec9102658c8dc332c61d25fa..1e376ea39e29774f89e4610b2dbed6b385e460eb 100755 (executable)
@@ -158,10 +158,6 @@ test_expect_success 'pack with missing parent' '
        git pack-objects --stdout --revs <revs >/dev/null
 '
 
-test_lazy_prereq JGIT '
-       type jgit
-'
-
 test_expect_success JGIT 'we can read jgit bitmaps' '
        git clone . compat-jgit &&
        (
index 819b9ddd0f917a21e3edf7122f99cfb04f4b7a8f..befdfeefc603e42ad1ce69599fd1b1142917a8d7 100755 (executable)
@@ -207,5 +207,45 @@ test_expect_success 'ls-remote --symref omits filtered-out matches' '
        test_cmp expect actual
 '
 
+test_lazy_prereq GIT_DAEMON '
+       test_tristate GIT_TEST_GIT_DAEMON &&
+       test "$GIT_TEST_GIT_DAEMON" != false
+'
+
+# This test spawns a daemon, so run it only if the user would be OK with
+# testing with git-daemon.
+test_expect_success PIPE,JGIT,GIT_DAEMON 'indicate no refs in standards-compliant empty remote' '
+       JGIT_DAEMON_PORT=${JGIT_DAEMON_PORT-${this_test#t}} &&
+       JGIT_DAEMON_PID= &&
+       git init --bare empty.git &&
+       >empty.git/git-daemon-export-ok &&
+       mkfifo jgit_daemon_output &&
+       {
+               jgit daemon --port="$JGIT_DAEMON_PORT" . >jgit_daemon_output &
+               JGIT_DAEMON_PID=$!
+       } &&
+       test_when_finished kill "$JGIT_DAEMON_PID" &&
+       {
+               read line &&
+               case $line in
+               Exporting*)
+                       ;;
+               *)
+                       echo "Expected: Exporting" &&
+                       false;;
+               esac &&
+               read line &&
+               case $line in
+               "Listening on"*)
+                       ;;
+               *)
+                       echo "Expected: Listening on" &&
+                       false;;
+               esac
+       } <jgit_daemon_output &&
+       # --exit-code asks the command to exit with 2 when no
+       # matching refs are found.
+       test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git
+'
 
 test_done
index ac56512a1c5e4fde4af33cedcbb1cab11487d29a..11562bde10be50d47f3a82b3885b5a0aab50c14a 100644 (file)
@@ -1073,6 +1073,10 @@ test_lazy_prereq NOT_ROOT '
        test "$uid" != 0
 '
 
+test_lazy_prereq JGIT '
+       type jgit
+'
+
 # SANITY is about "can you correctly predict what the filesystem would
 # do by only looking at the permission bits of the files and
 # directories?"  A typical example of !SANITY is running the test