|
|
@@ -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
|
|
|
+}
|