Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions common/httpx/httpx.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,15 @@ func New(options *Options) (*HTTPX, error) {
CheckRedirect: redirectFunc,
}, retryablehttpOptions)

// When HTTP/1.1-only mode is enforced, prevent retryablehttp-go's HTTP/2 fallback
// from bypassing the protocol restriction. retryablehttp-go falls back to HTTPClient2
// (an HTTP/2-capable client) when it encounters a "malformed HTTP version" error from
// a server that speaks HTTP/2. Replacing HTTPClient2 with the HTTP/1.1-only HTTPClient
// ensures the -pr http11 flag is honoured end-to-end. See: #2240
if httpx.Options.Protocol == "http11" {
httpx.client.HTTPClient2 = httpx.client.HTTPClient
}

transport2 := &http2.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
Expand Down
29 changes: 29 additions & 0 deletions common/httpx/httpx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,41 @@ package httpx

import (
"net/http"
"os"
"testing"

"github.com/projectdiscovery/retryablehttp-go"
"github.com/stretchr/testify/require"
)

// TestHTTP11ProtocolEnforcement verifies that -pr http11 prevents the retryablehttp-go
// HTTP/2 fallback from bypassing the HTTP/1.1-only restriction (#2240).
func TestHTTP11ProtocolEnforcement(t *testing.T) {
t.Run("http11 mode disables HTTPClient2 fallback", func(t *testing.T) {
t.Setenv("GODEBUG", os.Getenv("GODEBUG"))
opts := DefaultOptions
opts.Protocol = "http11"
ht, err := New(&opts)
require.Nil(t, err)

// When Protocol == "http11", HTTPClient2 must point to the same underlying
// client as HTTPClient so the retryablehttp-go fallback is neutralised.
require.Same(t, ht.client.HTTPClient, ht.client.HTTPClient2,
"HTTPClient2 must equal HTTPClient in http11 mode to prevent HTTP/2 fallback")
})

t.Run("default mode keeps distinct HTTPClient2", func(t *testing.T) {
t.Setenv("GODEBUG", os.Getenv("GODEBUG"))
ht, err := New(&DefaultOptions)
require.Nil(t, err)

// Without an explicit http11 restriction the two clients must differ
// (HTTPClient2 is the native HTTP/2 client used for protocol detection).
require.NotSame(t, ht.client.HTTPClient, ht.client.HTTPClient2,
"HTTPClient2 must be distinct from HTTPClient in default mode")
})
}

func TestDo(t *testing.T) {
ht, err := New(&DefaultOptions)
require.Nil(t, err)
Expand Down