rest: workaround for HTTP2 zero-length replies bug

The golang http client does not return an error when a HTTP2 reply
includes a non-zero content length but does not return any data at all.
This scenario can occur e.g. when using rclone when a file stored in a
backend seems to be accessible but then fails to download.
This commit is contained in:
Michael Eischer 2021-05-16 00:28:12 +02:00
parent 790294dc26
commit 185a55026b
1 changed files with 15 additions and 0 deletions

View File

@ -9,6 +9,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"path" "path"
"strconv"
"strings" "strings"
"golang.org/x/net/context/ctxhttp" "golang.org/x/net/context/ctxhttp"
@ -246,6 +247,20 @@ func (b *Backend) openReader(ctx context.Context, h restic.Handle, length int, o
return nil, errors.Errorf("unexpected HTTP response (%v): %v", resp.StatusCode, resp.Status) return nil, errors.Errorf("unexpected HTTP response (%v): %v", resp.StatusCode, resp.Status)
} }
// workaround https://github.com/golang/go/issues/46071
// see also https://forum.restic.net/t/http2-stream-closed-connection-reset-context-canceled/3743/10
if resp.ContentLength == 0 && resp.ProtoMajor == 2 && resp.ProtoMinor == 0 {
if clens := resp.Header["Content-Length"]; len(clens) == 1 {
if cl, err := strconv.ParseUint(clens[0], 10, 63); err == nil {
resp.ContentLength = int64(cl)
}
if resp.ContentLength != 0 {
_ = resp.Body.Close()
return nil, errors.Errorf("unexpected EOF got 0 instead of %v bytes", resp.ContentLength)
}
}
}
return resp.Body, nil return resp.Body, nil
} }