From 185a55026b6701e9f8363cbfe764bca503f4de95 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sun, 16 May 2021 00:28:12 +0200 Subject: [PATCH] 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. --- internal/backend/rest/rest.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/internal/backend/rest/rest.go b/internal/backend/rest/rest.go index 44fcaead6..78cb6b10b 100644 --- a/internal/backend/rest/rest.go +++ b/internal/backend/rest/rest.go @@ -9,6 +9,7 @@ import ( "net/http" "net/url" "path" + "strconv" "strings" "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) } + // 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 }