webdav: prevent webdav client race condition (#626)

The race is described in
https://github.com/studio-b12/gowebdav/issues/36

We need this workaround until the fix is merged upstream,
to avoid maintaining a webdav client fork.

Fixes #624
This commit is contained in:
Jarek Kowalski
2020-09-19 11:47:57 -07:00
committed by GitHub
parent 538c644586
commit 04fcddeff0
2 changed files with 35 additions and 2 deletions

View File

@@ -6,8 +6,13 @@
"os/exec"
"testing"
"github.com/google/uuid"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
"github.com/kopia/kopia/internal/blobtesting"
"github.com/kopia/kopia/internal/testlogging"
"github.com/kopia/kopia/repo/blob"
"github.com/kopia/kopia/repo/blob/rclone"
)
@@ -36,6 +41,24 @@ func TestRCloneStorage(t *testing.T) {
defer st.Close(ctx)
var eg errgroup.Group
// trigger multiple parallel reads to ensure we're properly preventing race
// described in https://github.com/kopia/kopia/issues/624
for i := 0; i < 100; i++ {
eg.Go(func() error {
if _, err := st.GetBlob(ctx, blob.ID(uuid.New().String()), 0, -1); !errors.Is(err, blob.ErrBlobNotFound) {
return errors.Errorf("unexpected error when downloading non-existent blob: %v", err)
}
return nil
})
}
if err := eg.Wait(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
blobtesting.VerifyStorage(ctx, t, st)
blobtesting.AssertConnectionInfoRoundTrips(ctx, t, st)
}

View File

@@ -12,6 +12,7 @@
"strings"
"time"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/studio-b12/gowebdav"
@@ -201,7 +202,7 @@ func New(ctx context.Context, opts *Options) (blob.Storage, error) {
cli.SetTransport(tlsutil.TransportTrustingSingleCertificate(opts.TrustedServerCertificateFingerprint))
}
return &davStorage{
s := &davStorage{
sharded.Storage{
Impl: &davStorageImpl{
Options: *opts,
@@ -211,7 +212,16 @@ func New(ctx context.Context, opts *Options) (blob.Storage, error) {
Suffix: fsStorageChunkSuffix,
Shards: opts.shards(),
},
}, nil
}
// temporary workaround to a race condition problem in https://github.com/studio-b12/gowebdav/issues/36
// the race condition is only during first request to the server, so to fix it we force the first request
// to read a non-existent blob, which sets the authentication method.
if _, err := s.GetBlob(ctx, blob.ID(uuid.New().String()), 0, -1); !errors.Is(err, blob.ErrBlobNotFound) {
return nil, errors.Errorf("unexpected error when initializing webdav: %v", err)
}
return s, nil
}
func init() {