Commit 48d23c12 authored by Junio C Hamano's avatar Junio C Hamano

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. <[email protected]>

* 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
parents 8554ee15 f8edeaa0
...@@ -2971,6 +2971,11 @@ uploadpack.allowReachableSHA1InWant:: ...@@ -2971,6 +2971,11 @@ uploadpack.allowReachableSHA1InWant::
calculating object reachability is computationally expensive. calculating object reachability is computationally expensive.
Defaults to `false`. 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:: 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. ...@@ -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 { ...@@ -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, ...@@ -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 @@ static int post_rpc(struct rpc_state *rpc) ...@@ -663,6 +666,8 @@ static int post_rpc(struct rpc_state *rpc)
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 @@ static int post_rpc(struct rpc_state *rpc) ...@@ -671,6 +676,9 @@ static int post_rpc(struct rpc_state *rpc)
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' ' ...@@ -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; ...@@ -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) ...@@ -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) ...@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment