[PATCH] http: add a config to limit the connection time

"GalaxySnail via GitGitGadget" <[email protected]>
Newsgroups org.kernel.vger.git
Message-ID <[email protected]>
From: GalaxySnail <[email protected]>

By default, libcurl uses a 300 seconds timeout for the connection phase,
which is too long for some use cases.

Add http.connecttimeoutms and GIT_HTTP_CONNECT_TIMEOUT_MS to specify
timeout in milliseconds for the connection phase. Both of them call
CURLOPT_CONNECTTIMEOUT_MS internally.

Signed-off-by: GalaxySnail <[email protected]>
---
    http: add a config to limit the connection time

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2362%2FGalaxySnail%2Fhttp-connect-timeout-ms-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2362/GalaxySnail/http-connect-timeout-ms-v1
Pull-Request: https://github.com/git/git/pull/2362

 Documentation/config/http.adoc  |  7 ++++
 http.c                          | 11 ++++++
 t/meson.build                   |  1 +
 t/t5585-http-connect-timeout.sh | 60 +++++++++++++++++++++++++++++++++
 4 files changed, 79 insertions(+)
 create mode 100755 t/t5585-http-connect-timeout.sh

diff --git a/Documentation/config/http.adoc b/Documentation/config/http.adoc
index 792a71b413..a4f7afa61e 100644
--- a/Documentation/config/http.adoc
+++ b/Documentation/config/http.adoc
@@ -300,6 +300,13 @@ for most push problems, but can increase memory consumption
 significantly since the entire buffer is allocated even for small
 pushes.
 
+http.connectTimeoutMS::
+	Maximum time in milliseconds that you allow the connection phase
+	to take. The connection phase includes DNS lookup and subsequent
+	TCP, TLS or QUIC handshakes.
+	Can be overridden by the `GIT_HTTP_CONNECT_TIMEOUT_MS`
+	environment variable.
+
 http.lowSpeedLimit::
 http.lowSpeedTime::
 	If the HTTP transfer speed, in bytes per second, is less than
diff --git a/http.c b/http.c
index caccf2108e..befe9ea8a0 100644
--- a/http.c
+++ b/http.c
@@ -68,6 +68,7 @@ static char *ssl_capath;
 static char *curl_no_proxy;
 static char *ssl_pinnedkey;
 static char *ssl_cainfo;
+static long curl_connect_timeout_ms = -1;
 static long curl_low_speed_limit = -1;
 static long curl_low_speed_time = -1;
 static int curl_ftp_no_epsv;
@@ -450,6 +451,10 @@ static int http_options(const char *var, const char *value,
 		max_requests = git_config_int(var, value, ctx->kvi);
 		return 0;
 	}
+	if (!strcmp("http.connecttimeoutms", var)) {
+		curl_connect_timeout_ms = git_config_int(var, value, ctx->kvi);
+		return 0;
+	}
 	if (!strcmp("http.lowspeedlimit", var)) {
 		curl_low_speed_limit = git_config_int(var, value, ctx->kvi);
 		return 0;
@@ -1215,6 +1220,10 @@ static CURL *get_curl_handle(void)
 			curl_easy_setopt(result, CURLOPT_PROXY_CAINFO, http_proxy_ssl_ca_info);
 	}
 
+	if (curl_connect_timeout_ms > 0)
+		curl_easy_setopt(result, CURLOPT_CONNECTTIMEOUT_MS,
+				 curl_connect_timeout_ms);
+
 	if (curl_low_speed_limit > 0 && curl_low_speed_time > 0) {
 		curl_easy_setopt(result, CURLOPT_LOW_SPEED_LIMIT,
 				 curl_low_speed_limit);
@@ -1474,6 +1483,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
 
 	set_from_env(&user_agent, "GIT_HTTP_USER_AGENT");
 
+	set_long_from_env(&curl_connect_timeout_ms, "GIT_HTTP_CONNECT_TIMEOUT_MS");
+
 	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");
 
diff --git a/t/meson.build b/t/meson.build
index 8ae6ab6c5f..6196736cb2 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -724,6 +724,7 @@ integration_tests = [
   't5582-fetch-negative-refspec.sh',
   't5583-push-branches.sh',
   't5584-http-429-retry.sh',
+  't5585-http-connect-timeout.sh',
   't5600-clone-fail-cleanup.sh',
   't5601-clone.sh',
   't5602-clone-remote-exec.sh',
diff --git a/t/t5585-http-connect-timeout.sh b/t/t5585-http-connect-timeout.sh
new file mode 100755
index 0000000000..7363e23bfe
--- /dev/null
+++ b/t/t5585-http-connect-timeout.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+test_description='test http.connecttimeoutms and GIT_HTTP_CONNECT_TIMEOUT_MS'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
+
+test_expect_success 'setup repository' '
+	test_commit initial &&
+	git clone --bare . "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+	git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" config http.receivepack true
+'
+
+test_expect_success 'http.connecttimeoutms accepts a positive integer via config' '
+	test_config http.connecttimeoutms 5000 &&
+	git ls-remote "$HTTPD_URL/smart/repo.git" >output &&
+	test_grep "refs/heads/" output
+'
+
+test_expect_success 'http.connecttimeoutms=0 is accepted (disables the option)' '
+	test_config http.connecttimeoutms 0 &&
+	git ls-remote "$HTTPD_URL/smart/repo.git" >output &&
+	test_grep "refs/heads/" output
+'
+
+test_expect_success 'GIT_HTTP_CONNECT_TIMEOUT_MS env var is accepted' '
+	GIT_HTTP_CONNECT_TIMEOUT_MS=5000 \
+		git ls-remote "$HTTPD_URL/smart/repo.git" >output 2>err &&
+	test_grep "refs/heads/" output &&
+	test_grep ! . err
+'
+
+test_expect_success 'http.connecttimeoutms rejects non-numeric config value' '
+	test_config http.connecttimeoutms not-a-number &&
+	test_must_fail git ls-remote "$HTTPD_URL/smart/repo.git" 2>err &&
+	test_grep "bad numeric config value .not-a-number. for .http\.connecttimeoutms." err
+'
+
+test_expect_success 'http.connecttimeoutms rejects empty config value' '
+	test_config http.connecttimeoutms "" &&
+	test_must_fail git ls-remote "$HTTPD_URL/smart/repo.git" 2>err &&
+	test_grep "bad numeric config value" err
+'
+
+test_expect_success 'GIT_HTTP_CONNECT_TIMEOUT_MS warns on non-numeric value but succeeds' '
+	GIT_HTTP_CONNECT_TIMEOUT_MS=not-a-number \
+		git ls-remote "$HTTPD_URL/smart/repo.git" >output 2>err &&
+	test_grep "refs/heads/" output &&
+	test_grep "failed to parse GIT_HTTP_CONNECT_TIMEOUT_MS" err
+'
+
+test_expect_success 'GIT_HTTP_CONNECT_TIMEOUT_MS warns on empty value but succeeds' '
+	GIT_HTTP_CONNECT_TIMEOUT_MS= \
+		git ls-remote "$HTTPD_URL/smart/repo.git" >output 2>err &&
+	test_grep "refs/heads/" output &&
+	test_grep "failed to parse GIT_HTTP_CONNECT_TIMEOUT_MS" err
+'
+
+test_done

base-commit: 9a0c4701dcd5725c4184599322b52933ff5005ca
-- 
gitgitgadget
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.