Skip to content

Commit 36acec7

Browse files
committed
Merge branch 'tb/http-curl-keepalive'
TCP keepalive behaviour on http transports can now be configured by calling cURL library. * tb/http-curl-keepalive: http.c: allow custom TCP keepalive behavior via config http.c: inline `set_curl_keepalive()` http.c: introduce `set_long_from_env()` for convenience http.c: remove unnecessary casts to long
2 parents c6b3824 + 46e6f9a commit 36acec7

File tree

3 files changed

+84
-16
lines changed

3 files changed

+84
-16
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: 59 additions & 16 deletions
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,
@@ -438,11 +442,11 @@ static int http_options(const char *var, const char *value,
438442
return 0;
439443
}
440444
if (!strcmp("http.lowspeedlimit", var)) {
441-
curl_low_speed_limit = (long)git_config_int(var, value, ctx->kvi);
445+
curl_low_speed_limit = git_config_int(var, value, ctx->kvi);
442446
return 0;
443447
}
444448
if (!strcmp("http.lowspeedtime", var)) {
445-
curl_low_speed_time = (long)git_config_int(var, value, ctx->kvi);
449+
curl_low_speed_time = git_config_int(var, value, ctx->kvi);
446450
return 0;
447451
}
448452

@@ -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,11 +721,6 @@ static int has_proxy_cert_password(void)
704721
return 1;
705722
}
706723

707-
static void set_curl_keepalive(CURL *c)
708-
{
709-
curl_easy_setopt(c, CURLOPT_TCP_KEEPALIVE, 1);
710-
}
711-
712724
/* Return 1 if redactions have been made, 0 otherwise. */
713725
static int redact_sensitive_header(struct strbuf *header, size_t offset)
714726
{
@@ -1242,7 +1254,18 @@ static CURL *get_curl_handle(void)
12421254
}
12431255
init_curl_proxy_auth(result);
12441256

1245-
set_curl_keepalive(result);
1257+
curl_easy_setopt(result, CURLOPT_TCP_KEEPALIVE, 1);
1258+
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
12461269

12471270
return result;
12481271
}
@@ -1256,10 +1279,30 @@ static void set_from_env(char **var, const char *envname)
12561279
}
12571280
}
12581281

1282+
static void set_long_from_env(long *var, const char *envname)
1283+
{
1284+
const char *val = getenv(envname);
1285+
if (val) {
1286+
long tmp;
1287+
char *endp;
1288+
int saved_errno = errno;
1289+
1290+
errno = 0;
1291+
tmp = strtol(val, &endp, 10);
1292+
1293+
if (errno)
1294+
warning_errno(_("failed to parse %s"), envname);
1295+
else if (*endp || endp == val)
1296+
warning(_("failed to parse %s"), envname);
1297+
else
1298+
*var = tmp;
1299+
1300+
errno = saved_errno;
1301+
}
1302+
}
1303+
12591304
void http_init(struct remote *remote, const char *url, int proactive_auth)
12601305
{
1261-
char *low_speed_limit;
1262-
char *low_speed_time;
12631306
char *normalized_url;
12641307
struct urlmatch_config config = URLMATCH_CONFIG_INIT;
12651308

@@ -1338,12 +1381,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
13381381

13391382
set_from_env(&user_agent, "GIT_HTTP_USER_AGENT");
13401383

1341-
low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT");
1342-
if (low_speed_limit)
1343-
curl_low_speed_limit = strtol(low_speed_limit, NULL, 10);
1344-
low_speed_time = getenv("GIT_HTTP_LOW_SPEED_TIME");
1345-
if (low_speed_time)
1346-
curl_low_speed_time = strtol(low_speed_time, NULL, 10);
1384+
set_long_from_env(&curl_low_speed_limit, "GIT_HTTP_LOW_SPEED_LIMIT");
1385+
set_long_from_env(&curl_low_speed_time, "GIT_HTTP_LOW_SPEED_TIME");
13471386

13481387
if (curl_ssl_verify == -1)
13491388
curl_ssl_verify = 1;
@@ -1370,6 +1409,10 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
13701409
ssl_cert_password_required = 1;
13711410
}
13721411

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+
13731416
curl_default = get_curl_handle();
13741417
}
13751418

0 commit comments

Comments
 (0)