From 0716b6ffa204f1a38613b1041c6932ae637ce8e8 Mon Sep 17 00:00:00 2001 From: Jefferson Rodrigues Date: Thu, 26 Mar 2026 20:26:52 -0300 Subject: [PATCH] fix: prevent HTTP/2 hpack panic with shared HTTP client Replace per-request http.Client{} (3 occurrences) with a package-level shared client using custom transport with ForceAttemptHTTP2: false. The bare http.Client{} used Go's default transport which enables HTTP/2 over HTTPS, causing hpack encoder panic under concurrent goroutine access. X-Lerian-Ref: 0x1 --- auth/middleware/middleware.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/auth/middleware/middleware.go b/auth/middleware/middleware.go index 758f06c..2fd47be 100644 --- a/auth/middleware/middleware.go +++ b/auth/middleware/middleware.go @@ -49,6 +49,19 @@ const ( pluginName string = "plugin-auth" ) +// sharedHTTPClient is a package-level HTTP client with a custom transport +// that prevents HTTP/2 hpack panics under concurrent access. HTTP clients +// are safe for concurrent use and should be reused across requests. +var sharedHTTPClient = &http.Client{ + Timeout: 30 * time.Second, + Transport: &http.Transport{ + ForceAttemptHTTP2: false, + MaxIdleConns: 100, + MaxIdleConnsPerHost: 10, + IdleConnTimeout: 90 * time.Second, + }, +} + // unmarshalErrorResponse unmarshals a JSON response body into commons.Response, // tolerating a numeric "code" field (the auth service may return code as a number). func unmarshalErrorResponse(body []byte) (commons.Response, error) { @@ -157,7 +170,7 @@ func NewAuthClient(address string, enabled bool, logger *log.Logger) *AuthClient } } - client := &http.Client{} + client := sharedHTTPClient healthURL := fmt.Sprintf("%s/health", address) failedToConnectMsg := fmt.Sprintf("Failed to connect to %s: %%v\n", pluginName) @@ -257,7 +270,7 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a attribute.String("app.request.request_id", reqID), ) - client := &http.Client{} + client := sharedHTTPClient token, _, err := new(jwt.Parser).ParseUnverified(accessToken, jwt.MapClaims{}) if err != nil { @@ -400,7 +413,7 @@ func (auth *AuthClient) GetApplicationToken(ctx context.Context, clientID, clien return "", nil } - client := &http.Client{} + client := sharedHTTPClient requestBody := map[string]string{ "grantType": "client_credentials",