Skip to content

fix: respect -pr http11 flag by disabling HTTP/2 fallback#2450

Open
VoidChecksum wants to merge 1 commit intoprojectdiscovery:devfrom
VoidChecksum:fix/respect-http11-protocol-flag
Open

fix: respect -pr http11 flag by disabling HTTP/2 fallback#2450
VoidChecksum wants to merge 1 commit intoprojectdiscovery:devfrom
VoidChecksum:fix/respect-http11-protocol-flag

Conversation

@VoidChecksum
Copy link

@VoidChecksum VoidChecksum commented Mar 15, 2026

Summary

When users specify -pr http11 to force HTTP/1.1-only connections, httpx correctly disables HTTP/2 on the primary transport via transport.TLSNextProto = map[string]...{}. However, retryablehttp-go's fallback mechanism silently retries failed requests with an HTTP/2-capable client (HTTPClient2), effectively bypassing the explicit protocol restriction.

This means -pr http11 is not actually enforced — any target that returns malformed HTTP/1.x responses triggers an automatic HTTP/2 retry through a completely separate client that ignores the user's protocol preference.

Root Cause

In retryablehttp-go/do.go, the Do() method contains:

if err != nil && stringsutil.ContainsAny(err.Error(),
    "net/http: HTTP/1.x transport connection broken: malformed HTTP version \"HTTP/2\"",
    "net/http: HTTP/1.x transport connection broken: malformed HTTP response") {
    resp, err = c.HTTPClient2.Do(req.Request)  // ← bypasses -pr http11
}

HTTPClient2 is initialized internally with http2.ConfigureTransport(), making it HTTP/2-capable regardless of the user's -pr flag.

Fix

After creating the retryablehttp client with the HTTP/1.1-only *http.Client, override the fallback HTTPClient2 with the same client when Protocol == "http11":

if httpx.Options.Protocol == "http11" {
    httpx.client.HTTPClient2 = httpClient
}

This ensures the -pr http11 flag is respected end-to-end, including during the HTTP/2 fallback path in retries.

Test plan

  • -pr http11 against an HTTP/2-only server: requests fail cleanly instead of silently upgrading
  • Default mode (no -pr flag): HTTP/2 fallback works as before (no behavioral change)
  • -pr http2 mode: unaffected
  • Retry behavior: retries use the protocol-restricted client consistently

Related

Fixes #2240

Summary by CodeRabbit

  • Refactor
    • Restructured HTTP client initialization for improved code organization and maintainability
    • Enhanced HTTP/1.1 protocol handling during network retry operations to ensure consistent protocol behavior is preserved throughout the entire retry process
    • No changes to the public API—existing integrations will work as before

When users specify -pr http11 to force HTTP/1.1-only connections,
httpx correctly disables HTTP/2 on the primary transport. However,
retryablehttp-go's fallback mechanism automatically retries failed
HTTP/1.x requests with an HTTP/2 client (HTTPClient2), effectively
bypassing the explicit protocol restriction.

Disable the HTTP/2 fallback when HTTP/1.1-only mode is requested
so the protocol flag is respected throughout the entire request
lifecycle, including retries.

Fixes projectdiscovery#2240
Copilot AI review requested due to automatic review settings March 15, 2026 18:33
@auto-assign auto-assign bot requested a review from dwisiswant0 March 15, 2026 18:33
@neo-by-projectdiscovery-dev
Copy link

neo-by-projectdiscovery-dev bot commented Mar 15, 2026

Neo - PR Security Review

No security issues found

Highlights

  • Fixes -pr http11 flag to prevent unintended HTTP/2 fallback via retryablehttp-go's HTTPClient2
  • Overrides HTTPClient2 with the same HTTP/1.1-only client when Protocol == 'http11'
  • Addresses functional issue where protocol preference was bypassed during retry logic
Hardening Notes
  • Sandbox connectivity issues prevented full code analysis; review based on PR description
  • The change enforces user-specified protocol restrictions, reducing unexpected behavior
  • This is primarily a functional fix rather than a security patch

Comment @pdneo help for available commands. · Open in Neo

@coderabbitai
Copy link

coderabbitai bot commented Mar 15, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 43b772f7-93ca-4659-ae41-4bda62591e4e

📥 Commits

Reviewing files that changed from the base of the PR and between 73afc60 and 41312c8.

📒 Files selected for processing (1)
  • common/httpx/httpx.go

Walkthrough

Refactors HTTP client setup in httpx to ensure HTTP/1.1 protocol configuration is consistently applied to retryablehttp's retry mechanism. When HTTP/1.1 mode is enabled, the HTTPClient2 fallback client in retryablehttp is replaced with the primary client, preventing unintended HTTP/2 protocol fallback during retries.

Changes

Cohort / File(s) Summary
HTTP/1.1 Protocol Handling
common/httpx/httpx.go
Extracts HTTP client creation into a separate variable and configures retryablehttp's HTTPClient2 with the same client when HTTP/1.1 mode is active, preventing HTTP/2 fallback during retry operations.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A hop, a skip, through protocols we go,
HTTP/1.1, no fallbacks below!
No more surprise HTTP/2 creeping in,
The retry path's steady—same transport wins. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the main fix: respecting the -pr http11 flag by disabling HTTP/2 fallback, which matches the code changes that override HTTPClient2 to enforce HTTP/1.1 protocol enforcement.
Linked Issues check ✅ Passed The changes directly address issue #2240 by overriding HTTPClient2 with the HTTP/1.1-restricted client when Protocol is set to http11, preventing silent HTTP/2 fallback and ensuring protocol restrictions apply end-to-end through retries.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing HTTP/1.1 protocol enforcement during retries; no unrelated modifications to other functionality or areas of the codebase are present.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Tip

CodeRabbit can generate a title for your PR based on the changes with custom instructions.

Set the reviews.auto_title_instructions setting to generate a title for your PR based on the changes in the PR with custom instructions.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR ensures the -pr http11 (HTTP/1.1-only) setting is respected end-to-end by preventing retryablehttp-go from silently retrying failed requests using its internal HTTP/2-capable fallback client.

Changes:

  • Refactors HTTP client construction into a named httpClient variable for reuse.
  • When Protocol is HTTP/1.1-only, overrides retryablehttp’s HTTPClient2 fallback to use the same HTTP/1.1 client/transport.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

// responses. Override that fallback client with the same HTTP/1.1 transport
// so the -pr http11 flag is respected throughout the entire request
// lifecycle, including retries.
if httpx.Options.Protocol == "http11" {
Comment on lines +180 to +195
httpClient := &http.Client{
Transport: transport,
Timeout: httpx.Options.Timeout,
CheckRedirect: redirectFunc,
}, retryablehttpOptions)
}
httpx.client = retryablehttp.NewWithHTTPClient(httpClient, retryablehttpOptions)

// When HTTP/1.1-only mode is requested, the retryablehttp-go library still
// has an internal fallback (HTTPClient2) that retries with a native HTTP/2
// client when it encounters certain error messages about malformed HTTP/2
// responses. Override that fallback client with the same HTTP/1.1 transport
// so the -pr http11 flag is respected throughout the entire request
// lifecycle, including retries.
if httpx.Options.Protocol == "http11" {
httpx.client.HTTPClient2 = httpClient
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

-pr http11 flag is ignored on retryablehttp-go due to HTTP/2 fallback

2 participants