Merge branch 'dt/smart-http-detect-server-going-away'
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 outputmaint
commit
d984592043
|
@ -3030,6 +3030,11 @@ uploadpack.allowReachableSHA1InWant::
|
||||||
section of the linkgit:gitnamespaces[7] man page; it's best to
|
section of the linkgit:gitnamespaces[7] man page; it's best to
|
||||||
keep private data in a separate repository.
|
keep private data in a separate repository.
|
||||||
|
|
||||||
|
uploadpack.allowAnySHA1InWant::
|
||||||
|
Allow `upload-pack` to accept a fetch request that asks for any
|
||||||
|
object at all.
|
||||||
|
Defaults to `false`.
|
||||||
|
|
||||||
uploadpack.keepAlive::
|
uploadpack.keepAlive::
|
||||||
When `upload-pack` has started `pack-objects`, there may be a
|
When `upload-pack` has started `pack-objects`, there may be a
|
||||||
quiet period while `pack-objects` prepares the pack. Normally
|
quiet period while `pack-objects` prepares the pack. Normally
|
||||||
|
|
|
@ -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
|
$GIT_DIR (e.g. "HEAD", "refs/heads/master"). When
|
||||||
unspecified, update from all heads the remote side has.
|
unspecified, update from all heads the remote side has.
|
||||||
+
|
+
|
||||||
If the remote has enabled the options `uploadpack.allowTipSHA1InWant` or
|
If the remote has enabled the options `uploadpack.allowTipSHA1InWant`,
|
||||||
`uploadpack.allowReachableSHA1InWant`, they may alternatively be 40-hex
|
`uploadpack.allowReachableSHA1InWant`, or `uploadpack.allowAnySHA1InWant`,
|
||||||
sha1s present on the remote.
|
they may alternatively be 40-hex sha1s present on the remote.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
|
|
@ -404,6 +404,7 @@ struct rpc_state {
|
||||||
size_t pos;
|
size_t pos;
|
||||||
int in;
|
int in;
|
||||||
int out;
|
int out;
|
||||||
|
int any_written;
|
||||||
struct strbuf result;
|
struct strbuf result;
|
||||||
unsigned gzip_request : 1;
|
unsigned gzip_request : 1;
|
||||||
unsigned initial_buffer : 1;
|
unsigned initial_buffer : 1;
|
||||||
|
@ -460,6 +461,8 @@ static size_t rpc_in(char *ptr, size_t eltsize,
|
||||||
{
|
{
|
||||||
size_t size = eltsize * nmemb;
|
size_t size = eltsize * nmemb;
|
||||||
struct rpc_state *rpc = buffer_;
|
struct rpc_state *rpc = buffer_;
|
||||||
|
if (size)
|
||||||
|
rpc->any_written = 1;
|
||||||
write_or_die(rpc->in, ptr, size);
|
write_or_die(rpc->in, ptr, size);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
@ -663,6 +666,8 @@ retry:
|
||||||
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in);
|
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in);
|
||||||
curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
|
curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
|
||||||
|
|
||||||
|
|
||||||
|
rpc->any_written = 0;
|
||||||
err = run_slot(slot, NULL);
|
err = run_slot(slot, NULL);
|
||||||
if (err == HTTP_REAUTH && !large_request) {
|
if (err == HTTP_REAUTH && !large_request) {
|
||||||
credential_fill(&http_auth);
|
credential_fill(&http_auth);
|
||||||
|
@ -671,6 +676,9 @@ retry:
|
||||||
if (err != HTTP_OK)
|
if (err != HTTP_OK)
|
||||||
err = -1;
|
err = -1;
|
||||||
|
|
||||||
|
if (!rpc->any_written)
|
||||||
|
err = -1;
|
||||||
|
|
||||||
curl_slist_free_all(headers);
|
curl_slist_free_all(headers);
|
||||||
free(gzip_body);
|
free(gzip_body);
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -280,6 +280,58 @@ test_expect_success 'large fetch-pack requests can be split across POSTs' '
|
||||||
test_line_count = 2 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' '
|
test_expect_success EXPENSIVE 'http can handle enormous ref negotiation' '
|
||||||
(
|
(
|
||||||
cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
|
cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
|
||||||
|
|
|
@ -46,6 +46,8 @@ static int no_progress, daemon_mode;
|
||||||
#define ALLOW_TIP_SHA1 01
|
#define ALLOW_TIP_SHA1 01
|
||||||
/* Allow request of a sha1 if it is reachable from a ref (possibly hidden ref). */
|
/* Allow request of a sha1 if it is reachable from a ref (possibly hidden ref). */
|
||||||
#define ALLOW_REACHABLE_SHA1 02
|
#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 unsigned int allow_unadvertised_object_request;
|
||||||
static int shallow_nr;
|
static int shallow_nr;
|
||||||
static struct object_array have_obj;
|
static struct object_array have_obj;
|
||||||
|
@ -825,7 +827,8 @@ static void receive_needs(void)
|
||||||
sha1_to_hex(sha1_buf));
|
sha1_to_hex(sha1_buf));
|
||||||
if (!(o->flags & WANTED)) {
|
if (!(o->flags & WANTED)) {
|
||||||
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;
|
has_non_tip = 1;
|
||||||
add_object_array(o, NULL, &want_obj);
|
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;
|
allow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1;
|
||||||
else
|
else
|
||||||
allow_unadvertised_object_request &= ~ALLOW_REACHABLE_SHA1;
|
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)) {
|
} else if (!strcmp("uploadpack.keepalive", var)) {
|
||||||
keepalive = git_config_int(var, value);
|
keepalive = git_config_int(var, value);
|
||||||
if (!keepalive)
|
if (!keepalive)
|
||||||
|
|
Loading…
Reference in New Issue