diff --git a/src/asset_util/src/lib.rs b/src/asset_util/src/lib.rs index 59433aabb6..7cf85c9917 100644 --- a/src/asset_util/src/lib.rs +++ b/src/asset_util/src/lib.rs @@ -422,19 +422,18 @@ pub fn collect_assets(dir: &Dir, html_transformer: Option String>) - /// NOTE: behavior is undefined with symlinks (and esp. symlink loops)! fn collect_assets_rec(dir: &Dir, assets: &mut Vec) { for asset in dir.files() { - let file_bytes = asset.contents().to_vec(); - let (content, encoding, content_type) = match file_extension(asset) { - "css" => (file_bytes, ContentEncoding::Identity, ContentType::CSS), - "html" => (file_bytes, ContentEncoding::Identity, ContentType::HTML), - "ico" => (file_bytes, ContentEncoding::Identity, ContentType::ICO), - "json" => (file_bytes, ContentEncoding::Identity, ContentType::JSON), - "js" => (file_bytes, ContentEncoding::Identity, ContentType::JS), - "js.gz" => (file_bytes, ContentEncoding::GZip, ContentType::JS), - "png" => (file_bytes, ContentEncoding::Identity, ContentType::PNG), - "svg" => (file_bytes, ContentEncoding::Identity, ContentType::SVG), - "webp" => (file_bytes, ContentEncoding::Identity, ContentType::WEBP), - "woff2" => (file_bytes, ContentEncoding::Identity, ContentType::WOFF2), - "woff2.gz" => (file_bytes, ContentEncoding::GZip, ContentType::WOFF2), + let content = asset.contents().to_vec(); + let (extension, encoding) = file_extension(asset); + let content_type = match extension { + "css" => ContentType::CSS, + "html" => ContentType::HTML, + "ico" => ContentType::ICO, + "json" => ContentType::JSON, + "js" => ContentType::JS, + "png" => ContentType::PNG, + "svg" => ContentType::SVG, + "webp" => ContentType::WEBP, + "woff2" => ContentType::WOFF2, ext => panic!( "Unknown asset type '{}' for asset '{}'", ext, @@ -465,21 +464,29 @@ fn collect_assets_rec(dir: &Dir, assets: &mut Vec) { } } -/// Returns the portion of the filename after the first dot. -/// This corresponds to the file extension for the assets handled by this canister. -/// -/// The builtin `extension` method on `Path` does not work for file extensions with multiple dots -/// such as `.js.gz`. -fn file_extension<'a>(asset: &'a File) -> &'a str { - asset - .path() - .file_name() - .unwrap() - .to_str() - .unwrap() - .split_once('.') - .unwrap() - .1 +/// Returns the extension of the given file, and the encoding type. +/// If the text after the last dot is "gz" (i.e. this is a gzipped file), then the extension +/// is the text after the second to last dot and the last dot in the file name +/// (e.g. "js" for "some.gzipped.file.js.gz"), and the encoding is `ContentEncoding::GZip`. +/// Otherwise the extension is the text after the last dot in the file name, +/// and the encoding is `ContentEncoding::Identity`. +/// This corresponds to the file extension for the assets handled by this crate. +fn file_extension<'a>(asset: &'a File) -> (&'a str, ContentEncoding) { + let extension = asset.path().extension().unwrap().to_str().unwrap(); + if extension == "gz" { + let type_extension = asset + .path() + .file_name() + .unwrap() + .to_str() + .unwrap() + .split('.') + .nth_back(1) + .unwrap(); + return (type_extension, ContentEncoding::GZip); + } else { + return (extension, ContentEncoding::Identity); + } } /// Returns the URL paths for a given asset filepath. For instance: @@ -605,3 +612,30 @@ fn test_filepath_urlpaths() { ], ); } + +#[test] +fn should_return_correct_extension() { + let path_extension_encoding = [ + ("path1/some_css_file.css", "css", ContentEncoding::Identity), + ("path2/an_html_file.html", "html", ContentEncoding::Identity), + ("path3/an_ico_file.ico", "ico", ContentEncoding::Identity), + ("path4/json_file.json", "json", ContentEncoding::Identity), + ("path5/js_file.js", "js", ContentEncoding::Identity), + ("path6/gzipped_js_file.js.gz", "js", ContentEncoding::GZip), + ("path7/a_png_file.png", "png", ContentEncoding::Identity), + ("path8/svg_file.svg", "svg", ContentEncoding::Identity), + ("path9/webp_file.webp", "webp", ContentEncoding::Identity), + ("path10/a_file.woff2", "woff2", ContentEncoding::Identity), + ("path11/gz_woff2.woff2.gz", "woff2", ContentEncoding::GZip), + ("path.dots/ico_file.ico", "ico", ContentEncoding::Identity), + ("path13/file.with.dots.js", "js", ContentEncoding::Identity), + ("path14.dot/gz_js_file.js.gz", "js", ContentEncoding::GZip), + ("path15.dots/.dots.woff2.gz", "woff2", ContentEncoding::GZip), + ]; + for (path, expected_extension, expected_encoding) in path_extension_encoding { + assert_eq!( + file_extension(&File::new(path, &[42])), + (expected_extension, expected_encoding) + ); + } +}