Skip to content

Commit f07e330

Browse files
vnghiactron
authored andcommitted
fix: dont escape asset integrity
1 parent ab628ab commit f07e330

File tree

13 files changed

+79
-42
lines changed

13 files changed

+79
-42
lines changed

src/pipelines/copy_dir.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ impl CopyDir {
3737
r#"required attr `href` missing for <link data-trunk rel="copy-dir" .../> element"#,
3838
)?;
3939
let mut path = PathBuf::new();
40-
path.extend(href_attr.split('/'));
40+
path.extend(href_attr.value.split('/'));
4141
if !path.is_absolute() {
4242
path = html_dir.join(path);
4343
}

src/pipelines/copy_file.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl CopyFile {
3838
r#"required attr `href` missing for <link data-trunk rel="copy-file" .../> element"#,
3939
)?;
4040
let mut path = PathBuf::new();
41-
path.extend(href_attr.split('/'));
41+
path.extend(href_attr.value.split('/'));
4242
let asset = AssetFile::new(&html_dir, path).await?;
4343

4444
let target_path = data_target_path(&attrs)?;

src/pipelines/css.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ impl Css {
4747
r#"required attr `href` missing for <link data-trunk rel="css" .../> element"#,
4848
)?;
4949
let mut path = PathBuf::new();
50-
path.extend(href_attr.split('/'));
50+
path.extend(href_attr.value.split('/'));
5151
let asset = AssetFile::new(&html_dir, path).await?;
5252

5353
let integrity = IntegrityType::from_attrs(&attrs, &cfg)?;

src/pipelines/html.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ impl HtmlPipeline {
120120
// raw data instead of passing around the link itself, is the lifetime
121121
// requirements of elements used in `lol_html::html_content::HtmlRewriter`.
122122
let attrs = el.attributes().iter().fold(Attrs::new(), |mut acc, attr| {
123-
acc.insert(attr.name(), attr.value());
123+
acc.insert(attr.name(), attr.value().into());
124124
acc
125125
});
126126

src/pipelines/icon.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ impl Icon {
4444
r#"required attr `href` missing for <link data-trunk rel="icon" .../> element"#,
4545
)?;
4646
let mut path = PathBuf::new();
47-
path.extend(href_attr.split('/'));
47+
path.extend(href_attr.value.split('/'));
4848
let asset = AssetFile::new(&html_dir, path).await?;
4949

5050
let integrity = IntegrityType::from_attrs(&attrs, &cfg)?;

src/pipelines/inline.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,13 @@ impl Inline {
3737
)?;
3838

3939
let mut path = PathBuf::new();
40-
path.extend(href_attr.split('/'));
40+
path.extend(href_attr.value.split('/'));
4141

4242
let asset = AssetFile::new(&html_dir, path).await?;
43-
let content_type =
44-
ContentType::from_attr_or_ext(attrs.get(ATTR_TYPE), asset.ext.as_deref())?;
43+
let content_type = ContentType::from_attr_or_ext(
44+
attrs.get(ATTR_TYPE).map(|attr| &attr.value),
45+
asset.ext.as_deref(),
46+
)?;
4547

4648
Ok(Self {
4749
id,

src/pipelines/js.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ impl Js {
4747
.get(ATTR_SRC)
4848
.context(r#"required attr `src` missing for <script data-trunk ...> element"#)?;
4949
let mut path = PathBuf::new();
50-
path.extend(src_attr.split('/'));
50+
path.extend(src_attr.value.split('/'));
5151
let asset = AssetFile::new(&html_dir, path).await?;
5252

5353
let integrity = IntegrityType::from_attrs(&attrs, &cfg)?;
54-
let module = attrs.get("type").map(|s| s.as_str()) == Some("module");
54+
let module = attrs.get("type").map(|s| s.value.as_str()) == Some("module");
5555
let no_minify = attrs.contains_key(ATTR_NO_MINIFY);
5656
let target_path = data_target_path(&attrs)?;
5757

src/pipelines/mod.rs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use serde::{Deserialize, Serialize};
4141
use std::{
4242
collections::HashMap,
4343
ffi::OsString,
44-
fmt::{self},
44+
fmt::{self, Display},
4545
path::{Path, PathBuf},
4646
sync::Arc,
4747
};
@@ -60,8 +60,14 @@ const SNIPPETS_DIR: &str = "snippets";
6060
const TRUNK_ID: &str = "data-trunk-id";
6161
const PNG_OPTIMIZATION_LEVEL: u8 = 6;
6262

63+
#[derive(Debug, Clone)]
64+
pub struct Attr {
65+
pub value: String,
66+
pub need_escape: bool,
67+
}
68+
6369
/// A mapping of all attrs associated with a specific `<link data-trunk .../>` element.
64-
pub type Attrs = HashMap<String, String>;
70+
pub type Attrs = HashMap<String, Attr>;
6571

6672
/// A reference to a trunk asset.
6773
pub enum TrunkAssetReference {
@@ -89,6 +95,15 @@ pub enum TrunkAsset {
8995
RustApp(RustApp),
9096
}
9197

98+
impl<S: Display> From<S> for Attr {
99+
fn from(value: S) -> Self {
100+
Self {
101+
value: value.to_string(),
102+
need_escape: true,
103+
}
104+
}
105+
}
106+
92107
impl TrunkAsset {
93108
/// Construct a new instance.
94109
pub async fn from_html(
@@ -104,7 +119,7 @@ impl TrunkAsset {
104119
"all <link data-trunk .../> elements must have a `rel` attribute indicating \
105120
the asset type",
106121
)?;
107-
Ok(match rel.as_str() {
122+
Ok(match rel.value.as_str() {
108123
Sass::TYPE_SASS | Sass::TYPE_SCSS => {
109124
Self::Sass(Sass::new(cfg, html_dir, attrs, id).await?)
110125
}
@@ -130,7 +145,7 @@ impl TrunkAsset {
130145
),
131146
_ => bail!(
132147
r#"unknown <link data-trunk .../> attr value `rel="{}"`; please ensure the value is lowercase and is a supported asset type"#,
133-
rel
148+
rel.value
134149
),
135150
})
136151
}
@@ -414,10 +429,14 @@ impl fmt::Display for AttrWriter<'_> {
414429
// Assume the name doesn't need to be escaped, as if we managed to parse it as HTML,
415430
// then it's probably fine.
416431
write!(f, " {name}")?;
417-
let value = &self.attrs[name];
418-
if !value.is_empty() {
419-
let encoded = htmlescape::encode_attribute(value);
420-
write!(f, "=\"{}\"", encoded)?;
432+
let attr = &self.attrs[name];
433+
if !attr.value.is_empty() {
434+
if attr.need_escape {
435+
let encoded = htmlescape::encode_attribute(&attr.value);
436+
write!(f, "=\"{}\"", encoded)?;
437+
} else {
438+
write!(f, "=\"{}\"", attr.value)?;
439+
}
421440
}
422441
}
423442
Ok(())
@@ -428,7 +447,7 @@ impl fmt::Display for AttrWriter<'_> {
428447
fn data_target_path(attrs: &Attrs) -> Result<Option<PathBuf>> {
429448
Ok(attrs
430449
.get(ATTR_TARGET_PATH)
431-
.map(|val| val.trim_end_matches('/'))
450+
.map(|attr| attr.value.trim_end_matches('/'))
432451
.map(|val| val.parse())
433452
.transpose()?)
434453
}

src/pipelines/rust/mod.rs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ impl RustApp {
138138
.get(ATTR_HREF)
139139
.map(|attr| {
140140
let mut path = PathBuf::new();
141-
path.extend(attr.split('/'));
141+
path.extend(attr.value.split('/'));
142142
if !path.is_absolute() {
143143
path = html_dir.join(path);
144144
}
@@ -148,21 +148,23 @@ impl RustApp {
148148
path
149149
})
150150
.unwrap_or_else(|| html_dir.join("Cargo.toml"));
151-
let bin = attrs.get("data-bin").map(|val| val.to_string());
152-
let target_name = attrs.get("data-target-name").map(|val| val.to_string());
151+
let bin = attrs.get("data-bin").map(|attr| attr.value.to_string());
152+
let target_name = attrs
153+
.get("data-target-name")
154+
.map(|attr| attr.value.to_string());
153155
let keep_debug = attrs.contains_key("data-keep-debug");
154156
let typescript = attrs.contains_key("data-typescript");
155157
let no_demangle = attrs.contains_key("data-no-demangle");
156158
let app_type = attrs
157159
.get("data-type")
158-
.map(|s| s.parse())
160+
.map(|attr| attr.value.parse())
159161
.transpose()?
160162
.unwrap_or(RustAppType::Main);
161163
let reference_types = attrs.contains_key("data-reference-types");
162164
let weak_refs = attrs.contains_key("data-weak-refs");
163165
let wasm_opt = attrs
164166
.get("data-wasm-opt")
165-
.map(|val| val.parse())
167+
.map(|attr| attr.value.parse())
166168
.transpose()?
167169
.unwrap_or_else(|| {
168170
if cfg.release {
@@ -174,20 +176,20 @@ impl RustApp {
174176
let wasm_opt_params = attrs
175177
.get("data-wasm-opt-params")
176178
.iter()
177-
.flat_map(|val| val.split_whitespace())
179+
.flat_map(|attr| attr.value.split_whitespace())
178180
.map(|val| val.to_string())
179181
.collect();
180182
let wasm_bindgen_target = attrs
181183
.get("data-bindgen-target")
182-
.map(|s| s.parse())
184+
.map(|attr| attr.value.parse())
183185
.transpose()?
184186
.unwrap_or(match app_type {
185187
RustAppType::Main => WasmBindgenTarget::Web,
186188
RustAppType::Worker => WasmBindgenTarget::NoModules,
187189
});
188190
let cross_origin = attrs
189191
.get("data-cross-origin")
190-
.map(|val| CrossOrigin::from_str(val))
192+
.map(|attr| CrossOrigin::from_str(&attr.value))
191193
.transpose()?
192194
.unwrap_or_default();
193195
let integrity = IntegrityType::from_attrs(&attrs, &cfg)?;
@@ -214,8 +216,9 @@ impl RustApp {
214216

215217
let cargo_profile = match data_cargo_profile {
216218
Some(cargo_profile) => {
219+
let cargo_profile = &cargo_profile.value;
217220
if let Some(config_cargo_profile) = &cfg.cargo_profile {
218-
log::warn!("Cargo profile from configuration ({config_cargo_profile}) will be overridden with HTML file's more specific setting ({cargo_profile})");
221+
log::warn!("Cargo profile from configuration ({config_cargo_profile}) will be overridden with HTML file's more specific setting ({})", cargo_profile);
219222
}
220223
Some(cargo_profile.clone())
221224
}
@@ -224,7 +227,9 @@ impl RustApp {
224227

225228
// cargo features
226229

227-
let data_features = attrs.get("data-cargo-features").map(|val| val.to_string());
230+
let data_features = attrs
231+
.get("data-cargo-features")
232+
.map(|attr| attr.value.to_string());
228233
let data_all_features = attrs.contains_key("data-cargo-all-features");
229234
let data_no_default_features = attrs.contains_key("data-cargo-no-default-features");
230235

@@ -254,13 +259,16 @@ impl RustApp {
254259
// bindings
255260

256261
let import_bindings = !attrs.contains_key("data-wasm-no-import");
257-
let import_bindings_name = attrs.get("data-wasm-import-name").cloned();
262+
let import_bindings_name = attrs
263+
.get("data-wasm-import-name")
264+
.map(|attr| &attr.value)
265+
.cloned();
258266

259267
// progress function
260268

261269
let initializer = attrs
262270
.get("data-initializer")
263-
.map(|path| PathBuf::from_str(path))
271+
.map(|path| PathBuf::from_str(&path.value))
264272
.transpose()?
265273
.map(|path| {
266274
if !path.is_absolute() {
@@ -403,7 +411,7 @@ impl RustApp {
403411
];
404412
if let Some(profile) = &self.cargo_profile {
405413
args.push("--profile");
406-
args.push(profile);
414+
args.push(&profile);
407415
} else if self.cfg.release {
408416
args.push("--release");
409417
}

src/pipelines/sass.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ impl Sass {
4949
r#"required attr `href` missing for <link data-trunk rel="sass|scss" .../> element"#,
5050
)?;
5151
let mut path = PathBuf::new();
52-
path.extend(href_attr.split('/'));
52+
path.extend(href_attr.value.split('/'));
5353
let asset = AssetFile::new(&html_dir, path).await?;
5454
let use_inline = attrs.contains_key(ATTR_INLINE);
5555
let no_minify = attrs.contains_key(ATTR_NO_MINIFY);

0 commit comments

Comments
 (0)