diff --git a/src/css.rs b/src/css.rs index 6be5de6..4572e36 100644 --- a/src/css.rs +++ b/src/css.rs @@ -2,6 +2,7 @@ use cssparser::{ParseError, Parser, ParserInput, SourcePosition, Token}; use reqwest::blocking::Client; use std::collections::HashMap; +use crate::opts::Options; use crate::url::{data_to_data_url, get_url_fragment, is_http_url, resolve_url, url_with_fragment}; use crate::utils::retrieve_asset; @@ -59,12 +60,10 @@ pub fn process_css<'a>( client: &Client, parent_url: &str, parser: &mut Parser, + options: &Options, rule_name: &str, prop_name: &str, func_name: &str, - opt_no_fonts: bool, - opt_no_images: bool, - opt_silent: bool, ) -> Result> { let mut result: String = str!(); @@ -91,7 +90,7 @@ pub fn process_css<'a>( Token::Colon => result.push_str(":"), Token::Comma => result.push_str(","), Token::ParenthesisBlock | Token::SquareBracketBlock | Token::CurlyBracketBlock => { - if opt_no_fonts && curr_rule == "font-face" { + if options.no_fonts && curr_rule == "font-face" { continue; } @@ -114,12 +113,10 @@ pub fn process_css<'a>( client, parent_url, parser, + options, rule_name, curr_prop.as_str(), func_name, - opt_no_fonts, - opt_no_images, - opt_silent, ) }) .unwrap(); @@ -149,7 +146,7 @@ pub fn process_css<'a>( // @import, @font-face, @charset, @media... Token::AtKeyword(ref value) => { curr_rule = str!(value); - if opt_no_fonts && curr_rule == "font-face" { + if options.no_fonts && curr_rule == "font-face" { continue; } result.push_str("@"); @@ -172,7 +169,13 @@ pub fn process_css<'a>( let import_full_url = resolve_url(&parent_url, value).unwrap_or_default(); let import_url_fragment = get_url_fragment(import_full_url.clone()); - match retrieve_asset(cache, client, &parent_url, &import_full_url, opt_silent) { + match retrieve_asset( + cache, + client, + &parent_url, + &import_full_url, + options.silent, + ) { Ok((import_contents, import_final_url, _import_media_type)) => { let import_data_url = data_to_data_url( "text/css", @@ -181,9 +184,7 @@ pub fn process_css<'a>( client, &import_final_url, &String::from_utf8_lossy(&import_contents), - opt_no_fonts, - opt_no_images, - opt_silent, + options, ) .as_bytes(), &import_final_url, @@ -212,7 +213,7 @@ pub fn process_css<'a>( continue; } - if opt_no_images && is_image_url_prop(curr_prop.as_str()) { + if options.no_images && is_image_url_prop(curr_prop.as_str()) { result.push_str(enquote(str!(empty_image!()), false).as_str()); } else { let resolved_url = resolve_url(&parent_url, value).unwrap_or_default(); @@ -222,7 +223,7 @@ pub fn process_css<'a>( client, &parent_url, &resolved_url, - opt_silent, + options.silent, ) { Ok((data, final_url, media_type)) => { let data_url = data_to_data_url(&media_type, &data, &final_url); @@ -265,7 +266,7 @@ pub fn process_css<'a>( if *has_sign && *unit_value >= 0. { result.push_str("+"); } - result.push_str(str!(unit_value * 100.).as_str()); + result.push_str(str!(unit_value * 100.0).as_str()); result.push_str("%"); } Token::Dimension { @@ -309,7 +310,7 @@ pub fn process_css<'a>( if is_import { let full_url = resolve_url(&parent_url, value).unwrap_or_default(); let url_fragment = get_url_fragment(full_url.clone()); - match retrieve_asset(cache, client, &parent_url, &full_url, opt_silent) { + match retrieve_asset(cache, client, &parent_url, &full_url, options.silent) { Ok((css, final_url, _media_type)) => { let data_url = data_to_data_url( "text/css", @@ -318,9 +319,7 @@ pub fn process_css<'a>( client, &final_url, &String::from_utf8_lossy(&css), - opt_no_fonts, - opt_no_images, - opt_silent, + options, ) .as_bytes(), &final_url, @@ -339,12 +338,13 @@ pub fn process_css<'a>( } } } else { - if opt_no_images && is_image_url_prop(curr_prop.as_str()) { + if options.no_images && is_image_url_prop(curr_prop.as_str()) { result.push_str(enquote(str!(empty_image!()), false).as_str()); } else { let full_url = resolve_url(&parent_url, value).unwrap_or_default(); let url_fragment = get_url_fragment(full_url.clone()); - match retrieve_asset(cache, client, &parent_url, &full_url, opt_silent) { + match retrieve_asset(cache, client, &parent_url, &full_url, options.silent) + { Ok((data, final_url, media_type)) => { let data_url = data_to_data_url(&media_type, &data, &final_url); let assembled_url: String = @@ -377,12 +377,10 @@ pub fn process_css<'a>( client, parent_url, parser, + options, curr_rule.as_str(), curr_prop.as_str(), function_name, - opt_no_fonts, - opt_no_images, - opt_silent, ) }) .unwrap(); @@ -407,24 +405,10 @@ pub fn embed_css( client: &Client, parent_url: &str, css: &str, - opt_no_fonts: bool, - opt_no_images: bool, - opt_silent: bool, + options: &Options, ) -> String { let mut input = ParserInput::new(&css); let mut parser = Parser::new(&mut input); - process_css( - cache, - client, - parent_url, - &mut parser, - "", - "", - "", - opt_no_fonts, - opt_no_images, - opt_silent, - ) - .unwrap() + process_css(cache, client, parent_url, &mut parser, options, "", "", "").unwrap() } diff --git a/src/html.rs b/src/html.rs index 3ae3e2d..034bc97 100644 --- a/src/html.rs +++ b/src/html.rs @@ -15,6 +15,7 @@ use std::default::Default; use crate::css::embed_css; use crate::js::attr_is_event_handler; +use crate::opts::Options; use crate::url::{ data_to_data_url, get_url_fragment, is_http_url, resolve_url, url_has_protocol, url_with_fragment, @@ -73,8 +74,7 @@ pub fn embed_srcset( client: &Client, parent_url: &str, srcset: &str, - opt_no_images: bool, - opt_silent: bool, + options: &Options, ) -> String { let mut array: Vec = vec![]; let srcset_items: Vec<&str> = srcset.split(',').collect(); @@ -89,12 +89,12 @@ pub fn embed_srcset( let mut result: String = str!(); let mut i: usize = array.len(); for part in array { - if opt_no_images { + if options.no_images { result.push_str(empty_image!()); } else { let image_full_url = resolve_url(&parent_url, part.path).unwrap_or_default(); let image_url_fragment = get_url_fragment(image_full_url.clone()); - match retrieve_asset(cache, client, &parent_url, &image_full_url, opt_silent) { + match retrieve_asset(cache, client, &parent_url, &image_full_url, options.silent) { Ok((image_data, image_final_url, image_media_type)) => { let image_data_url = data_to_data_url(&image_media_type, &image_data, &image_final_url); @@ -137,29 +137,13 @@ pub fn walk_and_embed_assets( client: &Client, url: &str, node: &Handle, - opt_no_css: bool, - opt_no_fonts: bool, - opt_no_frames: bool, - opt_no_js: bool, - opt_no_images: bool, - opt_silent: bool, + options: &Options, ) { match node.data { NodeData::Document => { // Dig deeper for child in node.children.borrow().iter() { - walk_and_embed_assets( - cache, - client, - &url, - child, - opt_no_css, - opt_no_fonts, - opt_no_frames, - opt_no_js, - opt_no_images, - opt_silent, - ); + walk_and_embed_assets(cache, client, &url, child, options); } } NodeData::Element { @@ -245,7 +229,7 @@ pub fn walk_and_embed_assets( } } - if !opt_no_images && !link_href.is_empty() { + if !options.no_images && !link_href.is_empty() { let link_href_full_url = resolve_url(&url, link_href).unwrap_or_default(); let link_href_url_fragment = @@ -255,7 +239,7 @@ pub fn walk_and_embed_assets( client, &url, &link_href_full_url, - opt_silent, + options.silent, ) { Ok(( link_href_data, @@ -319,7 +303,7 @@ pub fn walk_and_embed_assets( } } - if !opt_no_css && !link_href.is_empty() { + if !options.no_css && !link_href.is_empty() { let link_href_full_url = resolve_url(&url, link_href).unwrap_or_default(); match retrieve_asset( @@ -327,7 +311,7 @@ pub fn walk_and_embed_assets( client, &url, &link_href_full_url, - opt_silent, + options.silent, ) { Ok(( link_href_data, @@ -343,9 +327,7 @@ pub fn walk_and_embed_assets( client, &link_href_final_url, &String::from_utf8_lossy(&link_href_data), - opt_no_fonts, - opt_no_images, - opt_silent, + options, ); let link_href_data_url = data_to_data_url( "text/css", @@ -415,11 +397,16 @@ pub fn walk_and_embed_assets( } } - if !opt_no_images && !background.is_empty() { + if !options.no_images && !background.is_empty() { let background_full_url = resolve_url(&url, background).unwrap_or_default(); let background_url_fragment = get_url_fragment(background_full_url.clone()); - match retrieve_asset(cache, client, &url, &background_full_url, opt_silent) - { + match retrieve_asset( + cache, + client, + &url, + &background_full_url, + options.silent, + ) { Ok((background_data, background_final_url, background_media_type)) => { let background_data_url = data_to_data_url( &background_media_type, @@ -471,7 +458,7 @@ pub fn walk_and_embed_assets( } } - if opt_no_images { + if options.no_images { // Add empty image src attribute attrs_mut.push(Attribute { name: QualName::new(None, ns!(), local_name!("src")), @@ -496,7 +483,8 @@ pub fn walk_and_embed_assets( ) .unwrap_or_default(); let img_url_fragment = get_url_fragment(img_full_url.clone()); - match retrieve_asset(cache, client, &url, &img_full_url, opt_silent) { + match retrieve_asset(cache, client, &url, &img_full_url, options.silent) + { Ok((img_data, img_final_url, img_media_type)) => { let img_data_url = data_to_data_url( &img_media_type, @@ -533,21 +521,13 @@ pub fn walk_and_embed_assets( attrs_mut.push(Attribute { name: QualName::new(None, ns!(), local_name!("srcset")), value: Tendril::from_slice( - embed_srcset( - cache, - client, - &url, - &img_srcset, - opt_no_images, - opt_silent, - ) - .as_ref(), + embed_srcset(cache, client, &url, &img_srcset, options).as_ref(), ), }); } } "svg" => { - if opt_no_images { + if options.no_images { node.children.borrow_mut().clear(); } } @@ -573,7 +553,7 @@ pub fn walk_and_embed_assets( } } - if opt_no_images || input_image_src.is_empty() { + if options.no_images || input_image_src.is_empty() { attrs_mut.push(Attribute { name: QualName::new(None, ns!(), local_name!("src")), value: Tendril::from_slice(if input_image_src.is_empty() { @@ -592,7 +572,7 @@ pub fn walk_and_embed_assets( client, &url, &input_image_full_url, - opt_silent, + options.silent, ) { Ok(( input_image_data, @@ -646,10 +626,10 @@ pub fn walk_and_embed_assets( } } - if !opt_no_images && !image_href.is_empty() { + if !options.no_images && !image_href.is_empty() { let image_full_url = resolve_url(&url, image_href).unwrap_or_default(); let image_url_fragment = get_url_fragment(image_full_url.clone()); - match retrieve_asset(cache, client, &url, &image_full_url, opt_silent) { + match retrieve_asset(cache, client, &url, &image_full_url, options.silent) { Ok((image_data, image_final_url, image_media_type)) => { let image_data_url = data_to_data_url( &image_media_type, @@ -693,7 +673,7 @@ pub fn walk_and_embed_assets( attr.value.push_slice(src_full_url.as_str()); } else if attr_name.eq_ignore_ascii_case("srcset") { if get_node_name(&get_parent_node(&node)) == Some("picture") { - if opt_no_images { + if options.no_images { attr.value.clear(); attr.value.push_slice(empty_image!()); } else { @@ -706,7 +686,7 @@ pub fn walk_and_embed_assets( client, &url, &srcset_full_url, - opt_silent, + options.silent, ) { Ok((srcset_data, srcset_final_url, srcset_media_type)) => { let srcset_data_url = data_to_data_url( @@ -744,7 +724,7 @@ pub fn walk_and_embed_assets( if attr_name.eq_ignore_ascii_case("href") { let attr_value = attr.value.trim(); - if opt_no_js && attr_value.starts_with("javascript:") { + if options.no_js && attr_value.trim().starts_with("javascript:") { attr.value.clear(); // Replace with empty JS call to preserve original behavior attr.value.push_slice("javascript:;"); @@ -778,12 +758,13 @@ pub fn walk_and_embed_assets( } } - if opt_no_js { + if options.no_js { // Empty inner content (src is already gone) node.children.borrow_mut().clear(); } else if !script_src.is_empty() { let script_full_url = resolve_url(&url, script_src).unwrap_or_default(); - match retrieve_asset(cache, client, &url, &script_full_url, opt_silent) { + match retrieve_asset(cache, client, &url, &script_full_url, options.silent) + { Ok((script_data, script_final_url, _script_media_type)) => { // Only embed if we're able to validate integrity if script_integrity.is_empty() @@ -814,22 +795,15 @@ pub fn walk_and_embed_assets( } } "style" => { - if opt_no_css { + if options.no_css { // Empty inner content of STYLE tags node.children.borrow_mut().clear(); } else { for node in node.children.borrow_mut().iter_mut() { if let NodeData::Text { ref contents } = node.data { let mut tendril = contents.borrow_mut(); - let replacement = embed_css( - cache, - client, - &url, - tendril.as_ref(), - opt_no_fonts, - opt_no_images, - opt_silent, - ); + let replacement = + embed_css(cache, client, &url, tendril.as_ref(), options); tendril.clear(); tendril.push_slice(&replacement); } @@ -855,7 +829,7 @@ pub fn walk_and_embed_assets( for attr in attrs_mut.iter_mut() { let attr_name: &str = &attr.name.local; if attr_name.eq_ignore_ascii_case("src") { - if opt_no_frames { + if options.no_frames { // Empty the src attribute attr.value.clear(); continue; @@ -870,7 +844,13 @@ pub fn walk_and_embed_assets( let frame_full_url = resolve_url(&url, frame_src).unwrap_or_default(); let frame_url_fragment = get_url_fragment(frame_full_url.clone()); - match retrieve_asset(cache, client, &url, &frame_full_url, opt_silent) { + match retrieve_asset( + cache, + client, + &url, + &frame_full_url, + options.silent, + ) { Ok((frame_data, frame_final_url, frame_media_type)) => { let frame_dom = html_to_dom(&String::from_utf8_lossy(&frame_data)); @@ -879,12 +859,7 @@ pub fn walk_and_embed_assets( client, &frame_final_url, &frame_dom.document, - opt_no_css, - opt_no_fonts, - opt_no_frames, - opt_no_js, - opt_no_images, - opt_silent, + &options, ); let mut frame_data: Vec = Vec::new(); serialize( @@ -931,7 +906,7 @@ pub fn walk_and_embed_assets( continue; } - if opt_no_images { + if options.no_images { attr.value.clear(); continue; } @@ -945,7 +920,7 @@ pub fn walk_and_embed_assets( client, &url, &video_poster_full_url, - opt_silent, + options.silent, ) { Ok(( video_poster_data, @@ -983,7 +958,7 @@ pub fn walk_and_embed_assets( } // Process style attributes - if opt_no_css { + if options.no_css { // Get rid of style attributes let mut i = 0; while i < attrs_mut.len() { @@ -1000,22 +975,15 @@ pub fn walk_and_embed_assets( .iter_mut() .filter(|a| a.name.local.as_ref().eq_ignore_ascii_case("style")) { - let replacement = embed_css( - cache, - client, - &url, - attribute.value.as_ref(), - opt_no_fonts, - opt_no_images, - opt_silent, - ); + let replacement = + embed_css(cache, client, &url, attribute.value.as_ref(), options); // let replacement = str!(); attribute.value.clear(); attribute.value.push_slice(&replacement); } } - if opt_no_js { + if options.no_js { // Get rid of JS event attributes let mut js_attr_indexes = Vec::new(); for (i, attr) in attrs_mut.iter_mut().enumerate() { @@ -1031,22 +999,11 @@ pub fn walk_and_embed_assets( // Dig deeper for child in node.children.borrow().iter() { - walk_and_embed_assets( - cache, - client, - &url, - child, - opt_no_css, - opt_no_fonts, - opt_no_frames, - opt_no_js, - opt_no_images, - opt_silent, - ); + walk_and_embed_assets(cache, client, &url, child, options); } } _ => { - // Note: in case of opt_no_js being set to true, there's no need to worry about + // Note: in case of options.no_js being set to true, there's no need to worry about // getting rid of comments that may contain scripts, e.g.