summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2017-01-17 15:19:03 -0800
committerJunio C Hamano <gitster@pobox.com>2017-01-17 15:19:03 -0800
commit48d23c12e7329213e0dfd73bbffc6ad05efcaf9d (patch)
tree0be1b42a367d5cd1c4bfb0296695be2c7a157fda
parent8554ee155d8e69703dfaa04d03cd45f2d82f1a0f (diff)
parentf8edeaa05d8623a9f6dad408237496c51101aad8 (diff)
downloadgit-48d23c12e7329213e0dfd73bbffc6ad05efcaf9d.tar.gz
Merge branch 'dt/smart-http-detect-server-going-away' into maint
When the http server gives an incomplete response to a smart-http rpc call, it could lead to client waiting for a full response that will never come. Teach the client side to notice this condition and abort the transfer. An improvement counterproposal has failed. cf. <20161114194049.mktpsvgdhex2f4zv@sigill.intra.peff.net> * dt/smart-http-detect-server-going-away: upload-pack: optionally allow fetching any sha1 remote-curl: don't hang when a server dies before any output
-rw-r--r--Documentation/config.txt5
-rw-r--r--Documentation/git-fetch-pack.txt6
-rw-r--r--remote-curl.c8
-rwxr-xr-xt/t5551-http-fetch-smart.sh52
-rw-r--r--upload-pack.c10
5 files changed, 77 insertions, 4 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt
index d51182a060..febf95d6c6 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -2971,6 +2971,11 @@ uploadpack.allowReachableSHA1InWant::
calculating object reachability is computationally expensive.
Defaults to `false`.
+uploadpack.allowAnySHA1InWant::
+ Allow `upload-pack` to accept a fetch request that asks for any
+ object at all.
+ Defaults to `false`.
+
uploadpack.keepAlive::
When `upload-pack` has started `pack-objects`, there may be a
quiet period while `pack-objects` prepares the pack. Normally
diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt
index d45f6adc69..f7ebe36a7b 100644
--- a/Documentation/git-fetch-pack.txt
+++ b/Documentation/git-fetch-pack.txt
@@ -119,9 +119,9 @@ be in a separate packet, and the list must end with a flush packet.
$GIT_DIR (e.g. "HEAD", "refs/heads/master"). When
unspecified, update from all heads the remote side has.
+
-If the remote has enabled the options `uploadpack.allowTipSHA1InWant` or
-`uploadpack.allowReachableSHA1InWant`, they may alternatively be 40-hex
-sha1s present on the remote.
+If the remote has enabled the options `uploadpack.allowTipSHA1InWant`,
+`uploadpack.allowReachableSHA1InWant`, or `uploadpack.allowAnySHA1InWant`,
+they may alternatively be 40-hex sha1s present on the remote.
SEE ALSO
--------
diff --git a/remote-curl.c b/remote-curl.c
index 28d9d10638..34a97e7328 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -404,6 +404,7 @@ struct rpc_state {
size_t pos;
int in;
int out;
+ int any_written;
struct strbuf result;
unsigned gzip_request : 1;
unsigned initial_buffer : 1;
@@ -460,6 +461,8 @@ static size_t rpc_in(char *ptr, size_t eltsize,
{
size_t size = eltsize * nmemb;
struct rpc_state *rpc = buffer_;
+ if (size)
+ rpc->any_written = 1;
write_or_die(rpc->in, ptr, size);
return size;
}
@@ -663,6 +666,8 @@ retry:
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in);
curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
+
+ rpc->any_written = 0;
err = run_slot(slot, NULL);
if (err == HTTP_REAUTH && !large_request) {
credential_fill(&http_auth);
@@ -671,6 +676,9 @@ retry:
if (err != HTTP_OK)
err = -1;
+ if (!rpc->any_written)
+ err = -1;
+
curl_slist_free_all(headers);
free(gzip_body);
return err;
diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh
index 6e5b9e42fb..a51b7e20d3 100755
--- a/t/t5551-http-fetch-smart.sh
+++ b/t/t5551-http-fetch-smart.sh
@@ -280,6 +280,58 @@ test_expect_success 'large fetch-pack requests can be split across POSTs' '
test_line_count = 2 posts
'
+test_expect_success 'test allowreachablesha1inwant' '
+ test_when_finished "rm -rf test_reachable.git" &&
+ server="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+ master_sha=$(git -C "$server" rev-parse refs/heads/master) &&
+ git -C "$server" config uploadpack.allowreachablesha1inwant 1 &&
+
+ git init --bare test_reachable.git &&
+ git -C test_reachable.git remote add origin "$HTTPD_URL/smart/repo.git" &&
+ git -C test_reachable.git fetch origin "$master_sha"
+'
+
+test_expect_success 'test allowreachablesha1inwant with unreachable' '
+ test_when_finished "rm -rf test_reachable.git; git reset --hard $(git rev-parse HEAD)" &&
+
+ #create unreachable sha
+ echo content >file2 &&
+ git add file2 &&
+ git commit -m two &&
+ git push public HEAD:refs/heads/doomed &&
+ git push public :refs/heads/doomed &&
+
+ server="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+ master_sha=$(git -C "$server" rev-parse refs/heads/master) &&
+ git -C "$server" config uploadpack.allowreachablesha1inwant 1 &&
+
+ git init --bare test_reachable.git &&
+ git -C test_reachable.git remote add origin "$HTTPD_URL/smart/repo.git" &&
+ test_must_fail git -C test_reachable.git fetch origin "$(git rev-parse HEAD)"
+'
+
+test_expect_success 'test allowanysha1inwant with unreachable' '
+ test_when_finished "rm -rf test_reachable.git; git reset --hard $(git rev-parse HEAD)" &&
+
+ #create unreachable sha
+ echo content >file2 &&
+ git add file2 &&
+ git commit -m two &&
+ git push public HEAD:refs/heads/doomed &&
+ git push public :refs/heads/doomed &&
+
+ server="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+ master_sha=$(git -C "$server" rev-parse refs/heads/master) &&
+ git -C "$server" config uploadpack.allowreachablesha1inwant 1 &&
+
+ git init --bare test_reachable.git &&
+ git -C test_reachable.git remote add origin "$HTTPD_URL/smart/repo.git" &&
+ test_must_fail git -C test_reachable.git fetch origin "$(git rev-parse HEAD)" &&
+
+ git -C "$server" config uploadpack.allowanysha1inwant 1 &&
+ git -C test_reachable.git fetch origin "$(git rev-parse HEAD)"
+'
+
test_expect_success EXPENSIVE 'http can handle enormous ref negotiation' '
(
cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
diff --git a/upload-pack.c b/upload-pack.c
index e0db8b42be..7597ba3405 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -46,6 +46,8 @@ static int no_progress, daemon_mode;
#define ALLOW_TIP_SHA1 01
/* Allow request of a sha1 if it is reachable from a ref (possibly hidden ref). */
#define ALLOW_REACHABLE_SHA1 02
+/* Allow request of any sha1. Implies ALLOW_TIP_SHA1 and ALLOW_REACHABLE_SHA1. */
+#define ALLOW_ANY_SHA1 07
static unsigned int allow_unadvertised_object_request;
static int shallow_nr;
static struct object_array have_obj;
@@ -825,7 +827,8 @@ static void receive_needs(void)
sha1_to_hex(sha1_buf));
if (!(o->flags & WANTED)) {
o->flags |= WANTED;
- if (!is_our_ref(o))
+ if (!((allow_unadvertised_object_request & ALLOW_ANY_SHA1) == ALLOW_ANY_SHA1
+ || is_our_ref(o)))
has_non_tip = 1;
add_object_array(o, NULL, &want_obj);
}
@@ -1008,6 +1011,11 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
allow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1;
else
allow_unadvertised_object_request &= ~ALLOW_REACHABLE_SHA1;
+ } else if (!strcmp("uploadpack.allowanysha1inwant", var)) {
+ if (git_config_bool(var, value))
+ allow_unadvertised_object_request |= ALLOW_ANY_SHA1;
+ else
+ allow_unadvertised_object_request &= ~ALLOW_ANY_SHA1;
} else if (!strcmp("uploadpack.keepalive", var)) {
keepalive = git_config_int(var, value);
if (!keepalive)