upload-pack: optionally allow fetching any sha1

It seems a little silly to do a reachabilty check in the case where we trust the user to access absolutely everything in the repository. Also, it's racy in a distributed system -- perhaps one server advertises a ref, but another has since had a force-push to that ref, and perhaps the two HTTP requests end up directed to these different servers. Signed-off-by: David Turner <dturner@twosigma.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

David Turner committed Nov 11, 2016 at 12:23 UTC f8edeaa05d8623a9f6dad408237496c51101aad8
4 files changed +39 -4
Documentation/config.txt
+5
@@ -2961,6 +2961,11 @@ uploadpack.allowReachableSHA1InWant::
2961 calculating object reachability is computationally expensive.
2962 Defaults to `false`.
2963
2964 +uploadpack.allowAnySHA1InWant::
2965 + Allow `upload-pack` to accept a fetch request that asks for any
2966 + object at all.
2967 + Defaults to `false`.
2968 +
2969 uploadpack.keepAlive::
2970 When `upload-pack` has started `pack-objects`, there may be a
2971 quiet period while `pack-objects` prepares the pack. Normally
Documentation/git-fetch-pack.txt
+3 -3
@@ -119,9 +119,9 @@ be in a separate packet, and the list must end with a flush packet.
119 $GIT_DIR (e.g. "HEAD", "refs/heads/master"). When
120 unspecified, update from all heads the remote side has.
121 +
122 -If the remote has enabled the options `uploadpack.allowTipSHA1InWant` or
123 -`uploadpack.allowReachableSHA1InWant`, they may alternatively be 40-hex
124 -sha1s present on the remote.
122 +If the remote has enabled the options `uploadpack.allowTipSHA1InWant`,
123 +`uploadpack.allowReachableSHA1InWant`, or `uploadpack.allowAnySHA1InWant`,
124 +they may alternatively be 40-hex sha1s present on the remote.
125
126 SEE ALSO
127 --------
t/t5551-http-fetch-smart.sh
+22
@@ -306,6 +306,28 @@ test_expect_success 'test allowreachablesha1inwant with unreachable' '
306 test_must_fail git -C test_reachable.git fetch origin "$(git rev-parse HEAD)"
307 '
308
309 +test_expect_success 'test allowanysha1inwant with unreachable' '
310 + test_when_finished "rm -rf test_reachable.git; git reset --hard $(git rev-parse HEAD)" &&
311 +
312 + #create unreachable sha
313 + echo content >file2 &&
314 + git add file2 &&
315 + git commit -m two &&
316 + git push public HEAD:refs/heads/doomed &&
317 + git push public :refs/heads/doomed &&
318 +
319 + server="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
320 + master_sha=$(git -C "$server" rev-parse refs/heads/master) &&
321 + git -C "$server" config uploadpack.allowreachablesha1inwant 1 &&
322 +
323 + git init --bare test_reachable.git &&
324 + git -C test_reachable.git remote add origin "$HTTPD_URL/smart/repo.git" &&
325 + test_must_fail git -C test_reachable.git fetch origin "$(git rev-parse HEAD)" &&
326 +
327 + git -C "$server" config uploadpack.allowanysha1inwant 1 &&
328 + git -C test_reachable.git fetch origin "$(git rev-parse HEAD)"
329 +'
330 +
331 test_expect_success EXPENSIVE 'http can handle enormous ref negotiation' '
332 (
333 cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
upload-pack.c
+9 -1
@@ -46,6 +46,8 @@ static int no_progress, daemon_mode;
46 #define ALLOW_TIP_SHA1 01
47 /* Allow request of a sha1 if it is reachable from a ref (possibly hidden ref). */
48 #define ALLOW_REACHABLE_SHA1 02
49 +/* Allow request of any sha1. Implies ALLOW_TIP_SHA1 and ALLOW_REACHABLE_SHA1. */
50 +#define ALLOW_ANY_SHA1 07
51 static unsigned int allow_unadvertised_object_request;
52 static int shallow_nr;
53 static struct object_array have_obj;
@@ -825,7 +827,8 @@ static void receive_needs(void)
827 sha1_to_hex(sha1_buf));
828 if (!(o->flags & WANTED)) {
829 o->flags |= WANTED;
828 - if (!is_our_ref(o))
830 + if (!((allow_unadvertised_object_request & ALLOW_ANY_SHA1) == ALLOW_ANY_SHA1
831 + || is_our_ref(o)))
832 has_non_tip = 1;
833 add_object_array(o, NULL, &want_obj);
834 }
@@ -1008,6 +1011,11 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
1011 allow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1;
1012 else
1013 allow_unadvertised_object_request &= ~ALLOW_REACHABLE_SHA1;
1014 + } else if (!strcmp("uploadpack.allowanysha1inwant", var)) {
1015 + if (git_config_bool(var, value))
1016 + allow_unadvertised_object_request |= ALLOW_ANY_SHA1;
1017 + else
1018 + allow_unadvertised_object_request &= ~ALLOW_ANY_SHA1;
1019 } else if (!strcmp("uploadpack.keepalive", var)) {
1020 keepalive = git_config_int(var, value);
1021 if (!keepalive)