Skip to content

fix: prevent HTTP/2 hpack panic with shared HTTP client#85

Merged
jeffersonrodrigues92 merged 1 commit intodevelopfrom
fix/http2-hpack-panic
Mar 26, 2026
Merged

fix: prevent HTTP/2 hpack panic with shared HTTP client#85
jeffersonrodrigues92 merged 1 commit intodevelopfrom
fix/http2-hpack-panic

Conversation

@jeffersonrodrigues92
Copy link
Copy Markdown
Contributor

@jeffersonrodrigues92 jeffersonrodrigues92 commented Mar 26, 2026

Summary

Replace per-request &http.Client{} (3 occurrences in auth middleware) with a package-level shared client using custom transport with ForceAttemptHTTP2: false.

Problem

Each auth request created a new &http.Client{} without custom transport, using Go's http.DefaultTransport which negotiates HTTP/2 over HTTPS. Under concurrent requests, multiple goroutines share the same HTTP/2 connection whose hpack encoder is not goroutine-safe in Go 1.26.1, causing:

panic: id (7) <= evictCount (7)
goroutine XXX [running]:
vendor/golang.org/x/net/http2/hpack.(*headerFieldTable).idToIndex

Fix

Single shared http.Client with:

  • ForceAttemptHTTP2: false — stays on HTTP/1.1 with connection pooling
  • MaxIdleConnsPerHost: 10 — reuses connections efficiently
  • Timeout: 30s — prevents hanging requests

Per Go docs, http.Client is safe for concurrent use and should be reused.

Test plan

  • go build ./...
  • go vet ./...
  • go test ./auth/middleware/... passes
  • Verified panic no longer reproduces with GODEBUG=http2client=0

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
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 26, 2026

Walkthrough

The change introduces a package-level shared HTTP client in the authentication middleware that consolidates HTTP client creation. Previously, NewAuthClient, checkAuthorization, and GetApplicationToken each instantiated their own http.Client. Now they reuse a single configured client with a custom transport that disables HTTP/2, includes tuned idle connection settings, and enforces a 30-second timeout.

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: preventing HTTP/2 hpack panic through the use of a shared HTTP client, which directly aligns with the primary fix in the changeset.
Description check ✅ Passed The PR description is well-structured with clear sections (Summary, Problem, Fix, Test plan) and provides comprehensive context about the issue and solution.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@auth/middleware/middleware.go`:
- Around line 52-63: The custom transport for sharedHTTPClient omits important
DefaultTransport fields; update the Transport in sharedHTTPClient to set Proxy:
http.ProxyFromEnvironment and add TLSHandshakeTimeout (e.g., 10*time.Second) and
ExpectContinueTimeout (e.g., 1*time.Second) alongside the existing
ForceAttemptHTTP2/MaxIdleConns/MaxIdleConnsPerHost/IdleConnTimeout so the client
respects system proxies and uses robust TLS/expect-continue timeouts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ffdb6080-8e29-4286-a23f-68f597a6c3f9

📥 Commits

Reviewing files that changed from the base of the PR and between cfeb75e and 0716b6f.

📒 Files selected for processing (1)
  • auth/middleware/middleware.go

Comment on lines +52 to +63
// 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,
},
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider adding missing transport settings for robustness.

The fix correctly addresses the HTTP/2 panic by using a shared client with ForceAttemptHTTP2: false. However, the custom transport omits several settings from Go's DefaultTransport that could cause issues:

  1. Missing Proxy: http.ProxyFromEnvironment – HTTP/HTTPS proxy environment variables won't be respected, which may break deployments behind corporate proxies.
  2. Missing TLSHandshakeTimeout – TLS handshakes could stall; the client-level timeout is a coarse fallback.
  3. Missing ExpectContinueTimeout – Affects POST requests with Expect: 100-continue.
♻️ Proposed enhancement to match DefaultTransport behavior
 var sharedHTTPClient = &http.Client{
 	Timeout: 30 * time.Second,
 	Transport: &http.Transport{
+		Proxy:               http.ProxyFromEnvironment,
 		ForceAttemptHTTP2:   false,
 		MaxIdleConns:        100,
 		MaxIdleConnsPerHost: 10,
 		IdleConnTimeout:     90 * time.Second,
+		TLSHandshakeTimeout: 10 * time.Second,
+		ExpectContinueTimeout: 1 * time.Second,
 	},
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 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,
},
}
// 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{
Proxy: http.ProxyFromEnvironment,
ForceAttemptHTTP2: false,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@auth/middleware/middleware.go` around lines 52 - 63, The custom transport for
sharedHTTPClient omits important DefaultTransport fields; update the Transport
in sharedHTTPClient to set Proxy: http.ProxyFromEnvironment and add
TLSHandshakeTimeout (e.g., 10*time.Second) and ExpectContinueTimeout (e.g.,
1*time.Second) alongside the existing
ForceAttemptHTTP2/MaxIdleConns/MaxIdleConnsPerHost/IdleConnTimeout so the client
respects system proxies and uses robust TLS/expect-continue timeouts.

Copy link
Copy Markdown

@gandalf-at-lerian gandalf-at-lerian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix correto. Client compartilhado com HTTP/1.1 elimina o race condition no hpack encoder e melhora performance com connection pooling. Merge seguro.

@gandalf-at-lerian gandalf-at-lerian changed the base branch from main to develop March 26, 2026 23:56
@jeffersonrodrigues92 jeffersonrodrigues92 merged commit 292e241 into develop Mar 26, 2026
7 checks passed
@jeffersonrodrigues92 jeffersonrodrigues92 deleted the fix/http2-hpack-panic branch March 26, 2026 23:56
@lerian-studio-midaz-push-bot
Copy link
Copy Markdown

🎉 This PR is included in version 2.6.0-beta.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@lerian-studio-midaz-push-bot
Copy link
Copy Markdown

🎉 This PR is included in version 2.6.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants