From 7655400560036acb7e9a449f7f3b09b608ded1ff Mon Sep 17 00:00:00 2001 From: Catherine Date: Sun, 14 Dec 2025 19:25:28 +0000 Subject: [PATCH] Limit original size of the contents of a site manifest. The limit is applied to the original size and not compressed size for predictability and fairness. --- src/manifest.go | 14 ++++++++++++-- src/pages.go | 6 ++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/manifest.go b/src/manifest.go index f6d7caa..b84a194 100644 --- a/src/manifest.go +++ b/src/manifest.go @@ -283,6 +283,7 @@ func PrepareManifest(ctx context.Context, manifest *Manifest) error { return nil } +var ErrSiteTooLarge = errors.New("site too large") var ErrManifestTooLarge = errors.New("manifest too large") // Uploads inline file data over certain size to the storage backend. Returns a copy of @@ -325,13 +326,22 @@ func StoreManifest( } } - // Compute the deduplicated storage size. - var blobSizes = make(map[string]int64) + // Compute the total and deduplicated storage size. + totalSize := int64(0) + blobSizes := map[string]int64{} for _, entry := range manifest.Contents { + totalSize += entry.GetOriginalSize() if entry.GetType() == Type_ExternalFile { blobSizes[string(entry.Data)] = entry.GetCompressedSize() } } + if uint64(totalSize) > config.Limits.MaxSiteSize.Bytes() { + return nil, fmt.Errorf("%w: contents size %s exceeds %s limit", + ErrSiteTooLarge, + datasize.ByteSize(totalSize).HR(), + config.Limits.MaxSiteSize.HR(), + ) + } for _, blobSize := range blobSizes { *extManifest.StoredSize += blobSize } diff --git a/src/pages.go b/src/pages.go index cd9f2f7..61f2c17 100644 --- a/src/pages.go +++ b/src/pages.go @@ -599,8 +599,10 @@ func reportUpdateResult(w http.ResponseWriter, r *http.Request, result UpdateRes switch result.outcome { case UpdateError: - if errors.Is(result.err, ErrManifestTooLarge) { - w.WriteHeader(http.StatusRequestEntityTooLarge) + if errors.Is(result.err, ErrSiteTooLarge) { + w.WriteHeader(http.StatusUnprocessableEntity) + } else if errors.Is(result.err, ErrManifestTooLarge) { + w.WriteHeader(http.StatusUnprocessableEntity) } else if errors.Is(result.err, errArchiveFormat) { w.WriteHeader(http.StatusUnsupportedMediaType) } else if errors.Is(result.err, ErrArchiveTooLarge) {