Skip to content

Commit 77863f1

Browse files
Web3NLclaude
andcommitted
fix(my-canister-frontend): expose MAX_FILE_SIZE, add COOP comment, test .gz rejection
- Make MAX_FILE_SIZE a pub const with doc comment - Explain same-origin-allow-popups is required for Internet Identity popups - Add test asserting .gz files are rejected with a clear error - Extend README description to mention static serving Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 4d135ae commit 77863f1

2 files changed

Lines changed: 24 additions & 5 deletions

File tree

packages-rs/my-canister-frontend/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[![Build Status](https://github.com/Web3NL/my-canister-dapp/workflows/Release/badge.svg)](https://github.com/Web3NL/my-canister-dapp/actions)
66
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
77

8-
Frontend asset processing library for canisters on the Internet Computer.
8+
Frontend asset processing and static serving library for canisters on the Internet Computer.
99

1010
## Usage
1111

packages-rs/my-canister-frontend/src/asset_router.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ pub const DEFAULT_ALLOWED_EXTENSIONS: &[&str] = &[
1616
"woff2", "ttf", "otf", "eot", "json", "xml", "txt", "wasm", "map",
1717
];
1818

19-
// ICP query responses are capped at 2 MiB. Each response includes ~3.5 KB of
20-
// HTTP headers (IC-Certificate, security headers, Content-Type, etc.) on top of
21-
// the body. Reserve 16 KiB to ensure the total response always fits.
22-
const MAX_FILE_SIZE: usize = 2 * 1024 * 1024 - 16 * 1024;
19+
/// Maximum allowed file size in bytes (2 MiB − 16 KiB).
20+
///
21+
/// ICP query responses are capped at 2 MiB. Each response includes ~3.5 KB of
22+
/// HTTP headers (IC-Certificate, security headers, Content-Type, etc.) on top of
23+
/// the body. 16 KiB is reserved to ensure the total response always fits.
24+
pub const MAX_FILE_SIZE: usize = 2 * 1024 * 1024 - 16 * 1024;
2325

2426
/// File extensions that benefit from gzip compression.
2527
/// Binary formats (images, fonts, wasm) are already compressed.
@@ -327,6 +329,8 @@ fn build_headers(config: &FrontendConfig) -> Vec<(String, String)> {
327329
"Permissions-Policy".into(),
328330
"accelerometer=(), camera=(), geolocation=(), microphone=(), payment=(), usb=()".into(),
329331
),
332+
// same-origin-allow-popups is required for Internet Identity authentication,
333+
// which opens a popup window to complete the login flow.
330334
(
331335
"Cross-Origin-Opener-Policy".into(),
332336
"same-origin-allow-popups".into(),
@@ -885,6 +889,21 @@ mod tests {
885889
let config = FrontendConfig::default();
886890
assert!(validate_asset("/my-app_v2.js", 100, &config).is_ok());
887891
}
892+
893+
#[test]
894+
fn rejects_gz_extension() {
895+
// A manually-included .gz file (e.g. app.js.gz) is not in the allowlist.
896+
// The crate generates its own .gz variants internally; user-provided ones
897+
// would collide with those generated paths and produce a confusing duplicate error.
898+
// Rejecting .gz at validation gives a clear, actionable message instead.
899+
let config = FrontendConfig::default();
900+
let result = validate_asset("/app.js.gz", 100, &config);
901+
assert!(result.is_err());
902+
assert!(
903+
result.unwrap_err().contains("not in the allowed list"),
904+
"expected 'not in the allowed list' error for .gz file"
905+
);
906+
}
888907
}
889908

890909
mod gzip_compression {

0 commit comments

Comments
 (0)