diff --git a/Documentation/config.txt b/Documentation/config.txt index 6e53fc5074..432c38c3f2 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -2164,6 +2164,17 @@ uploadpack.allowtipsha1inwant:: of a hidden ref (by default, such a request is rejected). see also `uploadpack.hiderefs`. +uploadpack.keepalive:: + When `upload-pack` has started `pack-objects`, there may be a + quiet period while `pack-objects` prepares the pack. Normally + it would output progress information, but if `--quiet` was used + for the fetch, `pack-objects` will output nothing at all until + the pack data begins. Some clients and networks may consider + the server to be hung and give up. Setting this option instructs + `upload-pack` to send an empty keepalive packet every + `uploadpack.keepalive` seconds. Setting this option to 0 + disables keepalive packets entirely. The default is 0. + url..insteadOf:: Any URL that starts with this value will be rewritten to start, instead, with . In cases where some site serves a diff --git a/upload-pack.c b/upload-pack.c index bfa6279cc4..289717ed5f 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -40,6 +40,7 @@ static struct object_array have_obj; static struct object_array want_obj; static struct object_array extra_edge_obj; static unsigned int timeout; +static int keepalive = -1; /* 0 for no sideband, * otherwise maximum packet size (up to 65520 bytes). */ @@ -200,6 +201,7 @@ static void create_pack_file(void) while (1) { struct pollfd pfd[2]; int pe, pu, pollsize; + int ret; reset_timeout(); @@ -222,7 +224,8 @@ static void create_pack_file(void) if (!pollsize) break; - if (poll(pfd, pollsize, -1) < 0) { + ret = poll(pfd, pollsize, 1000 * keepalive); + if (ret < 0) { if (errno != EINTR) { error("poll failed, resuming: %s", strerror(errno)); @@ -284,6 +287,21 @@ static void create_pack_file(void) if (sz < 0) goto fail; } + + /* + * We hit the keepalive timeout without saying anything; send + * an empty message on the data sideband just to let the other + * side know we're still working on it, but don't have any data + * yet. + * + * If we don't have a sideband channel, there's no room in the + * protocol to say anything, so those clients are just out of + * luck. + */ + if (!ret && use_sideband) { + static const char buf[] = "0005\1"; + write_or_die(1, buf, 5); + } } if (finish_command(&pack_objects)) { @@ -785,6 +803,11 @@ static int upload_pack_config(const char *var, const char *value, void *unused) { if (!strcmp("uploadpack.allowtipsha1inwant", var)) allow_tip_sha1_in_want = git_config_bool(var, value); + else if (!strcmp("uploadpack.keepalive", var)) { + keepalive = git_config_int(var, value); + if (!keepalive) + keepalive = -1; + } return parse_hide_refs_config(var, value, "uploadpack"); }