diff --git a/changelog/unreleased/pull-4041 b/changelog/unreleased/pull-4041 index 35c7086ae..2e4a8de9d 100644 --- a/changelog/unreleased/pull-4041 +++ b/changelog/unreleased/pull-4041 @@ -1,7 +1,7 @@ Change: Update dependencies and require Go 1.18 or newer We've updated most dependencies. Since some libraries require newer language -features we're dropping support for Go 1.15 - 1.17, which means that restic now +features, we're dropping support for Go 1.15 - 1.17, which means that restic now requires at least Go 1.18 to build. https://github.com/restic/restic/pull/4041 diff --git a/internal/backend/rest/rest.go b/internal/backend/rest/rest.go index 3431fd681..be8b33363 100644 --- a/internal/backend/rest/rest.go +++ b/internal/backend/rest/rest.go @@ -8,10 +8,8 @@ import ( "io" "io/ioutil" "net/http" - "net/textproto" "net/url" "path" - "strconv" "strings" "github.com/restic/restic/internal/backend/layout" @@ -214,44 +212,6 @@ func (b *Backend) Load(ctx context.Context, h restic.Handle, length int, offset return err } -// checkContentLength returns an error if the server returned a value in the -// Content-Length header in an HTTP2 connection, but closed the connection -// before any data was sent. -// -// This is a workaround for https://github.com/golang/go/issues/46071 -// -// See also https://forum.restic.net/t/http2-stream-closed-connection-reset-context-canceled/3743/10 -func checkContentLength(resp *http.Response) error { - // the following code is based on - // https://github.com/golang/go/blob/b7a85e0003cedb1b48a1fd3ae5b746ec6330102e/src/net/http/h2_bundle.go#L8646 - - if resp.ContentLength != 0 { - return nil - } - - if resp.ProtoMajor != 2 && resp.ProtoMinor != 0 { - return nil - } - - if len(resp.Header[textproto.CanonicalMIMEHeaderKey("Content-Length")]) != 1 { - return nil - } - - // make sure that if the server returned a content length and we can - // parse it, it is really zero, otherwise return an error - contentLength := resp.Header.Get("Content-Length") - cl, err := strconv.ParseUint(contentLength, 10, 63) - if err != nil { - return fmt.Errorf("unable to parse Content-Length %q: %w", contentLength, err) - } - - if cl != 0 { - return errors.Errorf("unexpected EOF: got 0 instead of %v bytes", cl) - } - - return nil -} - func (b *Backend) openReader(ctx context.Context, h restic.Handle, length int, offset int64) (io.ReadCloser, error) { debug.Log("Load %v, length %v, offset %v", h, length, offset) if err := h.Valid(); err != nil { @@ -301,14 +261,6 @@ 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 - err = checkContentLength(resp) - if err != nil { - _ = resp.Body.Close() - return nil, err - } - return resp.Body, nil } diff --git a/internal/backend/rest/rest_int_go114_test.go b/internal/backend/rest/rest_int_go114_test.go deleted file mode 100644 index 7c040bf51..000000000 --- a/internal/backend/rest/rest_int_go114_test.go +++ /dev/null @@ -1,72 +0,0 @@ -//go:build go1.14 && !go1.18 -// +build go1.14,!go1.18 - -// missing eof error is fixed in golang >= 1.17.3 or >= 1.16.10 -// remove the workaround from rest.go when the minimum golang version -// supported by restic reaches 1.18. - -package rest_test - -import ( - "context" - "io" - "io/ioutil" - "net/http" - "net/http/httptest" - "net/url" - "testing" - - "github.com/restic/restic/internal/backend/rest" - "github.com/restic/restic/internal/restic" -) - -func TestZeroLengthRead(t *testing.T) { - // Test workaround for https://github.com/golang/go/issues/46071. Can be removed once this is fixed in Go - // and the minimum golang version supported by restic includes the fix. - numRequests := 0 - srv := httptest.NewUnstartedServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { - numRequests++ - t.Logf("req %v %v", req.Method, req.URL.Path) - if req.Method == "GET" { - res.Header().Set("Content-Length", "42") - // Now the handler fails for some reason and is unable to send data - return - } - - t.Errorf("unhandled request %v %v", req.Method, req.URL.Path) - })) - srv.EnableHTTP2 = true - srv.StartTLS() - defer srv.Close() - - srvURL, err := url.Parse(srv.URL) - if err != nil { - t.Fatal(err) - } - - cfg := rest.Config{ - Connections: 5, - URL: srvURL, - } - be, err := rest.Open(cfg, srv.Client().Transport) - if err != nil { - t.Fatal(err) - } - defer func() { - err = be.Close() - if err != nil { - t.Fatal(err) - } - }() - - err = be.Load(context.TODO(), restic.Handle{Type: restic.ConfigFile}, 0, 0, func(rd io.Reader) error { - _, err := ioutil.ReadAll(rd) - if err == nil { - t.Fatal("ReadAll should have returned an 'Unexpected EOF' error") - } - return nil - }) - if err == nil { - t.Fatal("Got no unexpected EOF error") - } -}