Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'internal/vfs/zip/archive.go')
-rw-r--r--internal/vfs/zip/archive.go42
1 files changed, 31 insertions, 11 deletions
diff --git a/internal/vfs/zip/archive.go b/internal/vfs/zip/archive.go
index df175764..1137f004 100644
--- a/internal/vfs/zip/archive.go
+++ b/internal/vfs/zip/archive.go
@@ -32,13 +32,21 @@ var (
errNotFile = errors.New("not a file")
)
+type archiveStatus int
+
+const (
+ archiveOpening archiveStatus = iota
+ archiveOpenError
+ archiveOpened
+ archiveCorrupted
+)
+
// zipArchive implements the vfs.Root interface.
// It represents a zip archive saving all its files in memory.
// It holds an httprange.Resource that can be read with httprange.RangedReader in chunks.
type zipArchive struct {
fs *zipVFS
- path string
once sync.Once
done chan struct{}
openTimeout time.Duration
@@ -54,10 +62,9 @@ type zipArchive struct {
directories map[string]*zip.FileHeader
}
-func newArchive(fs *zipVFS, path string, openTimeout time.Duration) *zipArchive {
+func newArchive(fs *zipVFS, openTimeout time.Duration) *zipArchive {
return &zipArchive{
fs: fs,
- path: path,
done: make(chan struct{}),
files: make(map[string]*zip.File),
directories: make(map[string]*zip.FileHeader),
@@ -66,9 +73,14 @@ func newArchive(fs *zipVFS, path string, openTimeout time.Duration) *zipArchive
}
}
-func (a *zipArchive) openArchive(parentCtx context.Context) (err error) {
+func (a *zipArchive) openArchive(parentCtx context.Context, url string) (err error) {
+ // always try to update URL on resource
+ if a.resource != nil {
+ a.resource.SetURL(url)
+ }
+
// return early if openArchive was done already in a concurrent request
- if ok, err := a.openStatus(); ok {
+ if status, err := a.openStatus(); status != archiveOpening {
return err
}
@@ -78,7 +90,7 @@ func (a *zipArchive) openArchive(parentCtx context.Context) (err error) {
a.once.Do(func() {
// read archive once in its own routine with its own timeout
// if parentCtx is canceled, readArchive will continue regardless and will be cached in memory
- go a.readArchive()
+ go a.readArchive(url)
})
// wait for readArchive to be done or return if the parent context is canceled
@@ -100,14 +112,14 @@ func (a *zipArchive) openArchive(parentCtx context.Context) (err error) {
// readArchive creates an httprange.Resource that can read the archive's contents and stores a slice of *zip.Files
// that can be accessed later when calling any of th vfs.VFS operations
-func (a *zipArchive) readArchive() {
+func (a *zipArchive) readArchive(url string) {
defer close(a.done)
// readArchive with a timeout separate from openArchive's
ctx, cancel := context.WithTimeout(context.Background(), a.openTimeout)
defer cancel()
- a.resource, a.err = httprange.NewResource(ctx, a.path)
+ a.resource, a.err = httprange.NewResource(ctx, url)
if a.err != nil {
metrics.ZipOpened.WithLabelValues("error").Inc()
return
@@ -281,12 +293,20 @@ func (a *zipArchive) onEvicted() {
metrics.ZipArchiveEntriesCached.Sub(float64(len(a.files)))
}
-func (a *zipArchive) openStatus() (bool, error) {
+func (a *zipArchive) openStatus() (archiveStatus, error) {
select {
case <-a.done:
- return true, a.err
+ if a.err != nil {
+ return archiveOpenError, a.err
+ }
+
+ if a.resource != nil && a.resource.Err() != nil {
+ return archiveCorrupted, a.resource.Err()
+ }
+
+ return archiveOpened, nil
default:
- return false, nil
+ return archiveOpening, nil
}
}