2
2
mirror of https://github.com/octoleo/restic.git synced 2025-01-02 22:50:19 +00:00

rest: remove workaround for content-length handling bug

This commit is contained in:
Michael Eischer 2022-11-26 12:09:01 +01:00
parent 8ad231bcad
commit 530f129a39
3 changed files with 1 additions and 121 deletions

View File

@ -1,7 +1,7 @@
Change: Update dependencies and require Go 1.18 or newer Change: Update dependencies and require Go 1.18 or newer
We've updated most dependencies. Since some libraries require newer language 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. requires at least Go 1.18 to build.
https://github.com/restic/restic/pull/4041 https://github.com/restic/restic/pull/4041

View File

@ -8,10 +8,8 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/textproto"
"net/url" "net/url"
"path" "path"
"strconv"
"strings" "strings"
"github.com/restic/restic/internal/backend/layout" "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 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) { 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) debug.Log("Load %v, length %v, offset %v", h, length, offset)
if err := h.Valid(); err != nil { 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) 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 return resp.Body, nil
} }

View File

@ -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")
}
}