From 2cc4d27d6292f4dddeb277b24ec3d176ce1eb716 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 8 May 2026 13:21:16 +0300 Subject: [PATCH] net.http: timeout fixes (mbedtls/openssl) --- thirdparty/mbedtls/include/mbedtls/mbedtls_config.h | 10 ++++++++++ vlib/net/http/backend.c.v | 6 ++++++ vlib/net/http/http.v | 4 ++-- vlib/net/openssl/ssl_connection.c.v | 11 +++++++++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/thirdparty/mbedtls/include/mbedtls/mbedtls_config.h b/thirdparty/mbedtls/include/mbedtls/mbedtls_config.h index ff25511de..dc98200a2 100644 --- a/thirdparty/mbedtls/include/mbedtls/mbedtls_config.h +++ b/thirdparty/mbedtls/include/mbedtls/mbedtls_config.h @@ -4441,6 +4441,16 @@ #undef MBEDTLS_HAVE_ASM #undef MBEDTLS_AESNI_C #undef MBEDTLS_PADLOCK_C +/* + * Force 32-bit bignum limbs under tcc. + * On 64-bit hosts, bignum.h would otherwise typedef the double-width type as + * `unsigned int __attribute__((mode(TI)))` (or `__uint128_t`). tcc accepts the + * declaration but miscompiles the resulting 64x64->128 multiplications, which + * makes the modular reduction loop in ecp_modp() spin forever during the + * TLS 1.3 X25519 client_hello key share generation. Falling back to 32-bit + * limbs keeps the double-width type at uint64_t, which tcc handles correctly. + */ +#define MBEDTLS_HAVE_INT32 #else // __TINYC__ #define MBEDTLS_HAVE_ASM #define MBEDTLS_AESNI_C diff --git a/vlib/net/http/backend.c.v b/vlib/net/http/backend.c.v index ffc9ab848..39453dfb5 100644 --- a/vlib/net/http/backend.c.v +++ b/vlib/net/http/backend.c.v @@ -36,6 +36,12 @@ fn net_ssl_do(req &Request, port int, method Method, host_name string, path stri } continue } + // Propagate the request's read timeout into the SSL backend. + // Without this, mbedtls keeps its init-time default and openssl falls back to no + // timeout at all on a stalled socket — see issue surfaced by macOS arm64 + tcc CI hangs. + if req.read_timeout > 0 { + ssl_conn.set_read_timeout(req.read_timeout) + } return req.do_request(req_headers, mut ssl_conn)! } return error('http.net_ssl_do: exhausted retries') diff --git a/vlib/net/http/http.v b/vlib/net/http/http.v index c0cf0e016..fffe0afa8 100644 --- a/vlib/net/http/http.v +++ b/vlib/net/http/http.v @@ -26,8 +26,8 @@ pub mut: user_ptr voidptr = unsafe { nil } verbose bool proxy &HttpProxy = unsafe { nil } - read_timeout i64 = 30 * time.second // timeout for reading the response; currently not used for direct https requests - write_timeout i64 = 30 * time.second // timeout for writing the request; currently not used for direct https requests + read_timeout i64 = 30 * time.second // timeout for reading the response; applies to plain http and to direct https requests + write_timeout i64 = 30 * time.second // timeout for writing the request; applies to plain http (write timeouts are not enforced on the SSL write path yet) validate bool // set this to true, if you want to stop requests, when their certificates are found to be invalid verify string // the path to a rootca.pem file, containing trusted CA certificate(s) diff --git a/vlib/net/openssl/ssl_connection.c.v b/vlib/net/openssl/ssl_connection.c.v index cbcb84853..3ad7ce911 100644 --- a/vlib/net/openssl/ssl_connection.c.v +++ b/vlib/net/openssl/ssl_connection.c.v @@ -281,6 +281,17 @@ fn (mut s SSLConn) complete_connect() ! { } } +// read_timeout returns the current SSL read timeout. +pub fn (s &SSLConn) read_timeout() time.Duration { + return s.duration +} + +// set_read_timeout sets the read timeout used for subsequent SSL reads. +// A value of 0, or net.infinite_timeout means "wait forever". +pub fn (mut s SSLConn) set_read_timeout(timeout time.Duration) { + s.duration = timeout +} + // addr retrieves the local ip address and port number for this connection pub fn (s &SSLConn) addr() !net.Addr { return net.addr_from_socket_handle(s.handle) -- 2.39.5