1
0
mirror of https://github.com/golang/go synced 2024-11-19 21:14:43 -07:00

net/http/httputil: allow ReverseProxy to call ModifyResponse on failed requests

Previously when RoundTrip returned a non-nil error, the proxy returned a
StatusBadGateway error, instead of first calling ModifyResponse. This
commit first calls ModifyResponse, whether or not the error returned
from RoundTrip is nil.

Also closes response body when ModifyResponse returns an error. See #22658.

Fixes #21255

Change-Id: I5b5bf23a69ae5608f87d4ece756a1b4985ccaa9c
Reviewed-on: https://go-review.googlesource.com/54030
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Akhil Indurti 2017-11-14 11:40:09 -05:00 committed by Brad Fitzpatrick
parent 0d9dc044d2
commit 5ea2360b66
2 changed files with 42 additions and 8 deletions

View File

@ -191,10 +191,11 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
}
res, err := transport.RoundTrip(outreq)
if err != nil {
p.logf("http: proxy error: %v", err)
rw.WriteHeader(http.StatusBadGateway)
return
if res == nil {
res = &http.Response{
StatusCode: http.StatusBadGateway,
Body: http.NoBody,
}
}
removeConnectionHeaders(res.Header)
@ -204,12 +205,16 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
}
if p.ModifyResponse != nil {
if err := p.ModifyResponse(res); err != nil {
if err != nil {
p.logf("http: proxy error: %v", err)
rw.WriteHeader(http.StatusBadGateway)
res.Body.Close()
return
}
err = p.ModifyResponse(res)
}
if err != nil {
p.logf("http: proxy error: %v", err)
rw.WriteHeader(http.StatusBadGateway)
res.Body.Close()
return
}
copyHeader(rw.Header(), res.Header)

View File

@ -631,6 +631,35 @@ func TestReverseProxyModifyResponse(t *testing.T) {
}
}
// Issue 21255. Test ModifyResponse when an error from transport.RoundTrip
// occurs, and that the proxy returns StatusOK.
func TestReverseProxyModifyResponse_OnError(t *testing.T) {
// Always returns an error
errBackend := httptest.NewUnstartedServer(nil)
errBackend.Config.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests
defer errBackend.Close()
rpURL, _ := url.Parse(errBackend.URL)
rproxy := NewSingleHostReverseProxy(rpURL)
rproxy.ModifyResponse = func(resp *http.Response) error {
// Will be set for a non-nil error
resp.StatusCode = http.StatusOK
return nil
}
frontend := httptest.NewServer(rproxy)
defer frontend.Close()
resp, err := http.Get(frontend.URL)
if err != nil {
t.Fatalf("failed to reach proxy: %v", err)
}
if resp.StatusCode != http.StatusOK {
t.Errorf("err != nil: got res.StatusCode %d; expected %d", resp.StatusCode, http.StatusOK)
}
resp.Body.Close()
}
// Issue 16659: log errors from short read
func TestReverseProxy_CopyBuffer(t *testing.T) {
backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {