mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-04-30 17:38:41 +00:00
SplitHTTP: Fix connection leaks and crashes (#3710)
This commit is contained in:
parent
2be03c56cb
commit
83eef6bc1f
7 changed files with 109 additions and 65 deletions
|
@ -49,6 +49,8 @@ func (c *DefaultDialerClient) OpenDownload(ctx context.Context, baseURL string)
|
|||
var downResponse io.ReadCloser
|
||||
gotDownResponse := done.New()
|
||||
|
||||
ctx, ctxCancel := context.WithCancel(ctx)
|
||||
|
||||
go func() {
|
||||
trace := &httptrace.ClientTrace{
|
||||
GotConn: func(connInfo httptrace.GotConnInfo) {
|
||||
|
@ -61,8 +63,10 @@ func (c *DefaultDialerClient) OpenDownload(ctx context.Context, baseURL string)
|
|||
// in case we hit an error, we want to unblock this part
|
||||
defer gotConn.Close()
|
||||
|
||||
ctx = httptrace.WithClientTrace(ctx, trace)
|
||||
|
||||
req, err := http.NewRequestWithContext(
|
||||
httptrace.WithClientTrace(ctx, trace),
|
||||
ctx,
|
||||
"GET",
|
||||
baseURL,
|
||||
nil,
|
||||
|
@ -94,16 +98,17 @@ func (c *DefaultDialerClient) OpenDownload(ctx context.Context, baseURL string)
|
|||
gotDownResponse.Close()
|
||||
}()
|
||||
|
||||
if c.isH3 {
|
||||
gotConn.Close()
|
||||
if !c.isH3 {
|
||||
// in quic-go, sometimes gotConn is never closed for the lifetime of
|
||||
// the entire connection, and the download locks up
|
||||
// https://github.com/quic-go/quic-go/issues/3342
|
||||
// for other HTTP versions, we want to block Dial until we know the
|
||||
// remote address of the server, for logging purposes
|
||||
<-gotConn.Wait()
|
||||
}
|
||||
|
||||
// we want to block Dial until we know the remote address of the server,
|
||||
// for logging purposes
|
||||
<-gotConn.Wait()
|
||||
|
||||
lazyDownload := &LazyReader{
|
||||
CreateReader: func() (io.ReadCloser, error) {
|
||||
CreateReader: func() (io.Reader, error) {
|
||||
<-gotDownResponse.Wait()
|
||||
if downResponse == nil {
|
||||
return nil, errors.New("downResponse failed")
|
||||
|
@ -112,7 +117,15 @@ func (c *DefaultDialerClient) OpenDownload(ctx context.Context, baseURL string)
|
|||
},
|
||||
}
|
||||
|
||||
return lazyDownload, remoteAddr, localAddr, nil
|
||||
// workaround for https://github.com/quic-go/quic-go/issues/2143 --
|
||||
// always cancel request context so that Close cancels any Read.
|
||||
// Should then match the behavior of http2 and http1.
|
||||
reader := downloadBody{
|
||||
lazyDownload,
|
||||
ctxCancel,
|
||||
}
|
||||
|
||||
return reader, remoteAddr, localAddr, nil
|
||||
}
|
||||
|
||||
func (c *DefaultDialerClient) SendUploadRequest(ctx context.Context, url string, payload io.ReadWriteCloser, contentLength int64) error {
|
||||
|
@ -172,3 +185,13 @@ func (c *DefaultDialerClient) SendUploadRequest(ctx context.Context, url string,
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
type downloadBody struct {
|
||||
io.Reader
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (c downloadBody) Close() error {
|
||||
c.cancel()
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue