summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorTw <[email protected]>2017-01-24 09:03:42 +0800
committerMatt Holt <[email protected]>2017-01-23 18:03:42 -0700
commit38c76647c96e9eee0e3908e80c7a143dc271aa5a (patch)
treede99d757d14df4e20dc95aa2eb139e4880bade89
parent696b46f075361fafd596765357718117097e6ae4 (diff)
downloadcaddy-38c76647c96e9eee0e3908e80c7a143dc271aa5a.tar.gz
caddy-38c76647c96e9eee0e3908e80c7a143dc271aa5a.zip
proxy: use a new context for the outgoing request (#1358)
* proxy: use a new context for the outgoing request fix issue #1345 Signed-off-by: Tw <[email protected]> * proxy: add test for canceling the request Signed-off-by: Tw <[email protected]>
-rw-r--r--caddyhttp/proxy/proxy_test.go43
-rw-r--r--caddyhttp/proxy/reverseproxy.go9
2 files changed, 52 insertions, 0 deletions
diff --git a/caddyhttp/proxy/proxy_test.go b/caddyhttp/proxy/proxy_test.go
index 979576957..90753ab3a 100644
--- a/caddyhttp/proxy/proxy_test.go
+++ b/caddyhttp/proxy/proxy_test.go
@@ -3,6 +3,7 @@ package proxy
import (
"bufio"
"bytes"
+ "context"
"crypto/tls"
"fmt"
"io"
@@ -11,6 +12,7 @@ import (
"net"
"net/http"
"net/http/httptest"
+ "net/http/httptrace"
"net/url"
"os"
"path/filepath"
@@ -1017,6 +1019,47 @@ func TestReverseProxyLargeBody(t *testing.T) {
}
}
+func TestCancelRequest(t *testing.T) {
+ backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte("Hello, client"))
+ }))
+ defer backend.Close()
+
+ // set up proxy
+ p := &Proxy{
+ Next: httpserver.EmptyNext, // prevents panic in some cases when test fails
+ Upstreams: []Upstream{newFakeUpstream(backend.URL, false)},
+ }
+
+ // setup request with cancel ctx
+ req := httptest.NewRequest("GET", "/", nil)
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ req = req.WithContext(ctx)
+
+ // add GotConn hook to cancel the request
+ gotC := make(chan struct{})
+ defer close(gotC)
+ trace := &httptrace.ClientTrace{
+ GotConn: func(connInfo httptrace.GotConnInfo) {
+ gotC <- struct{}{}
+ },
+ }
+ req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
+
+ // wait for canceling the request
+ go func() {
+ <-gotC
+ cancel()
+ }()
+
+ status, err := p.ServeHTTP(httptest.NewRecorder(), req)
+ if status != 0 || err != nil {
+ t.Errorf("expect proxy handle normally, but not, status:%d, err:%q",
+ status, err)
+ }
+}
+
type noopReader struct {
len uint64
pos uint64
diff --git a/caddyhttp/proxy/reverseproxy.go b/caddyhttp/proxy/reverseproxy.go
index 27bb44323..945e4e893 100644
--- a/caddyhttp/proxy/reverseproxy.go
+++ b/caddyhttp/proxy/reverseproxy.go
@@ -12,6 +12,7 @@
package proxy
import (
+ "context"
"crypto/tls"
"io"
"net"
@@ -206,6 +207,14 @@ func (rp *ReverseProxy) ServeHTTP(rw http.ResponseWriter, outreq *http.Request,
rp.Director(outreq)
+ // Original incoming server request may be canceled by the
+ // user or by std lib(e.g. too many idle connections).
+ // Now we issue the new outgoing client request which
+ // doesn't depend on the original one. (issue 1345)
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ outreq = outreq.WithContext(ctx)
+
res, err := transport.RoundTrip(outreq)
if err != nil {
return err