From 13e53bcf034e23f1d60877db24a655f4276ed594 Mon Sep 17 00:00:00 2001 From: logandavies181 Date: Fri, 5 Feb 2021 11:07:32 +0000 Subject: [PATCH 1/2] Add ProxyConnectError type to be returned on non 200 responses to HTTP CONNECT requests --- src/net/http/transport.go | 19 ++++++++++++++---- src/net/http/transport_test.go | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 0aa48273dd3858..d61e5d0b220c3c 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -1553,6 +1553,19 @@ type erringRoundTripper interface { RoundTripErr() error } +type ProxyConnectError struct { + Response *Response +} + +func (p *ProxyConnectError) Error() string { + // Don't return full Response.Status for backwards compatibility + f := strings.SplitN(p.Response.Status, " ", 2) + if len(f) < 2 { + return "unknown status code" + } + return f[1] +} + func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *persistConn, err error) { pconn = &persistConn{ t: t, @@ -1711,12 +1724,10 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers return nil, err } if resp.StatusCode != 200 { - f := strings.SplitN(resp.Status, " ", 2) conn.Close() - if len(f) < 2 { - return nil, errors.New("unknown status code") + return nil, &ProxyConnectError{ + Response: resp, } - return nil, errors.New(f[1]) } } diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index ba85a61683add3..1b60cb8b5615cc 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -3774,6 +3774,41 @@ func TestRoundTripReturnsProxyError(t *testing.T) { } } +// Test for issue 38143 +// Return an error containing the proxy CONNECT request if status is not 200 +func TestRoundTripReturnsProxyConnectError(t *testing.T) { + s := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + w.WriteHeader(StatusServiceUnavailable) + })) + defer s.Close() + + proxyURL, err := url.Parse(s.URL) + if err != nil { + t.Fatal(err) + } + tr := &Transport{ + Proxy: ProxyURL(proxyURL), + } + + req, err := NewRequest("GET", "https://example.com", nil) + if err != nil { + t.Fatal(err) + } + + _, got := tr.RoundTrip(req) + + switch errType := got.(type) { + case *ProxyConnectError: + default: + t.Errorf("Wrong error type returned, Got: %T, Want: *ProxyConnectError", errType) + } + + // Test backwards compatibility + if got.Error() != "Service Unavailable" { + t.Error("Non-backwards compatible error message from *ProxyConnectError") + } +} + // tests that putting an idle conn after a call to CloseIdleConns does return it func TestTransportCloseIdleConnsThenReturn(t *testing.T) { tr := &Transport{} From 895745b543a69ad360355b899b3ead923dc8da77 Mon Sep 17 00:00:00 2001 From: logandavies181 Date: Fri, 5 Feb 2021 11:16:56 +0000 Subject: [PATCH 2/2] Add struct comment --- src/net/http/transport.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/net/http/transport.go b/src/net/http/transport.go index d61e5d0b220c3c..5c9fb30f0e5198 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -1553,6 +1553,7 @@ type erringRoundTripper interface { RoundTripErr() error } +// ProxyConnectError holds the response to an unsuccessful proxy CONNECT request. type ProxyConnectError struct { Response *Response }