* [PATCH 0/3] http: support fine-tuning curl's keepalive behavior
@ 2025-03-18 22:21 Taylor Blau
2025-03-18 22:21 ` [PATCH 1/3] http.c: introduce `set_long_from_env()` for convenience Taylor Blau
` (3 more replies)
0 siblings, 4 replies; 21+ messages in thread
From: Taylor Blau @ 2025-03-18 22:21 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Elijah Newren
This short series introduces a few new http.* configuration options to
control curl's behavior around TCP keepalive packets. The details are
spelled out in the final patch, but the gist is:
- http.keepAliveIdle specifies how long in seconds to wait on an idle
connection before beginning to send keepalive packets.
- http.keepAliveInterval does the same but controls the interval
between successive keepalive packets.
- http.keepAliveCount specifies how many keepalive packets to send
before closing down the connection.
The first two commits of the series are general code clean-up of a
couple of small things I noticed while reading through the http.c code,
and the final patch implements these new options.
I couldn't think of a great way to test these new configuration
settings, and given the simplicity of the final patch I opted for no
tests there. But if someone has a good idea of how to test this
behavior, please let me know.
In either case, thanks in advance for your review!
Taylor Blau (3):
http.c: introduce `set_long_from_env()` for convenience
http.c: inline `set_curl_keepalive()`
http.c: allow custom TCP keepalive behavior via config
Documentation/config/http.adoc | 18 ++++++++++++
http.c | 54 +++++++++++++++++++++++++---------
2 files changed, 58 insertions(+), 14 deletions(-)
base-commit: 683c54c999c301c2cd6f715c411407c413b1d84e
--
2.49.0.3.gbb7a4a684c.dirty
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 1/3] http.c: introduce `set_long_from_env()` for convenience
2025-03-18 22:21 [PATCH 0/3] http: support fine-tuning curl's keepalive behavior Taylor Blau
@ 2025-03-18 22:21 ` Taylor Blau
2025-03-19 16:00 ` Elijah Newren
2025-03-19 16:00 ` Patrick Steinhardt
2025-03-18 22:21 ` [PATCH 2/3] http.c: inline `set_curl_keepalive()` Taylor Blau
` (2 subsequent siblings)
3 siblings, 2 replies; 21+ messages in thread
From: Taylor Blau @ 2025-03-18 22:21 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Elijah Newren
In 7059cd99fc (http_init(): Fix config file parsing, 2009-03-09), http.c
gained a new "set_from_env()" function as a convenience function around
conditionally assigning an environment variable to some variable if and
only if the environment variable was set to begin with.
But prior to 7059cd99fc, there were two spots which need to first
strtol() whatever is set in the environment before assigning it to a
long pointer. Both instances stored the result of getenv() in a
temporary variable, and conditionally strtol() it depending on whether
or not getenv() returned NULL.
Replace those two instances with a new cousin of 'set_from_env()' called
'set_long_from_env()', which does what its name suggests. This allows us
to remove the temporary variables and clean up some minor code
duplication. More importantly, however, it prepares us for a future
commit which will introduce more instances of assigning an environment
variable to a long.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
http.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/http.c b/http.c
index 0c9a872809..be564fd520 100644
--- a/http.c
+++ b/http.c
@@ -1256,10 +1256,15 @@ static void set_from_env(char **var, const char *envname)
}
}
+static void set_long_from_env(long *var, const char *envname)
+{
+ const char *val = getenv(envname);
+ if (val)
+ *var = strtol(val, NULL, 10);
+}
+
void http_init(struct remote *remote, const char *url, int proactive_auth)
{
- char *low_speed_limit;
- char *low_speed_time;
char *normalized_url;
struct urlmatch_config config = URLMATCH_CONFIG_INIT;
@@ -1338,12 +1343,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
set_from_env(&user_agent, "GIT_HTTP_USER_AGENT");
- low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT");
- if (low_speed_limit)
- curl_low_speed_limit = strtol(low_speed_limit, NULL, 10);
- low_speed_time = getenv("GIT_HTTP_LOW_SPEED_TIME");
- if (low_speed_time)
- curl_low_speed_time = strtol(low_speed_time, NULL, 10);
+ set_long_from_env(&curl_low_speed_limit, "GIT_HTTP_LOW_SPEED_LIMIT");
+ set_long_from_env(&curl_low_speed_time, "GIT_HTTP_LOW_SPEED_TIME");
if (curl_ssl_verify == -1)
curl_ssl_verify = 1;
--
2.49.0.3.gbb7a4a684c.dirty
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 2/3] http.c: inline `set_curl_keepalive()`
2025-03-18 22:21 [PATCH 0/3] http: support fine-tuning curl's keepalive behavior Taylor Blau
2025-03-18 22:21 ` [PATCH 1/3] http.c: introduce `set_long_from_env()` for convenience Taylor Blau
@ 2025-03-18 22:21 ` Taylor Blau
2025-03-19 16:01 ` Elijah Newren
2025-03-18 22:21 ` [PATCH 3/3] http.c: allow custom TCP keepalive behavior via config Taylor Blau
2025-03-19 22:23 ` [PATCH v2 0/4] http: support fine-tuning curl's keepalive behavior Taylor Blau
3 siblings, 1 reply; 21+ messages in thread
From: Taylor Blau @ 2025-03-18 22:21 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Elijah Newren
At the end of `get_curl_handle()` we call `set_curl_keepalive()` to
enable TCP keepalive probes on our CURL handle. `set_curl_keepalive()`
dates back to 47ce115370 (http: use curl's tcp keepalive if available,
2013-10-14), which conditionally compiled different variants of
`set_curl_keepalive()` depending on what version of curl we were
compiled with[^1].
As of f7c094060c (git-curl-compat: remove check for curl 7.25.0,
2024-10-23), we no longer conditionally compile `set_curl_keepalive()`
since we no longer support pre-7.25.0 versions of curl. But the version
of that function that we kept is really just a thin wrapper around
setting the TCP_KEEPALIVE option, so there's no reason to keep it in its
own function.
Inline the definition of `set_curl_keepalive()` to within
`get_curl_handle()` so that the setup of our CURL handle is
self-contained.
[1]: The details are spelled out in 47ce115370, but the gist is curl
7.25.0 and newer use CURLOPT_TCP_KEEPALIVE, older versions use
CURLOPT_SOCKOPTFUNCTION with a custom callback, and older versions
that predate even that option do nothing.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
http.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/http.c b/http.c
index be564fd520..526f9680f9 100644
--- a/http.c
+++ b/http.c
@@ -704,10 +704,6 @@ static int has_proxy_cert_password(void)
return 1;
}
-static void set_curl_keepalive(CURL *c)
-{
- curl_easy_setopt(c, CURLOPT_TCP_KEEPALIVE, 1);
-}
/* Return 1 if redactions have been made, 0 otherwise. */
static int redact_sensitive_header(struct strbuf *header, size_t offset)
@@ -1242,7 +1238,7 @@ static CURL *get_curl_handle(void)
}
init_curl_proxy_auth(result);
- set_curl_keepalive(result);
+ curl_easy_setopt(result, CURLOPT_TCP_KEEPALIVE, 1);
return result;
}
--
2.49.0.3.gbb7a4a684c.dirty
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH 3/3] http.c: allow custom TCP keepalive behavior via config
2025-03-18 22:21 [PATCH 0/3] http: support fine-tuning curl's keepalive behavior Taylor Blau
2025-03-18 22:21 ` [PATCH 1/3] http.c: introduce `set_long_from_env()` for convenience Taylor Blau
2025-03-18 22:21 ` [PATCH 2/3] http.c: inline `set_curl_keepalive()` Taylor Blau
@ 2025-03-18 22:21 ` Taylor Blau
2025-03-19 16:00 ` Patrick Steinhardt
2025-03-19 22:23 ` [PATCH v2 0/4] http: support fine-tuning curl's keepalive behavior Taylor Blau
3 siblings, 1 reply; 21+ messages in thread
From: Taylor Blau @ 2025-03-18 22:21 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Elijah Newren
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.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
Documentation/config/http.adoc | 18 ++++++++++++++++++
http.c | 31 ++++++++++++++++++++++++++++++-
2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/Documentation/config/http.adoc b/Documentation/config/http.adoc
index 22a8803dea..67393282fa 100644
--- a/Documentation/config/http.adoc
+++ b/Documentation/config/http.adoc
@@ -296,6 +296,24 @@ http.lowSpeedLimit, http.lowSpeedTime::
Can be overridden by the `GIT_HTTP_LOW_SPEED_LIMIT` and
`GIT_HTTP_LOW_SPEED_TIME` environment variables.
+http.keepAliveIdle::
+ Specifies how long in seconds to wait on an idle connection
+ before sending TCP keepalive probes (if supported by the OS). If
+ unset, curl's default value is used. Can be overridden by the
+ `GIT_HTTP_KEEPALIVE_IDLE` environment variable.
+
+http.keepAliveInterval::
+ Specifies how long in seconds to wait between TCP keepalive
+ probes (if supported by the OS). If unset, curl's default value
+ is used. Can be overridden by the `GIT_HTTP_KEEPALIVE_INTERVAL`
+ environment variable.
+
+http.keepAliveCount::
+ Specifies how many TCP keepalive probes to send before giving up
+ and terminating the connection (if supported by the OS). If
+ unset, curl's default value is used. Can be overridden by the
+ `GIT_HTTP_KEEPALIVE_COUNT` environment variable.
+
http.noEPSV::
A boolean which disables using of EPSV ftp command by curl.
This can be helpful with some "poor" ftp servers which don't
diff --git a/http.c b/http.c
index 526f9680f9..c13c7da530 100644
--- a/http.c
+++ b/http.c
@@ -104,6 +104,10 @@ static struct {
};
#endif
+static long curl_tcp_keepidle = -1;
+static long curl_tcp_keepintvl = -1;
+static long curl_tcp_keepcnt = -1;
+
enum proactive_auth {
PROACTIVE_AUTH_NONE = 0,
PROACTIVE_AUTH_IF_CREDENTIALS,
@@ -557,6 +561,19 @@ static int http_options(const char *var, const char *value,
return 0;
}
+ if (!strcmp("http.keepaliveidle", var)) {
+ curl_tcp_keepidle = (long)git_config_int(var, value, ctx->kvi);
+ return 0;
+ }
+ if (!strcmp("http.keepaliveinterval", var)) {
+ curl_tcp_keepintvl = (long)git_config_int(var, value, ctx->kvi);
+ return 0;
+ }
+ if (!strcmp("http.keepalivecount", var)) {
+ curl_tcp_keepcnt = (long)git_config_int(var, value, ctx->kvi);
+ return 0;
+ }
+
/* Fall back on the default ones */
return git_default_config(var, value, ctx, data);
}
@@ -704,7 +721,6 @@ static int has_proxy_cert_password(void)
return 1;
}
-
/* Return 1 if redactions have been made, 0 otherwise. */
static int redact_sensitive_header(struct strbuf *header, size_t offset)
{
@@ -1240,6 +1256,15 @@ static CURL *get_curl_handle(void)
curl_easy_setopt(result, CURLOPT_TCP_KEEPALIVE, 1);
+ if (curl_tcp_keepidle > -1)
+ curl_easy_setopt(result, CURLOPT_TCP_KEEPIDLE,
+ curl_tcp_keepidle);
+ if (curl_tcp_keepintvl > -1)
+ curl_easy_setopt(result, CURLOPT_TCP_KEEPINTVL,
+ curl_tcp_keepintvl);
+ if (curl_tcp_keepcnt > -1)
+ curl_easy_setopt(result, CURLOPT_TCP_KEEPCNT, curl_tcp_keepcnt);
+
return result;
}
@@ -1367,6 +1392,10 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
ssl_cert_password_required = 1;
}
+ set_long_from_env(&curl_tcp_keepidle, "GIT_TCP_KEEPIDLE");
+ set_long_from_env(&curl_tcp_keepintvl, "GIT_TCP_KEEPINTVL");
+ set_long_from_env(&curl_tcp_keepcnt, "GIT_TCP_KEEPCNT");
+
curl_default = get_curl_handle();
}
--
2.49.0.3.gbb7a4a684c.dirty
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH 1/3] http.c: introduce `set_long_from_env()` for convenience
2025-03-18 22:21 ` [PATCH 1/3] http.c: introduce `set_long_from_env()` for convenience Taylor Blau
@ 2025-03-19 16:00 ` Elijah Newren
2025-03-19 16:00 ` Patrick Steinhardt
1 sibling, 0 replies; 21+ messages in thread
From: Elijah Newren @ 2025-03-19 16:00 UTC (permalink / raw)
To: Taylor Blau; +Cc: git, Junio C Hamano
On Tue, Mar 18, 2025 at 3:21 PM Taylor Blau <me@ttaylorr.com> wrote:
>
> In 7059cd99fc (http_init(): Fix config file parsing, 2009-03-09), http.c
> gained a new "set_from_env()" function as a convenience function around
> conditionally assigning an environment variable to some variable if and
> only if the environment variable was set to begin with.
>
> But prior to 7059cd99fc, there were two spots which need to first
> strtol() whatever is set in the environment before assigning it to a
> long pointer. Both instances stored the result of getenv() in a
> temporary variable, and conditionally strtol() it depending on whether
> or not getenv() returned NULL.
>
> Replace those two instances with a new cousin of 'set_from_env()' called
> 'set_long_from_env()', which does what its name suggests. This allows us
> to remove the temporary variables and clean up some minor code
> duplication. More importantly, however, it prepares us for a future
> commit which will introduce more instances of assigning an environment
> variable to a long.
>
> Signed-off-by: Taylor Blau <me@ttaylorr.com>
> ---
> http.c | 17 +++++++++--------
> 1 file changed, 9 insertions(+), 8 deletions(-)
>
> diff --git a/http.c b/http.c
> index 0c9a872809..be564fd520 100644
> --- a/http.c
> +++ b/http.c
> @@ -1256,10 +1256,15 @@ static void set_from_env(char **var, const char *envname)
> }
> }
>
> +static void set_long_from_env(long *var, const char *envname)
> +{
> + const char *val = getenv(envname);
> + if (val)
> + *var = strtol(val, NULL, 10);
> +}
> +
> void http_init(struct remote *remote, const char *url, int proactive_auth)
> {
> - char *low_speed_limit;
> - char *low_speed_time;
> char *normalized_url;
> struct urlmatch_config config = URLMATCH_CONFIG_INIT;
>
> @@ -1338,12 +1343,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
>
> set_from_env(&user_agent, "GIT_HTTP_USER_AGENT");
>
> - low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT");
> - if (low_speed_limit)
> - curl_low_speed_limit = strtol(low_speed_limit, NULL, 10);
> - low_speed_time = getenv("GIT_HTTP_LOW_SPEED_TIME");
> - if (low_speed_time)
> - curl_low_speed_time = strtol(low_speed_time, NULL, 10);
> + set_long_from_env(&curl_low_speed_limit, "GIT_HTTP_LOW_SPEED_LIMIT");
> + set_long_from_env(&curl_low_speed_time, "GIT_HTTP_LOW_SPEED_TIME");
>
> if (curl_ssl_verify == -1)
> curl_ssl_verify = 1;
> --
> 2.49.0.3.gbb7a4a684c.dirty
No behavioral changes, just the use of a new convenience function;
simple enough.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 1/3] http.c: introduce `set_long_from_env()` for convenience
2025-03-18 22:21 ` [PATCH 1/3] http.c: introduce `set_long_from_env()` for convenience Taylor Blau
2025-03-19 16:00 ` Elijah Newren
@ 2025-03-19 16:00 ` Patrick Steinhardt
2025-03-19 18:02 ` Taylor Blau
1 sibling, 1 reply; 21+ messages in thread
From: Patrick Steinhardt @ 2025-03-19 16:00 UTC (permalink / raw)
To: Taylor Blau; +Cc: git, Junio C Hamano, Elijah Newren
On Tue, Mar 18, 2025 at 06:21:34PM -0400, Taylor Blau wrote:
> In 7059cd99fc (http_init(): Fix config file parsing, 2009-03-09), http.c
> gained a new "set_from_env()" function as a convenience function around
> conditionally assigning an environment variable to some variable if and
> only if the environment variable was set to begin with.
>
> But prior to 7059cd99fc, there were two spots which need to first
> strtol() whatever is set in the environment before assigning it to a
> long pointer. Both instances stored the result of getenv() in a
> temporary variable, and conditionally strtol() it depending on whether
> or not getenv() returned NULL.
>
> Replace those two instances with a new cousin of 'set_from_env()' called
> 'set_long_from_env()', which does what its name suggests. This allows us
> to remove the temporary variables and clean up some minor code
> duplication. More importantly, however, it prepares us for a future
> commit which will introduce more instances of assigning an environment
> variable to a long.
Okay, makes sense.
> Signed-off-by: Taylor Blau <me@ttaylorr.com>
> ---
> http.c | 17 +++++++++--------
> 1 file changed, 9 insertions(+), 8 deletions(-)
>
> diff --git a/http.c b/http.c
> index 0c9a872809..be564fd520 100644
> --- a/http.c
> +++ b/http.c
> @@ -1256,10 +1256,15 @@ static void set_from_env(char **var, const char *envname)
> }
> }
>
> +static void set_long_from_env(long *var, const char *envname)
> +{
> + const char *val = getenv(envname);
> + if (val)
> + *var = strtol(val, NULL, 10);
> +}
Hm. We don't perform any error checking at all for whether or not the
value of the environment variable is a valid integer. This isn't a new
issue introduced by your patch, but now that we have a central place
where it's being parsed I wonder whether we should be checking for
errors?
Patrick
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 3/3] http.c: allow custom TCP keepalive behavior via config
2025-03-18 22:21 ` [PATCH 3/3] http.c: allow custom TCP keepalive behavior via config Taylor Blau
@ 2025-03-19 16:00 ` Patrick Steinhardt
2025-03-19 16:15 ` Elijah Newren
2025-03-19 18:05 ` Taylor Blau
0 siblings, 2 replies; 21+ messages in thread
From: Patrick Steinhardt @ 2025-03-19 16:00 UTC (permalink / raw)
To: Taylor Blau; +Cc: git, Junio C Hamano, Elijah Newren
On Tue, Mar 18, 2025 at 06:21:41PM -0400, Taylor Blau wrote:
> 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.
Does this mean that our defaults are insufficient, as well? It's nice to
add a way to adapt those settings for the future, but ideally no user
should ever have to manually tweak them and Git should work out of the
box.
> diff --git a/http.c b/http.c
> index 526f9680f9..c13c7da530 100644
> --- a/http.c
> +++ b/http.c
> @@ -557,6 +561,19 @@ static int http_options(const char *var, const char *value,
> return 0;
> }
>
> + if (!strcmp("http.keepaliveidle", var)) {
> + curl_tcp_keepidle = (long)git_config_int(var, value, ctx->kvi);
> + return 0;
> + }
> + if (!strcmp("http.keepaliveinterval", var)) {
> + curl_tcp_keepintvl = (long)git_config_int(var, value, ctx->kvi);
> + return 0;
> + }
> + if (!strcmp("http.keepalivecount", var)) {
> + curl_tcp_keepcnt = (long)git_config_int(var, value, ctx->kvi);
> + return 0;
> + }
> +
> /* Fall back on the default ones */
> return git_default_config(var, value, ctx, data);
> }
Are the casts really necessary? The compiler shouldn't complain when
promoting from `int` to `long`.
Patrick
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 2/3] http.c: inline `set_curl_keepalive()`
2025-03-18 22:21 ` [PATCH 2/3] http.c: inline `set_curl_keepalive()` Taylor Blau
@ 2025-03-19 16:01 ` Elijah Newren
0 siblings, 0 replies; 21+ messages in thread
From: Elijah Newren @ 2025-03-19 16:01 UTC (permalink / raw)
To: Taylor Blau; +Cc: git, Junio C Hamano
On Tue, Mar 18, 2025 at 3:21 PM Taylor Blau <me@ttaylorr.com> wrote:
>
> At the end of `get_curl_handle()` we call `set_curl_keepalive()` to
> enable TCP keepalive probes on our CURL handle. `set_curl_keepalive()`
> dates back to 47ce115370 (http: use curl's tcp keepalive if available,
> 2013-10-14), which conditionally compiled different variants of
> `set_curl_keepalive()` depending on what version of curl we were
> compiled with[^1].
>
> As of f7c094060c (git-curl-compat: remove check for curl 7.25.0,
> 2024-10-23), we no longer conditionally compile `set_curl_keepalive()`
> since we no longer support pre-7.25.0 versions of curl. But the version
> of that function that we kept is really just a thin wrapper around
> setting the TCP_KEEPALIVE option, so there's no reason to keep it in its
> own function.
>
> Inline the definition of `set_curl_keepalive()` to within
> `get_curl_handle()` so that the setup of our CURL handle is
> self-contained.
>
> [1]: The details are spelled out in 47ce115370, but the gist is curl
> 7.25.0 and newer use CURLOPT_TCP_KEEPALIVE, older versions use
> CURLOPT_SOCKOPTFUNCTION with a custom callback, and older versions
> that predate even that option do nothing.
>
> Signed-off-by: Taylor Blau <me@ttaylorr.com>
> ---
> http.c | 6 +-----
> 1 file changed, 1 insertion(+), 5 deletions(-)
>
> diff --git a/http.c b/http.c
> index be564fd520..526f9680f9 100644
> --- a/http.c
> +++ b/http.c
> @@ -704,10 +704,6 @@ static int has_proxy_cert_password(void)
> return 1;
> }
>
> -static void set_curl_keepalive(CURL *c)
> -{
> - curl_easy_setopt(c, CURLOPT_TCP_KEEPALIVE, 1);
> -}
>
> /* Return 1 if redactions have been made, 0 otherwise. */
> static int redact_sensitive_header(struct strbuf *header, size_t offset)
> @@ -1242,7 +1238,7 @@ static CURL *get_curl_handle(void)
> }
> init_curl_proxy_auth(result);
>
> - set_curl_keepalive(result);
> + curl_easy_setopt(result, CURLOPT_TCP_KEEPALIVE, 1);
>
> return result;
> }
> --
> 2.49.0.3.gbb7a4a684c.dirty
In contrast to the last patch, this simply dispenses with rather than
adds a convenience function. That makes sense in this case, since it
was only a single line of code anyway.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 3/3] http.c: allow custom TCP keepalive behavior via config
2025-03-19 16:00 ` Patrick Steinhardt
@ 2025-03-19 16:15 ` Elijah Newren
2025-03-19 18:05 ` Taylor Blau
1 sibling, 0 replies; 21+ messages in thread
From: Elijah Newren @ 2025-03-19 16:15 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: Taylor Blau, git, Junio C Hamano
On Wed, Mar 19, 2025 at 9:00 AM Patrick Steinhardt <ps@pks.im> wrote:
>
> On Tue, Mar 18, 2025 at 06:21:41PM -0400, Taylor Blau wrote:
> > 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.
>
> Does this mean that our defaults are insufficient, as well? It's nice to
> add a way to adapt those settings for the future, but ideally no user
> should ever have to manually tweak them and Git should work out of the
> box.
Was going to comment with the same question.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 1/3] http.c: introduce `set_long_from_env()` for convenience
2025-03-19 16:00 ` Patrick Steinhardt
@ 2025-03-19 18:02 ` Taylor Blau
0 siblings, 0 replies; 21+ messages in thread
From: Taylor Blau @ 2025-03-19 18:02 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: git, Junio C Hamano, Elijah Newren
On Wed, Mar 19, 2025 at 05:00:43PM +0100, Patrick Steinhardt wrote:
> > diff --git a/http.c b/http.c
> > index 0c9a872809..be564fd520 100644
> > --- a/http.c
> > +++ b/http.c
> > @@ -1256,10 +1256,15 @@ static void set_from_env(char **var, const char *envname)
> > }
> > }
> >
> > +static void set_long_from_env(long *var, const char *envname)
> > +{
> > + const char *val = getenv(envname);
> > + if (val)
> > + *var = strtol(val, NULL, 10);
> > +}
>
> Hm. We don't perform any error checking at all for whether or not the
> value of the environment variable is a valid integer. This isn't a new
> issue introduced by your patch, but now that we have a central place
> where it's being parsed I wonder whether we should be checking for
> errors?
Yeah, I guess it's technically not "new" in the sense that we were
already doing:
xyz = getenv("XYZ");
if (xyz)
*var = strtol(xyz, NULL, 10);
I suppose we could do something like:
--- 8< ---
diff --git a/http.c b/http.c
index c13c7da530..6b01ad7a53 100644
--- a/http.c
+++ b/http.c
@@ -1280,8 +1280,20 @@ static void set_from_env(char **var, const char *envname)
static void set_long_from_env(long *var, const char *envname)
{
const char *val = getenv(envname);
- if (val)
- *var = strtol(val, NULL, 10);
+ if (val) {
+ long tmp;
+ char *endp;
+ errno = 0;
+ tmp = strtol(val, &endp, 10);
+ if (errno)
+ warning_errno(_("failed to parse '%s' (%s) as long"),
+ envname, val);
+ else if (endp == val)
+ warning(_("failed to parse '%s' (%s) as long"), envname,
+ val);
+ else
+ *var = tmp;
+ }
}
void http_init(struct remote *remote, const char *url, int proactive_auth)
--- >8 ---
On top, but TBH I'm not sure how much value it adds. This is only used
for reading GIT_XYZ variables out of the environment, and we're already
pretty lax about strtol() errors in other places. Since this isn't the
interface we expect users to use, I'm OK to punt on it for now unless
you feel strongly otherwise.
Thanks,
Taylor
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH 3/3] http.c: allow custom TCP keepalive behavior via config
2025-03-19 16:00 ` Patrick Steinhardt
2025-03-19 16:15 ` Elijah Newren
@ 2025-03-19 18:05 ` Taylor Blau
1 sibling, 0 replies; 21+ messages in thread
From: Taylor Blau @ 2025-03-19 18:05 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: git, Junio C Hamano, Elijah Newren
On Wed, Mar 19, 2025 at 05:00:51PM +0100, Patrick Steinhardt wrote:
> On Tue, Mar 18, 2025 at 06:21:41PM -0400, Taylor Blau wrote:
> > 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.
>
> Does this mean that our defaults are insufficient, as well? It's nice to
> add a way to adapt those settings for the future, but ideally no user
> should ever have to manually tweak them and Git should work out of the
> box.
No; the defaults are sufficient for most users. It's the users that have
extremely slow connections and/or are talking to hosts that have very
short timeouts for inactive TCP connections that would want to change
these values.
> > diff --git a/http.c b/http.c
> > index 526f9680f9..c13c7da530 100644
> > --- a/http.c
> > +++ b/http.c
> > @@ -557,6 +561,19 @@ static int http_options(const char *var, const char *value,
> > return 0;
> > }
> >
> > + if (!strcmp("http.keepaliveidle", var)) {
> > + curl_tcp_keepidle = (long)git_config_int(var, value, ctx->kvi);
> > + return 0;
> > + }
> > + if (!strcmp("http.keepaliveinterval", var)) {
> > + curl_tcp_keepintvl = (long)git_config_int(var, value, ctx->kvi);
> > + return 0;
> > + }
> > + if (!strcmp("http.keepalivecount", var)) {
> > + curl_tcp_keepcnt = (long)git_config_int(var, value, ctx->kvi);
> > + return 0;
> > + }
> > +
> > /* Fall back on the default ones */
> > return git_default_config(var, value, ctx, data);
> > }
>
> Are the casts really necessary? The compiler shouldn't complain when
> promoting from `int` to `long`.
No, they're not. They match the style of the rest of this file, but we
shouldn't have explicit casts anywhere. I'll send a new round with an
additional patch that drops the unnecessary casts, too.
Thanks,
Taylor
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 0/4] http: support fine-tuning curl's keepalive behavior
2025-03-18 22:21 [PATCH 0/3] http: support fine-tuning curl's keepalive behavior Taylor Blau
` (2 preceding siblings ...)
2025-03-18 22:21 ` [PATCH 3/3] http.c: allow custom TCP keepalive behavior via config Taylor Blau
@ 2025-03-19 22:23 ` Taylor Blau
2025-03-19 22:23 ` [PATCH v2 1/4] http.c: remove unnecessary casts to long Taylor Blau
` (4 more replies)
3 siblings, 5 replies; 21+ messages in thread
From: Taylor Blau @ 2025-03-19 22:23 UTC (permalink / raw)
To: git; +Cc: Jeff King, Junio C Hamano, Patrick Steinhardt
Here's a reroll of my series to introduce new http.* knobs to control
curl's TCP keepalive behavior.
This reroll is mostly minor, with the notable differences being limited
to:
- Added error handling in the new http.c::set_long_from_env().
- Removed unnecessary casts from int -> long.
- Only set CURLOPT_TCP_KEEPCNT when compiled with a version of curl
that knows about that option to begin with (>8.9.0).
As usual, a range-diff is included below for convenience. Thanks again
for reviewing!
== Original cover letter
This short series introduces a few new http.* configuration options to
control curl's behavior around TCP keepalive packets. The details are
spelled out in the final patch, but the gist is:
- http.keepAliveIdle specifies how long in seconds to wait on an idle
connection before beginning to send keepalive packets.
- http.keepAliveInterval does the same but controls the interval
between successive keepalive packets.
- http.keepAliveCount specifies how many keepalive packets to send
before closing down the connection.
The first two commits of the series are general code clean-up of a
couple of small things I noticed while reading through the http.c code,
and the final patch implements these new options.
I couldn't think of a great way to test these new configuration
settings, and given the simplicity of the final patch I opted for no
tests there. But if someone has a good idea of how to test this
behavior, please let me know.
In either case, thanks in advance for your review!
Taylor Blau (4):
http.c: remove unnecessary casts to long
http.c: introduce `set_long_from_env()` for convenience
http.c: inline `set_curl_keepalive()`
http.c: allow custom TCP keepalive behavior via config
Documentation/config/http.adoc | 18 ++++++++
git-curl-compat.h | 7 ++++
http.c | 75 ++++++++++++++++++++++++++--------
3 files changed, 84 insertions(+), 16 deletions(-)
Range-diff against v1:
-: ---------- > 1: 204e5e18d2 http.c: remove unnecessary casts to long
1: ba22a121fa ! 2: 2e39a78e87 http.c: introduce `set_long_from_env()` for convenience
@@ Commit message
Replace those two instances with a new cousin of 'set_from_env()' called
'set_long_from_env()', which does what its name suggests. This allows us
to remove the temporary variables and clean up some minor code
- duplication. More importantly, however, it prepares us for a future
- commit which will introduce more instances of assigning an environment
- variable to a long.
+ duplication while also adding more robust error handling.
+
+ More importantly, however, it prepares us for a future commit which will
+ introduce more instances of assigning an environment variable to a long.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
@@ http.c: static void set_from_env(char **var, const char *envname)
+static void set_long_from_env(long *var, const char *envname)
+{
+ const char *val = getenv(envname);
-+ if (val)
-+ *var = strtol(val, NULL, 10);
++ if (val) {
++ long tmp;
++ char *endp;
++ int saved_errno = errno;
++
++ errno = 0;
++ tmp = strtol(val, &endp, 10);
++
++ if (errno)
++ warning_errno(_("failed to parse %s"), envname);
++ else if (*endp || endp == val)
++ warning(_("failed to parse %s"), envname);
++ else
++ *var = tmp;
++
++ errno = saved_errno;
++ }
+}
+
void http_init(struct remote *remote, const char *url, int proactive_auth)
2: a05269552f = 3: cdfc9baa8d http.c: inline `set_curl_keepalive()`
3: d840415808 ! 4: 3fe62181e5 http.c: allow custom TCP keepalive behavior via config
@@ Commit message
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 f7c094060c
+ (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 <me@ttaylorr.com>
## Documentation/config/http.adoc ##
@@ Documentation/config/http.adoc: http.lowSpeedLimit, http.lowSpeedTime::
A boolean which disables using of EPSV ftp command by curl.
This can be helpful with some "poor" ftp servers which don't
+ ## git-curl-compat.h ##
+@@
+ #define GIT_CURL_HAVE_CURLOPT_PROTOCOLS_STR 1
+ #endif
+
++/**
++ * CURLOPT_TCP_KEEPCNT was added in 8.9.0, released in July, 2024.
++ */
++#if LIBCURL_VERSION_NUM >= 0x080900
++#define GIT_CURL_HAVE_CURLOPT_TCP_KEEPCNT
++#endif
++
+ #endif
+
## http.c ##
@@ http.c: static struct {
};
@@ http.c: static int http_options(const char *var, const char *value,
}
+ if (!strcmp("http.keepaliveidle", var)) {
-+ curl_tcp_keepidle = (long)git_config_int(var, value, ctx->kvi);
++ curl_tcp_keepidle = git_config_int(var, value, ctx->kvi);
+ return 0;
+ }
+ if (!strcmp("http.keepaliveinterval", var)) {
-+ curl_tcp_keepintvl = (long)git_config_int(var, value, ctx->kvi);
++ curl_tcp_keepintvl = git_config_int(var, value, ctx->kvi);
+ return 0;
+ }
+ if (!strcmp("http.keepalivecount", var)) {
-+ curl_tcp_keepcnt = (long)git_config_int(var, value, ctx->kvi);
++ curl_tcp_keepcnt = git_config_int(var, value, ctx->kvi);
+ return 0;
+ }
+
@@ http.c: static CURL *get_curl_handle(void)
+ if (curl_tcp_keepintvl > -1)
+ curl_easy_setopt(result, CURLOPT_TCP_KEEPINTVL,
+ curl_tcp_keepintvl);
++#ifdef GIT_CURL_HAVE_CURLOPT_TCP_KEEPCNT
+ if (curl_tcp_keepcnt > -1)
+ curl_easy_setopt(result, CURLOPT_TCP_KEEPCNT, curl_tcp_keepcnt);
++#endif
+
return result;
}
base-commit: 683c54c999c301c2cd6f715c411407c413b1d84e
--
2.49.0.4.ge59cf92f8d
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 1/4] http.c: remove unnecessary casts to long
2025-03-19 22:23 ` [PATCH v2 0/4] http: support fine-tuning curl's keepalive behavior Taylor Blau
@ 2025-03-19 22:23 ` Taylor Blau
2025-03-19 22:23 ` [PATCH v2 2/4] http.c: introduce `set_long_from_env()` for convenience Taylor Blau
` (3 subsequent siblings)
4 siblings, 0 replies; 21+ messages in thread
From: Taylor Blau @ 2025-03-19 22:23 UTC (permalink / raw)
To: git; +Cc: Jeff King, Junio C Hamano, Patrick Steinhardt
When parsing 'http.lowSpeedLimit' and 'http.lowSpeedTime', we explicitly
cast the result of 'git_config_int()' to a long before assignment. This
cast has been in place since all the way back in 58e60dd203 (Add support
for pushing to a remote repository using HTTP/DAV, 2005-11-02).
But that cast has always been unnecessary, since long is guaranteed to
be at least as wide as int. Let's drop the cast accordingly.
Noticed-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
http.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/http.c b/http.c
index 0c9a872809..0cbcb079b2 100644
--- a/http.c
+++ b/http.c
@@ -438,11 +438,11 @@ static int http_options(const char *var, const char *value,
return 0;
}
if (!strcmp("http.lowspeedlimit", var)) {
- curl_low_speed_limit = (long)git_config_int(var, value, ctx->kvi);
+ curl_low_speed_limit = git_config_int(var, value, ctx->kvi);
return 0;
}
if (!strcmp("http.lowspeedtime", var)) {
- curl_low_speed_time = (long)git_config_int(var, value, ctx->kvi);
+ curl_low_speed_time = git_config_int(var, value, ctx->kvi);
return 0;
}
--
2.49.0.4.ge59cf92f8d
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 2/4] http.c: introduce `set_long_from_env()` for convenience
2025-03-19 22:23 ` [PATCH v2 0/4] http: support fine-tuning curl's keepalive behavior Taylor Blau
2025-03-19 22:23 ` [PATCH v2 1/4] http.c: remove unnecessary casts to long Taylor Blau
@ 2025-03-19 22:23 ` Taylor Blau
2025-03-20 5:24 ` Patrick Steinhardt
2025-04-01 9:10 ` Jeff King
2025-03-19 22:23 ` [PATCH v2 3/4] http.c: inline `set_curl_keepalive()` Taylor Blau
` (2 subsequent siblings)
4 siblings, 2 replies; 21+ messages in thread
From: Taylor Blau @ 2025-03-19 22:23 UTC (permalink / raw)
To: git; +Cc: Jeff King, Junio C Hamano, Patrick Steinhardt
In 7059cd99fc (http_init(): Fix config file parsing, 2009-03-09), http.c
gained a new "set_from_env()" function as a convenience function around
conditionally assigning an environment variable to some variable if and
only if the environment variable was set to begin with.
But prior to 7059cd99fc, there were two spots which need to first
strtol() whatever is set in the environment before assigning it to a
long pointer. Both instances stored the result of getenv() in a
temporary variable, and conditionally strtol() it depending on whether
or not getenv() returned NULL.
Replace those two instances with a new cousin of 'set_from_env()' called
'set_long_from_env()', which does what its name suggests. This allows us
to remove the temporary variables and clean up some minor code
duplication while also adding more robust error handling.
More importantly, however, it prepares us for a future commit which will
introduce more instances of assigning an environment variable to a long.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
http.c | 32 ++++++++++++++++++++++++--------
1 file changed, 24 insertions(+), 8 deletions(-)
diff --git a/http.c b/http.c
index 0cbcb079b2..17b676a1d5 100644
--- a/http.c
+++ b/http.c
@@ -1256,10 +1256,30 @@ static void set_from_env(char **var, const char *envname)
}
}
+static void set_long_from_env(long *var, const char *envname)
+{
+ const char *val = getenv(envname);
+ if (val) {
+ long tmp;
+ char *endp;
+ int saved_errno = errno;
+
+ errno = 0;
+ tmp = strtol(val, &endp, 10);
+
+ if (errno)
+ warning_errno(_("failed to parse %s"), envname);
+ else if (*endp || endp == val)
+ warning(_("failed to parse %s"), envname);
+ else
+ *var = tmp;
+
+ errno = saved_errno;
+ }
+}
+
void http_init(struct remote *remote, const char *url, int proactive_auth)
{
- char *low_speed_limit;
- char *low_speed_time;
char *normalized_url;
struct urlmatch_config config = URLMATCH_CONFIG_INIT;
@@ -1338,12 +1358,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
set_from_env(&user_agent, "GIT_HTTP_USER_AGENT");
- low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT");
- if (low_speed_limit)
- curl_low_speed_limit = strtol(low_speed_limit, NULL, 10);
- low_speed_time = getenv("GIT_HTTP_LOW_SPEED_TIME");
- if (low_speed_time)
- curl_low_speed_time = strtol(low_speed_time, NULL, 10);
+ set_long_from_env(&curl_low_speed_limit, "GIT_HTTP_LOW_SPEED_LIMIT");
+ set_long_from_env(&curl_low_speed_time, "GIT_HTTP_LOW_SPEED_TIME");
if (curl_ssl_verify == -1)
curl_ssl_verify = 1;
--
2.49.0.4.ge59cf92f8d
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 3/4] http.c: inline `set_curl_keepalive()`
2025-03-19 22:23 ` [PATCH v2 0/4] http: support fine-tuning curl's keepalive behavior Taylor Blau
2025-03-19 22:23 ` [PATCH v2 1/4] http.c: remove unnecessary casts to long Taylor Blau
2025-03-19 22:23 ` [PATCH v2 2/4] http.c: introduce `set_long_from_env()` for convenience Taylor Blau
@ 2025-03-19 22:23 ` Taylor Blau
2025-04-01 9:12 ` Jeff King
2025-03-19 22:23 ` [PATCH v2 4/4] http.c: allow custom TCP keepalive behavior via config Taylor Blau
2025-03-19 22:49 ` [PATCH v2 0/4] http: support fine-tuning curl's keepalive behavior Elijah Newren
4 siblings, 1 reply; 21+ messages in thread
From: Taylor Blau @ 2025-03-19 22:23 UTC (permalink / raw)
To: git; +Cc: Jeff King, Junio C Hamano, Patrick Steinhardt
At the end of `get_curl_handle()` we call `set_curl_keepalive()` to
enable TCP keepalive probes on our CURL handle. `set_curl_keepalive()`
dates back to 47ce115370 (http: use curl's tcp keepalive if available,
2013-10-14), which conditionally compiled different variants of
`set_curl_keepalive()` depending on what version of curl we were
compiled with[^1].
As of f7c094060c (git-curl-compat: remove check for curl 7.25.0,
2024-10-23), we no longer conditionally compile `set_curl_keepalive()`
since we no longer support pre-7.25.0 versions of curl. But the version
of that function that we kept is really just a thin wrapper around
setting the TCP_KEEPALIVE option, so there's no reason to keep it in its
own function.
Inline the definition of `set_curl_keepalive()` to within
`get_curl_handle()` so that the setup of our CURL handle is
self-contained.
[1]: The details are spelled out in 47ce115370, but the gist is curl
7.25.0 and newer use CURLOPT_TCP_KEEPALIVE, older versions use
CURLOPT_SOCKOPTFUNCTION with a custom callback, and older versions
that predate even that option do nothing.
Signed-off-by: Taylor Blau <me@ttaylorr.com>
---
http.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/http.c b/http.c
index 17b676a1d5..b4267bfdb0 100644
--- a/http.c
+++ b/http.c
@@ -704,10 +704,6 @@ static int has_proxy_cert_password(void)
return 1;
}
-static void set_curl_keepalive(CURL *c)
-{
- curl_easy_setopt(c, CURLOPT_TCP_KEEPALIVE, 1);
-}
/* Return 1 if redactions have been made, 0 otherwise. */
static int redact_sensitive_header(struct strbuf *header, size_t offset)
@@ -1242,7 +1238,7 @@ static CURL *get_curl_handle(void)
}
init_curl_proxy_auth(result);
- set_curl_keepalive(result);
+ curl_easy_setopt(result, CURLOPT_TCP_KEEPALIVE, 1);
return result;
}
--
2.49.0.4.ge59cf92f8d
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 4/4] http.c: allow custom TCP keepalive behavior via config
2025-03-19 22:23 ` [PATCH v2 0/4] http: support fine-tuning curl's keepalive behavior Taylor Blau
` (2 preceding siblings ...)
2025-03-19 22:23 ` [PATCH v2 3/4] http.c: inline `set_curl_keepalive()` Taylor Blau
@ 2025-03-19 22:23 ` Taylor Blau
2025-04-01 9:16 ` Jeff King
2025-03-19 22:49 ` [PATCH v2 0/4] http: support fine-tuning curl's keepalive behavior Elijah Newren
4 siblings, 1 reply; 21+ messages in thread
From: Taylor Blau @ 2025-03-19 22:23 UTC (permalink / raw)
To: git; +Cc: Jeff King, Junio C Hamano, Patrick Steinhardt
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 f7c094060c
(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 <me@ttaylorr.com>
---
Documentation/config/http.adoc | 18 ++++++++++++++++++
git-curl-compat.h | 7 +++++++
http.c | 33 ++++++++++++++++++++++++++++++++-
3 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/Documentation/config/http.adoc b/Documentation/config/http.adoc
index 22a8803dea..67393282fa 100644
--- a/Documentation/config/http.adoc
+++ b/Documentation/config/http.adoc
@@ -296,6 +296,24 @@ http.lowSpeedLimit, http.lowSpeedTime::
Can be overridden by the `GIT_HTTP_LOW_SPEED_LIMIT` and
`GIT_HTTP_LOW_SPEED_TIME` environment variables.
+http.keepAliveIdle::
+ Specifies how long in seconds to wait on an idle connection
+ before sending TCP keepalive probes (if supported by the OS). If
+ unset, curl's default value is used. Can be overridden by the
+ `GIT_HTTP_KEEPALIVE_IDLE` environment variable.
+
+http.keepAliveInterval::
+ Specifies how long in seconds to wait between TCP keepalive
+ probes (if supported by the OS). If unset, curl's default value
+ is used. Can be overridden by the `GIT_HTTP_KEEPALIVE_INTERVAL`
+ environment variable.
+
+http.keepAliveCount::
+ Specifies how many TCP keepalive probes to send before giving up
+ and terminating the connection (if supported by the OS). If
+ unset, curl's default value is used. Can be overridden by the
+ `GIT_HTTP_KEEPALIVE_COUNT` environment variable.
+
http.noEPSV::
A boolean which disables using of EPSV ftp command by curl.
This can be helpful with some "poor" ftp servers which don't
diff --git a/git-curl-compat.h b/git-curl-compat.h
index 703756ba85..aa8eed7ed2 100644
--- a/git-curl-compat.h
+++ b/git-curl-compat.h
@@ -45,4 +45,11 @@
#define GIT_CURL_HAVE_CURLOPT_PROTOCOLS_STR 1
#endif
+/**
+ * CURLOPT_TCP_KEEPCNT was added in 8.9.0, released in July, 2024.
+ */
+#if LIBCURL_VERSION_NUM >= 0x080900
+#define GIT_CURL_HAVE_CURLOPT_TCP_KEEPCNT
+#endif
+
#endif
diff --git a/http.c b/http.c
index b4267bfdb0..d21e3a3bad 100644
--- a/http.c
+++ b/http.c
@@ -104,6 +104,10 @@ static struct {
};
#endif
+static long curl_tcp_keepidle = -1;
+static long curl_tcp_keepintvl = -1;
+static long curl_tcp_keepcnt = -1;
+
enum proactive_auth {
PROACTIVE_AUTH_NONE = 0,
PROACTIVE_AUTH_IF_CREDENTIALS,
@@ -557,6 +561,19 @@ static int http_options(const char *var, const char *value,
return 0;
}
+ if (!strcmp("http.keepaliveidle", var)) {
+ curl_tcp_keepidle = git_config_int(var, value, ctx->kvi);
+ return 0;
+ }
+ if (!strcmp("http.keepaliveinterval", var)) {
+ curl_tcp_keepintvl = git_config_int(var, value, ctx->kvi);
+ return 0;
+ }
+ if (!strcmp("http.keepalivecount", var)) {
+ curl_tcp_keepcnt = git_config_int(var, value, ctx->kvi);
+ return 0;
+ }
+
/* Fall back on the default ones */
return git_default_config(var, value, ctx, data);
}
@@ -704,7 +721,6 @@ static int has_proxy_cert_password(void)
return 1;
}
-
/* Return 1 if redactions have been made, 0 otherwise. */
static int redact_sensitive_header(struct strbuf *header, size_t offset)
{
@@ -1240,6 +1256,17 @@ static CURL *get_curl_handle(void)
curl_easy_setopt(result, CURLOPT_TCP_KEEPALIVE, 1);
+ if (curl_tcp_keepidle > -1)
+ curl_easy_setopt(result, CURLOPT_TCP_KEEPIDLE,
+ curl_tcp_keepidle);
+ if (curl_tcp_keepintvl > -1)
+ curl_easy_setopt(result, CURLOPT_TCP_KEEPINTVL,
+ curl_tcp_keepintvl);
+#ifdef GIT_CURL_HAVE_CURLOPT_TCP_KEEPCNT
+ if (curl_tcp_keepcnt > -1)
+ curl_easy_setopt(result, CURLOPT_TCP_KEEPCNT, curl_tcp_keepcnt);
+#endif
+
return result;
}
@@ -1382,6 +1409,10 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
ssl_cert_password_required = 1;
}
+ set_long_from_env(&curl_tcp_keepidle, "GIT_TCP_KEEPIDLE");
+ set_long_from_env(&curl_tcp_keepintvl, "GIT_TCP_KEEPINTVL");
+ set_long_from_env(&curl_tcp_keepcnt, "GIT_TCP_KEEPCNT");
+
curl_default = get_curl_handle();
}
--
2.49.0.4.ge59cf92f8d
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v2 0/4] http: support fine-tuning curl's keepalive behavior
2025-03-19 22:23 ` [PATCH v2 0/4] http: support fine-tuning curl's keepalive behavior Taylor Blau
` (3 preceding siblings ...)
2025-03-19 22:23 ` [PATCH v2 4/4] http.c: allow custom TCP keepalive behavior via config Taylor Blau
@ 2025-03-19 22:49 ` Elijah Newren
4 siblings, 0 replies; 21+ messages in thread
From: Elijah Newren @ 2025-03-19 22:49 UTC (permalink / raw)
To: Taylor Blau; +Cc: git, Jeff King, Junio C Hamano, Patrick Steinhardt
On Wed, Mar 19, 2025 at 3:37 PM Taylor Blau <me@ttaylorr.com> wrote:
>
> Here's a reroll of my series to introduce new http.* knobs to control
> curl's TCP keepalive behavior.
>
> This reroll is mostly minor, with the notable differences being limited
> to:
>
> - Added error handling in the new http.c::set_long_from_env().
>
> - Removed unnecessary casts from int -> long.
>
> - Only set CURLOPT_TCP_KEEPCNT when compiled with a version of curl
> that knows about that option to begin with (>8.9.0).
>
> As usual, a range-diff is included below for convenience. Thanks again
> for reviewing!
>
> == Original cover letter
>
> This short series introduces a few new http.* configuration options to
> control curl's behavior around TCP keepalive packets. The details are
> spelled out in the final patch, but the gist is:
>
> - http.keepAliveIdle specifies how long in seconds to wait on an idle
> connection before beginning to send keepalive packets.
>
> - http.keepAliveInterval does the same but controls the interval
> between successive keepalive packets.
>
> - http.keepAliveCount specifies how many keepalive packets to send
> before closing down the connection.
>
> The first two commits of the series are general code clean-up of a
> couple of small things I noticed while reading through the http.c code,
> and the final patch implements these new options.
>
> I couldn't think of a great way to test these new configuration
> settings, and given the simplicity of the final patch I opted for no
> tests there. But if someone has a good idea of how to test this
> behavior, please let me know.
>
> In either case, thanks in advance for your review!
>
> Taylor Blau (4):
> http.c: remove unnecessary casts to long
> http.c: introduce `set_long_from_env()` for convenience
> http.c: inline `set_curl_keepalive()`
> http.c: allow custom TCP keepalive behavior via config
>
> Documentation/config/http.adoc | 18 ++++++++
> git-curl-compat.h | 7 ++++
> http.c | 75 ++++++++++++++++++++++++++--------
> 3 files changed, 84 insertions(+), 16 deletions(-)
>
> Range-diff against v1:
> -: ---------- > 1: 204e5e18d2 http.c: remove unnecessary casts to long
> 1: ba22a121fa ! 2: 2e39a78e87 http.c: introduce `set_long_from_env()` for convenience
> @@ Commit message
> Replace those two instances with a new cousin of 'set_from_env()' called
> 'set_long_from_env()', which does what its name suggests. This allows us
> to remove the temporary variables and clean up some minor code
> - duplication. More importantly, however, it prepares us for a future
> - commit which will introduce more instances of assigning an environment
> - variable to a long.
> + duplication while also adding more robust error handling.
> +
> + More importantly, however, it prepares us for a future commit which will
> + introduce more instances of assigning an environment variable to a long.
>
> Signed-off-by: Taylor Blau <me@ttaylorr.com>
>
> @@ http.c: static void set_from_env(char **var, const char *envname)
> +static void set_long_from_env(long *var, const char *envname)
> +{
> + const char *val = getenv(envname);
> -+ if (val)
> -+ *var = strtol(val, NULL, 10);
> ++ if (val) {
> ++ long tmp;
> ++ char *endp;
> ++ int saved_errno = errno;
> ++
> ++ errno = 0;
> ++ tmp = strtol(val, &endp, 10);
> ++
> ++ if (errno)
> ++ warning_errno(_("failed to parse %s"), envname);
> ++ else if (*endp || endp == val)
> ++ warning(_("failed to parse %s"), envname);
> ++ else
> ++ *var = tmp;
> ++
> ++ errno = saved_errno;
> ++ }
> +}
> +
> void http_init(struct remote *remote, const char *url, int proactive_auth)
> 2: a05269552f = 3: cdfc9baa8d http.c: inline `set_curl_keepalive()`
> 3: d840415808 ! 4: 3fe62181e5 http.c: allow custom TCP keepalive behavior via config
> @@ Commit message
> 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 f7c094060c
> + (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 <me@ttaylorr.com>
>
> ## Documentation/config/http.adoc ##
> @@ Documentation/config/http.adoc: http.lowSpeedLimit, http.lowSpeedTime::
> A boolean which disables using of EPSV ftp command by curl.
> This can be helpful with some "poor" ftp servers which don't
>
> + ## git-curl-compat.h ##
> +@@
> + #define GIT_CURL_HAVE_CURLOPT_PROTOCOLS_STR 1
> + #endif
> +
> ++/**
> ++ * CURLOPT_TCP_KEEPCNT was added in 8.9.0, released in July, 2024.
> ++ */
> ++#if LIBCURL_VERSION_NUM >= 0x080900
> ++#define GIT_CURL_HAVE_CURLOPT_TCP_KEEPCNT
> ++#endif
> ++
> + #endif
> +
> ## http.c ##
> @@ http.c: static struct {
> };
> @@ http.c: static int http_options(const char *var, const char *value,
> }
>
> + if (!strcmp("http.keepaliveidle", var)) {
> -+ curl_tcp_keepidle = (long)git_config_int(var, value, ctx->kvi);
> ++ curl_tcp_keepidle = git_config_int(var, value, ctx->kvi);
> + return 0;
> + }
> + if (!strcmp("http.keepaliveinterval", var)) {
> -+ curl_tcp_keepintvl = (long)git_config_int(var, value, ctx->kvi);
> ++ curl_tcp_keepintvl = git_config_int(var, value, ctx->kvi);
> + return 0;
> + }
> + if (!strcmp("http.keepalivecount", var)) {
> -+ curl_tcp_keepcnt = (long)git_config_int(var, value, ctx->kvi);
> ++ curl_tcp_keepcnt = git_config_int(var, value, ctx->kvi);
> + return 0;
> + }
> +
> @@ http.c: static CURL *get_curl_handle(void)
> + if (curl_tcp_keepintvl > -1)
> + curl_easy_setopt(result, CURLOPT_TCP_KEEPINTVL,
> + curl_tcp_keepintvl);
> ++#ifdef GIT_CURL_HAVE_CURLOPT_TCP_KEEPCNT
> + if (curl_tcp_keepcnt > -1)
> + curl_easy_setopt(result, CURLOPT_TCP_KEEPCNT, curl_tcp_keepcnt);
> ++#endif
> +
> return result;
> }
>
> base-commit: 683c54c999c301c2cd6f715c411407c413b1d84e
> --
> 2.49.0.4.ge59cf92f8d
The new patch and range-diff look good to me.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 2/4] http.c: introduce `set_long_from_env()` for convenience
2025-03-19 22:23 ` [PATCH v2 2/4] http.c: introduce `set_long_from_env()` for convenience Taylor Blau
@ 2025-03-20 5:24 ` Patrick Steinhardt
2025-04-01 9:10 ` Jeff King
1 sibling, 0 replies; 21+ messages in thread
From: Patrick Steinhardt @ 2025-03-20 5:24 UTC (permalink / raw)
To: Taylor Blau; +Cc: git, Jeff King, Junio C Hamano
On Wed, Mar 19, 2025 at 06:23:50PM -0400, Taylor Blau wrote:
> diff --git a/http.c b/http.c
> index 0cbcb079b2..17b676a1d5 100644
> --- a/http.c
> +++ b/http.c
> @@ -1256,10 +1256,30 @@ static void set_from_env(char **var, const char *envname)
> }
> }
>
> +static void set_long_from_env(long *var, const char *envname)
> +{
> + const char *val = getenv(envname);
> + if (val) {
> + long tmp;
> + char *endp;
> + int saved_errno = errno;
> +
> + errno = 0;
> + tmp = strtol(val, &endp, 10);
> +
> + if (errno)
> + warning_errno(_("failed to parse %s"), envname);
> + else if (*endp || endp == val)
> + warning(_("failed to parse %s"), envname);
> + else
> + *var = tmp;
> +
> + errno = saved_errno;
> + }
> +}
The `saved_errno` dance feels a bit unnecessary, but other than that I'm
okay with this approach of only printing a warning instead of dying
right away.
The other patches look good to me, too, thanks!
Patrick
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 2/4] http.c: introduce `set_long_from_env()` for convenience
2025-03-19 22:23 ` [PATCH v2 2/4] http.c: introduce `set_long_from_env()` for convenience Taylor Blau
2025-03-20 5:24 ` Patrick Steinhardt
@ 2025-04-01 9:10 ` Jeff King
1 sibling, 0 replies; 21+ messages in thread
From: Jeff King @ 2025-04-01 9:10 UTC (permalink / raw)
To: Taylor Blau; +Cc: git, Junio C Hamano, Patrick Steinhardt
On Wed, Mar 19, 2025 at 06:23:50PM -0400, Taylor Blau wrote:
> +static void set_long_from_env(long *var, const char *envname)
> +{
> + const char *val = getenv(envname);
> + if (val) {
> + long tmp;
> + char *endp;
> + int saved_errno = errno;
> +
> + errno = 0;
> + tmp = strtol(val, &endp, 10);
> +
> + if (errno)
> + warning_errno(_("failed to parse %s"), envname);
> + else if (*endp || endp == val)
> + warning(_("failed to parse %s"), envname);
> + else
> + *var = tmp;
> +
> + errno = saved_errno;
> + }
> +}
If we are going to add error checking, should it be reusing the existing
code in parse.[ch]? As a bonus, that would support units like "K" (which
could perhaps be useful for LOW_SPEED_LIMIT).
We'd need to extend that code for "long" (it has wrappers for "int" and
"unsigned long", but not "long). But that seems like a good thing
overall. Something like:
diff --git a/http.c b/http.c
index 0c9a872809..a40e45e9cb 100644
--- a/http.c
+++ b/http.c
@@ -1256,10 +1256,15 @@ static void set_from_env(char **var, const char *envname)
}
}
+static void set_long_from_env(long *var, const char *envname)
+{
+ const char *val = getenv(envname);
+ if (val && !git_parse_long(val, var))
+ warning(_("failed to parse %s"), envname);
+}
+
void http_init(struct remote *remote, const char *url, int proactive_auth)
{
- char *low_speed_limit;
- char *low_speed_time;
char *normalized_url;
struct urlmatch_config config = URLMATCH_CONFIG_INIT;
@@ -1338,12 +1343,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
set_from_env(&user_agent, "GIT_HTTP_USER_AGENT");
- low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT");
- if (low_speed_limit)
- curl_low_speed_limit = strtol(low_speed_limit, NULL, 10);
- low_speed_time = getenv("GIT_HTTP_LOW_SPEED_TIME");
- if (low_speed_time)
- curl_low_speed_time = strtol(low_speed_time, NULL, 10);
+ set_long_from_env(&curl_low_speed_limit, "GIT_HTTP_LOW_SPEED_LIMIT");
+ set_long_from_env(&curl_low_speed_time, "GIT_HTTP_LOW_SPEED_TIME");
if (curl_ssl_verify == -1)
curl_ssl_verify = 1;
diff --git a/parse.c b/parse.c
index 7a60a4f816..4d9758132e 100644
--- a/parse.c
+++ b/parse.c
@@ -116,6 +116,15 @@ int git_parse_ulong(const char *value, unsigned long *ret)
return 1;
}
+int git_parse_long(const char *value, long *ret)
+{
+ intmax_t tmp;
+ if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(long)))
+ return 0;
+ *ret = tmp;
+ return 1;
+}
+
int git_parse_ssize_t(const char *value, ssize_t *ret)
{
intmax_t tmp;
diff --git a/parse.h b/parse.h
index 6bb9a54d9a..0e536536a2 100644
--- a/parse.h
+++ b/parse.h
@@ -4,6 +4,7 @@
int git_parse_signed(const char *value, intmax_t *ret, intmax_t max);
int git_parse_ssize_t(const char *, ssize_t *);
int git_parse_ulong(const char *, unsigned long *);
+int git_parse_long(const char *, long *);
int git_parse_int(const char *value, int *ret);
int git_parse_int64(const char *value, int64_t *ret);
int git_parse_double(const char *value, double *ret);
You could even add git_env_long() to match the existing git_env_ulong(),
although:
- that family of functions calls die() on error, rather than warning
- the calling convention is a bit different; it always assigns the
result, but takes a default value. So you'd need to pass in the
existing value, which is a little awkward:
curl_low_speed_limit = git_env_long("GIT_HTTP_LOW_SPEED_LIMIT",
curl_low_speed_limit);
-Peff
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v2 3/4] http.c: inline `set_curl_keepalive()`
2025-03-19 22:23 ` [PATCH v2 3/4] http.c: inline `set_curl_keepalive()` Taylor Blau
@ 2025-04-01 9:12 ` Jeff King
0 siblings, 0 replies; 21+ messages in thread
From: Jeff King @ 2025-04-01 9:12 UTC (permalink / raw)
To: Taylor Blau; +Cc: git, Junio C Hamano, Patrick Steinhardt
On Wed, Mar 19, 2025 at 06:23:53PM -0400, Taylor Blau wrote:
> At the end of `get_curl_handle()` we call `set_curl_keepalive()` to
> enable TCP keepalive probes on our CURL handle. `set_curl_keepalive()`
> dates back to 47ce115370 (http: use curl's tcp keepalive if available,
> 2013-10-14), which conditionally compiled different variants of
> `set_curl_keepalive()` depending on what version of curl we were
> compiled with[^1].
>
> As of f7c094060c (git-curl-compat: remove check for curl 7.25.0,
> 2024-10-23), we no longer conditionally compile `set_curl_keepalive()`
> since we no longer support pre-7.25.0 versions of curl. But the version
> of that function that we kept is really just a thin wrapper around
> setting the TCP_KEEPALIVE option, so there's no reason to keep it in its
> own function.
>
> Inline the definition of `set_curl_keepalive()` to within
> `get_curl_handle()` so that the setup of our CURL handle is
> self-contained.
>
> [1]: The details are spelled out in 47ce115370, but the gist is curl
> 7.25.0 and newer use CURLOPT_TCP_KEEPALIVE, older versions use
> CURLOPT_SOCKOPTFUNCTION with a custom callback, and older versions
> that predate even that option do nothing.
As the author of 47ce115370, I approve. This ideally would have been
cleaned up as part of the series with f7c094060c, but sometimes it's
hard to see these simplifications when you're focused on getting rid of
the complicated bits. Better late than never.
-Peff
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 4/4] http.c: allow custom TCP keepalive behavior via config
2025-03-19 22:23 ` [PATCH v2 4/4] http.c: allow custom TCP keepalive behavior via config Taylor Blau
@ 2025-04-01 9:16 ` Jeff King
0 siblings, 0 replies; 21+ messages in thread
From: Jeff King @ 2025-04-01 9:16 UTC (permalink / raw)
To: Taylor Blau; +Cc: git, Junio C Hamano, Patrick Steinhardt
On Wed, Mar 19, 2025 at 06:23:56PM -0400, Taylor Blau wrote:
> 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.
OK. I have never wanted those myself, but I have no problem with other
people using them. ;)
The implementation mostly looks as I'd expect, but...
> +http.keepAliveIdle::
> + Specifies how long in seconds to wait on an idle connection
> + before sending TCP keepalive probes (if supported by the OS). If
> + unset, curl's default value is used. Can be overridden by the
> + `GIT_HTTP_KEEPALIVE_IDLE` environment variable.
...while this environment variable (and its siblings) makes sense to
me....
> @@ -1382,6 +1409,10 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
> ssl_cert_password_required = 1;
> }
>
> + set_long_from_env(&curl_tcp_keepidle, "GIT_TCP_KEEPIDLE");
> + set_long_from_env(&curl_tcp_keepintvl, "GIT_TCP_KEEPINTVL");
> + set_long_from_env(&curl_tcp_keepcnt, "GIT_TCP_KEEPCNT");
...we seem to use different names in the code.
I think the ones mentioning HTTP make the most sense, to match the
config (and since this only affects curl).
-Peff
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2025-04-01 9:16 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-18 22:21 [PATCH 0/3] http: support fine-tuning curl's keepalive behavior Taylor Blau
2025-03-18 22:21 ` [PATCH 1/3] http.c: introduce `set_long_from_env()` for convenience Taylor Blau
2025-03-19 16:00 ` Elijah Newren
2025-03-19 16:00 ` Patrick Steinhardt
2025-03-19 18:02 ` Taylor Blau
2025-03-18 22:21 ` [PATCH 2/3] http.c: inline `set_curl_keepalive()` Taylor Blau
2025-03-19 16:01 ` Elijah Newren
2025-03-18 22:21 ` [PATCH 3/3] http.c: allow custom TCP keepalive behavior via config Taylor Blau
2025-03-19 16:00 ` Patrick Steinhardt
2025-03-19 16:15 ` Elijah Newren
2025-03-19 18:05 ` Taylor Blau
2025-03-19 22:23 ` [PATCH v2 0/4] http: support fine-tuning curl's keepalive behavior Taylor Blau
2025-03-19 22:23 ` [PATCH v2 1/4] http.c: remove unnecessary casts to long Taylor Blau
2025-03-19 22:23 ` [PATCH v2 2/4] http.c: introduce `set_long_from_env()` for convenience Taylor Blau
2025-03-20 5:24 ` Patrick Steinhardt
2025-04-01 9:10 ` Jeff King
2025-03-19 22:23 ` [PATCH v2 3/4] http.c: inline `set_curl_keepalive()` Taylor Blau
2025-04-01 9:12 ` Jeff King
2025-03-19 22:23 ` [PATCH v2 4/4] http.c: allow custom TCP keepalive behavior via config Taylor Blau
2025-04-01 9:16 ` Jeff King
2025-03-19 22:49 ` [PATCH v2 0/4] http: support fine-tuning curl's keepalive behavior Elijah Newren
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).