Repository: Y2Z/monolith
Pull request #458 (2025-03-30 00:26:42)

Fix parsing of srcset with whitespaces


Patch:
diff --git a/src/html.rs b/src/html.rs
index dd1df93..8b5283c 100644
--- a/src/html.rs
+++ b/src/html.rs
@@ -22,6 +22,9 @@ use crate::url::{
     clean_url, create_data_url, is_url_and_has_protocol, resolve_url, EMPTY_IMAGE_DATA_URL,
 };
 
+const FAVICON_VALUES: &[&str] = &["icon", "shortcut icon"];
+const WHITESPACES: &[char] = &[' ', '\t', '\n', '\x0c', '\r']; // ASCII whitespaces
+
 #[derive(PartialEq, Eq)]
 pub enum LinkType {
     Alternate,
@@ -32,14 +35,11 @@ pub enum LinkType {
     Stylesheet,
 }
 
-struct SrcSetItem<'a> {
-    path: &'a str,
-    descriptor: &'a str, // Width or pixel density descriptor
+pub struct SrcSetItem<'a> {
+    pub path: &'a str,
+    pub descriptor: &'a str, // Width or pixel density descriptor
 }
 
-const FAVICON_VALUES: &[&str] = &["icon", "shortcut icon"];
-const WHITESPACES: &[char] = &[' ', '\t', '\n', '\x0c', '\r']; // ASCII whitespaces
-
 pub fn add_favicon(document: &Handle, favicon_data_url: String) -> RcDom {
     let mut buf: Vec<u8> = Vec::new();
     serialize(
@@ -394,6 +394,8 @@ pub fn parse_srcset(srcset: &str) -> Vec<SrcSetItem> {
     while i < partials.len() {
         let partial = partials[i];
 
+        i += 1;
+
         // Skip empty strings
         if partial.is_empty() {
             continue;
@@ -435,8 +437,6 @@ pub fn parse_srcset(srcset: &str) -> Vec<SrcSetItem> {
             path = None;
             descriptor = None;
         }
-
-        i += 1;
     }
 
     // Final attempt to process what was found


Test patch:
diff --git a/tests/html/mod.rs b/tests/html/mod.rs
index 8aebfed..a1e8e76 100644
--- a/tests/html/mod.rs
+++ b/tests/html/mod.rs
@@ -10,6 +10,7 @@ mod get_node_name;
 mod has_favicon;
 mod is_favicon;
 mod parse_link_type;
+mod parse_srcset;
 mod serialize_document;
 mod set_node_attr;
 mod walk_and_embed_assets;
diff --git a/tests/html/parse_srcset.rs b/tests/html/parse_srcset.rs
new file mode 100644
index 0000000..6fee5f1
--- /dev/null
+++ b/tests/html/parse_srcset.rs
@@ -0,0 +1,27 @@
+//  ██████╗  █████╗ ███████╗███████╗██╗███╗   ██╗ ██████╗
+//  ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗  ██║██╔════╝
+//  ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║  ███╗
+//  ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║   ██║
+//  ██║     ██║  ██║███████║███████║██║██║ ╚████║╚██████╔╝
+//  ╚═╝     ╚═╝  ╚═╝╚══════╝╚══════╝╚═╝╚═╝  ╚═══╝ ╚═════╝
+
+#[cfg(test)]
+mod passing {
+    use monolith::html::{parse_srcset, SrcSetItem};
+
+    #[test]
+    fn three_items_with_width_descriptors_and_newlines() {
+        let srcset = r#"https://some-site.com/width/600/https://media2.some-site.com/2021/07/some-image-073362.jpg 600w,
+                        https://some-site.com/width/960/https://media2.some-site.com/2021/07/some-image-073362.jpg 960w,
+                        https://some-site.com/width/1200/https://media2.some-site.com/2021/07/some-image-073362.jpg 1200w"#;
+        let srcset_items: Vec<SrcSetItem> = parse_srcset(srcset);
+
+        assert_eq!(srcset_items.len(), 3);
+        assert_eq!(srcset_items[0].path, "https://some-site.com/width/600/https://media2.some-site.com/2021/07/some-image-073362.jpg");
+        assert_eq!(srcset_items[0].descriptor, "600w");
+        assert_eq!(srcset_items[1].path, "https://some-site.com/width/960/https://media2.some-site.com/2021/07/some-image-073362.jpg");
+        assert_eq!(srcset_items[1].descriptor, "960w");
+        assert_eq!(srcset_items[2].path, "https://some-site.com/width/1200/https://media2.some-site.com/2021/07/some-image-073362.jpg");
+        assert_eq!(srcset_items[2].descriptor, "1200w");
+    }
+}