Skip to content

Commit 46e6f9a

Browse files
ttaylorrgitster
authored andcommitted
http.c: allow custom TCP keepalive behavior via config
curl supports a few options to control when and how often it should instruct the OS to send TCP keepalives, like KEEPIDLE, KEEPINTVL, and KEEPCNT. Until this point, there hasn't been a way for users to change what values are used for these options, forcing them to rely on curl's defaults. But we do unconditionally enable TCP keepalives without giving users an ability to tweak any fine-grained parameters. Ordinarily this isn't a problem, particularly for users that have fast-enough connections, and/or are talking to a server that has generous or nonexistent thresholds for killing a connection it hasn't heard from in a while. But it can present a problem when one or both of those assumptions fail. For instance, I can reliably get an in-progress clone to be killed from the remote end when cloning from some forges while using trickle to limit my clone's bandwidth. For those users and others who wish to more finely tune the OS's keepalive behavior, expose configuration and environment variables which allow setting curl's KEEPIDLE, KEEPINTVL, and KEEPCNT options. Note that while KEEPIDLE and KEEPINTVL were added in curl 7.25.0, KEEPCNT was added much more recently in curl 8.9.0. Per f7c0940 (git-curl-compat: remove check for curl 7.25.0, 2024-10-23), both KEEPIDLE and KEEPINTVL are set unconditionally. But since we may be compiled with a curl that isn't as new as 8.9.0, only set KEEPCNT when we have CURLOPT_TCP_KEEPCNT to begin with. Signed-off-by: Taylor Blau <[email protected]> Acked-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent bfdd259 commit 46e6f9a

File tree

3 files changed

+57
-1
lines changed

3 files changed

+57
-1
lines changed

Documentation/config/http.adoc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,24 @@ http.lowSpeedLimit, http.lowSpeedTime::
296296
Can be overridden by the `GIT_HTTP_LOW_SPEED_LIMIT` and
297297
`GIT_HTTP_LOW_SPEED_TIME` environment variables.
298298

299+
http.keepAliveIdle::
300+
Specifies how long in seconds to wait on an idle connection
301+
before sending TCP keepalive probes (if supported by the OS). If
302+
unset, curl's default value is used. Can be overridden by the
303+
`GIT_HTTP_KEEPALIVE_IDLE` environment variable.
304+
305+
http.keepAliveInterval::
306+
Specifies how long in seconds to wait between TCP keepalive
307+
probes (if supported by the OS). If unset, curl's default value
308+
is used. Can be overridden by the `GIT_HTTP_KEEPALIVE_INTERVAL`
309+
environment variable.
310+
311+
http.keepAliveCount::
312+
Specifies how many TCP keepalive probes to send before giving up
313+
and terminating the connection (if supported by the OS). If
314+
unset, curl's default value is used. Can be overridden by the
315+
`GIT_HTTP_KEEPALIVE_COUNT` environment variable.
316+
299317
http.noEPSV::
300318
A boolean which disables using of EPSV ftp command by curl.
301319
This can be helpful with some "poor" ftp servers which don't

git-curl-compat.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,11 @@
4545
#define GIT_CURL_HAVE_CURLOPT_PROTOCOLS_STR 1
4646
#endif
4747

48+
/**
49+
* CURLOPT_TCP_KEEPCNT was added in 8.9.0, released in July, 2024.
50+
*/
51+
#if LIBCURL_VERSION_NUM >= 0x080900
52+
#define GIT_CURL_HAVE_CURLOPT_TCP_KEEPCNT
53+
#endif
54+
4855
#endif

http.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ static struct {
104104
};
105105
#endif
106106

107+
static long curl_tcp_keepidle = -1;
108+
static long curl_tcp_keepintvl = -1;
109+
static long curl_tcp_keepcnt = -1;
110+
107111
enum proactive_auth {
108112
PROACTIVE_AUTH_NONE = 0,
109113
PROACTIVE_AUTH_IF_CREDENTIALS,
@@ -557,6 +561,19 @@ static int http_options(const char *var, const char *value,
557561
return 0;
558562
}
559563

564+
if (!strcmp("http.keepaliveidle", var)) {
565+
curl_tcp_keepidle = git_config_int(var, value, ctx->kvi);
566+
return 0;
567+
}
568+
if (!strcmp("http.keepaliveinterval", var)) {
569+
curl_tcp_keepintvl = git_config_int(var, value, ctx->kvi);
570+
return 0;
571+
}
572+
if (!strcmp("http.keepalivecount", var)) {
573+
curl_tcp_keepcnt = git_config_int(var, value, ctx->kvi);
574+
return 0;
575+
}
576+
560577
/* Fall back on the default ones */
561578
return git_default_config(var, value, ctx, data);
562579
}
@@ -704,7 +721,6 @@ static int has_proxy_cert_password(void)
704721
return 1;
705722
}
706723

707-
708724
/* Return 1 if redactions have been made, 0 otherwise. */
709725
static int redact_sensitive_header(struct strbuf *header, size_t offset)
710726
{
@@ -1240,6 +1256,17 @@ static CURL *get_curl_handle(void)
12401256

12411257
curl_easy_setopt(result, CURLOPT_TCP_KEEPALIVE, 1);
12421258

1259+
if (curl_tcp_keepidle > -1)
1260+
curl_easy_setopt(result, CURLOPT_TCP_KEEPIDLE,
1261+
curl_tcp_keepidle);
1262+
if (curl_tcp_keepintvl > -1)
1263+
curl_easy_setopt(result, CURLOPT_TCP_KEEPINTVL,
1264+
curl_tcp_keepintvl);
1265+
#ifdef GIT_CURL_HAVE_CURLOPT_TCP_KEEPCNT
1266+
if (curl_tcp_keepcnt > -1)
1267+
curl_easy_setopt(result, CURLOPT_TCP_KEEPCNT, curl_tcp_keepcnt);
1268+
#endif
1269+
12431270
return result;
12441271
}
12451272

@@ -1382,6 +1409,10 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
13821409
ssl_cert_password_required = 1;
13831410
}
13841411

1412+
set_long_from_env(&curl_tcp_keepidle, "GIT_TCP_KEEPIDLE");
1413+
set_long_from_env(&curl_tcp_keepintvl, "GIT_TCP_KEEPINTVL");
1414+
set_long_from_env(&curl_tcp_keepcnt, "GIT_TCP_KEEPCNT");
1415+
13851416
curl_default = get_curl_handle();
13861417
}
13871418

0 commit comments

Comments
 (0)