mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
net/http/httputil: ReverseProxy request cancellation
If an inbound connection is closed, cancel the outbound http request. This is particularly useful if the outbound request may consume resources unnecessarily until it is cancelled. Fixes #8406 Change-Id: I738c4489186ce342f7e21d0ea3f529722c5b443a Signed-off-by: Peter Waller <p@pwaller.net> Reviewed-on: https://go-review.googlesource.com/2320 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
3aba41d6c3
commit
ececbe89d4
2 changed files with 102 additions and 0 deletions
|
|
@ -8,6 +8,7 @@ package httputil
|
|||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
|
|
@ -211,3 +212,58 @@ func TestReverseProxyFlushInterval(t *testing.T) {
|
|||
t.Error("maxLatencyWriter flushLoop() never exited")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReverseProxyCancellation(t *testing.T) {
|
||||
const backendResponse = "I am the backend"
|
||||
|
||||
reqInFlight := make(chan struct{})
|
||||
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
close(reqInFlight)
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
// Note: this should only happen in broken implementations, and the
|
||||
// closenotify case should be instantaneous.
|
||||
t.Log("Failed to close backend connection")
|
||||
t.Fail()
|
||||
case <-w.(http.CloseNotifier).CloseNotify():
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(backendResponse))
|
||||
}))
|
||||
|
||||
defer backend.Close()
|
||||
|
||||
backend.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
|
||||
|
||||
backendURL, err := url.Parse(backend.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
proxyHandler := NewSingleHostReverseProxy(backendURL)
|
||||
|
||||
// Discards errors of the form:
|
||||
// http: proxy error: read tcp 127.0.0.1:44643: use of closed network connection
|
||||
proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0)
|
||||
|
||||
frontend := httptest.NewServer(proxyHandler)
|
||||
defer frontend.Close()
|
||||
|
||||
getReq, _ := http.NewRequest("GET", frontend.URL, nil)
|
||||
go func() {
|
||||
<-reqInFlight
|
||||
http.DefaultTransport.(*http.Transport).CancelRequest(getReq)
|
||||
}()
|
||||
res, err := http.DefaultClient.Do(getReq)
|
||||
if res != nil {
|
||||
t.Fatal("Non-nil response")
|
||||
}
|
||||
if err == nil {
|
||||
// This should be an error like:
|
||||
// Get http://127.0.0.1:58079: read tcp 127.0.0.1:58079:
|
||||
// use of closed network connection
|
||||
t.Fatal("DefaultClient.Do() returned nil error")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue