mirror of
https://github.com/caddyserver/caddy.git
synced 2025-01-23 09:06:29 +01:00
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 <tw19881113@gmail.com> * proxy: add test for canceling the request Signed-off-by: Tw <tw19881113@gmail.com>
This commit is contained in:
parent
696b46f075
commit
38c76647c9
2 changed files with 52 additions and 0 deletions
|
@ -3,6 +3,7 @@ package proxy
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -11,6 +12,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"net/http/httptrace"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"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 {
|
type noopReader struct {
|
||||||
len uint64
|
len uint64
|
||||||
pos uint64
|
pos uint64
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
@ -206,6 +207,14 @@ func (rp *ReverseProxy) ServeHTTP(rw http.ResponseWriter, outreq *http.Request,
|
||||||
|
|
||||||
rp.Director(outreq)
|
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)
|
res, err := transport.RoundTrip(outreq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
Loading…
Reference in a new issue