From 6ab6926c94d00764b3ad5e5e757ebaa19de07dfe Mon Sep 17 00:00:00 2001 From: Nabil Ragab <70708931+nabilragab@users.noreply.github.com> Date: Sun, 18 Oct 2026 07:37:23 +0300 Subject: [PATCH] s3: read chunks from HTTPS volume servers with the global HTTP client (#11800) readChunkRange sent the volume lookup's http:// URL through a bare http.Client, so with [https.client]/[https.volume] configured every read of an SSE-KMS object larger than one chunk (and every ranged read through this path) failed with "client sent an HTTP request to an HTTPS server" and the GET returned 500. Normalise the URL's scheme and use util_http's global client, which carries the [https.client] TLS configuration, as the other volume reads already do. Drop the now-unused volumeServerHTTPClient. Fixes #11799 Co-authored-by: Claude Opus 5.5 --- weed/s3api/s3api_object_handlers.go | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/weed/s3api/s3api_object_handlers.go b/weed/s3api/s3api_object_handlers.go index f5e6b546c..2078d4e69 100644 --- a/weed/s3api/s3api_object_handlers.go +++ b/weed/s3api/s3api_object_handlers.go @@ -1486,16 +1486,6 @@ func (s3a *S3ApiServer) streamRangeToClient(w io.Writer, r *http.Request, reader return cw.written, nil } -// Shared HTTP client for volume server requests (connection pooling) -var volumeServerHTTPClient = &http.Client{ - Timeout: 5 * time.Minute, - Transport: &http.Transport{ - MaxIdleConns: 100, - MaxIdleConnsPerHost: 10, - IdleConnTimeout: 90 * time.Second, - }, -} - // createLookupFileIdFunction creates a reusable lookup function for resolving volume URLs // Uses FilerClient's vidMap cache to eliminate per-chunk gRPC overhead func (s3a *S3ApiServer) createLookupFileIdFunction() func(context.Context, string) ([]string, error) { @@ -2198,8 +2188,12 @@ func (s3a *S3ApiServer) readChunkRange(ctx context.Context, fileId string, offse return nil, fmt.Errorf("failed to lookup chunk %s: %w", fileId, err) } - // Use the first URL (already contains complete URL with fileId) - chunkUrl := urlStrings[0] + // Use the first URL (already contains complete URL with fileId). The lookup returns http:// URLs; when + // [https.client] is configured the volume servers only speak TLS, so take the global client's scheme. + chunkUrl, err := util_http.NormalizeUrl(urlStrings[0]) + if err != nil { + return nil, fmt.Errorf("failed to normalize chunk URL %s: %w", fileId, err) + } // Generate JWT for volume server authentication (uses config loaded once at startup) jwt := filer.JwtForVolumeServer(fileId) @@ -2220,8 +2214,9 @@ func (s3a *S3ApiServer) readChunkRange(ctx context.Context, fileId string, offse req.Header.Set("Authorization", security.BearerPrefix+jwt) } - // Use shared HTTP client with connection pooling - resp, err := volumeServerHTTPClient.Do(req) + // Use the global HTTP client: it carries the [https.client] TLS configuration (CA and client + // certificate) that HTTPS volume servers require; a bare http.Client cannot reach them. + resp, err := util_http.GetGlobalHttpClient().Do(req) if err != nil { return nil, fmt.Errorf("failed to fetch chunk: %w", err) }