Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use crate::css::{embed_css, embed_stylesheet};
use crate::js::{attr_is_event_handler, escape_script_end_tag};
use crate::session::Session;
use crate::url::{
EMPTY_IMAGE_DATA_URL, Url, clean_url, create_data_url, is_url_and_has_protocol, resolve_url,
EMPTY_IMAGE_DATA_URL, Url, clean_url, create_data_url, create_srcset_data_url,
is_url_and_has_protocol, resolve_url,
};

const FAVICON_VALUES: &[&str] = &["icon", "shortcut icon"];
Expand Down Expand Up @@ -160,7 +161,7 @@ pub fn embed_srcset(session: &mut Session, document_url: &Url, srcset: &str) ->
Ok((image_data, image_final_url, image_media_type, image_charset)) => {
if session.options.output_format == MonolithOutputFormat::HTML {
// Append retrieved asset as a data URL
result.push_str(&create_data_url(
result.push_str(&create_srcset_data_url(
&image_media_type,
&image_charset,
image_data,
Expand Down
39 changes: 36 additions & 3 deletions src/url.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt::Write;

use dataurl::{DataEncoding, DataUrl};
use dataurl::{DataEncoding, DataUrl, Escaping};
pub use url::Url;

use crate::core::detect_media_type;
Expand All @@ -19,15 +19,45 @@ pub fn clean_url(url: Url) -> Url {

/// Creates a data URL for an asset, with an optional fragment (already percent-encoded, as Url::fragment() returns it).
/// Passing data as a Vec<u8> moves it in without copying.
///
/// The data gets percent-encoded or base64-encoded, whichever is shorter, and percent-encoding only escapes
/// what has to be, which keeps text assets like SVG and CSS small and readable. That's only safe inside
/// double-quoted HTML attributes and CSS strings, which is where monolith puts data URLs; srcset is the exception,
/// see create_srcset_data_url().
pub fn create_data_url(
media_type: &str,
charset: &str,
data: impl Into<Vec<u8>>,
final_asset_url: &Url,
fragment: Option<&str>,
) -> String {
let data: Vec<u8> = data.into();
let mut data_url = new_data_url(media_type, charset, data.into(), final_asset_url, fragment);
data_url.set_data_encoding(DataEncoding::Shortest);
data_url.set_escaping(Escaping::Minimal);
serialize_data_url(&data_url)
}

/// Same as create_data_url(), but always uses base64, since srcset gets split on whitespace
/// and has trailing commas removed from URLs, which percent-encoded data could contain.
pub fn create_srcset_data_url(
media_type: &str,
charset: &str,
data: impl Into<Vec<u8>>,
final_asset_url: &Url,
fragment: Option<&str>,
) -> String {
let mut data_url = new_data_url(media_type, charset, data.into(), final_asset_url, fragment);
data_url.set_data_encoding(DataEncoding::Base64);
serialize_data_url(&data_url)
}

fn new_data_url(
media_type: &str,
charset: &str,
data: Vec<u8>,
final_asset_url: &Url,
fragment: Option<&str>,
) -> DataUrl {
// TODO: move this block out of this function
let media_type: String = if media_type.is_empty() {
detect_media_type(&data, final_asset_url)
Expand All @@ -36,7 +66,6 @@ pub fn create_data_url(
};

let mut data_url = DataUrl::new();
data_url.set_data_encoding(DataEncoding::Base64);
data_url.set_data(data);
data_url.set_fragment(fragment);

Expand All @@ -52,6 +81,10 @@ pub fn create_data_url(
let _ = data_url.set_parameter("charset", Some(charset));
}

data_url
}

fn serialize_data_url(data_url: &DataUrl) -> String {
// Allocating the exact size upfront avoids reallocations (and copies) while the string grows
let mut result = String::with_capacity(data_url.encoded_len());
write!(result, "{data_url}").unwrap();
Expand Down
6 changes: 3 additions & 3 deletions tests/cli/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,11 @@ mod passing {

@charset "UTF-8";

@import "data:text/css;charset=utf-8;base64,Ym9keXtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn0K";
@import "data:text/css;charset=utf-8,body{background-color:%23000;color:%23fff}%0A";

@import url("data:text/css;charset=utf-8;base64,Ym9keXtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn0K");
@import url("data:text/css;charset=utf-8,body{background-color:%23000;color:%23fff}%0A");

@import url("data:text/css;charset=utf-8;base64,Ym9keXtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn0K");
@import url("data:text/css;charset=utf-8,body{background-color:%23000;color:%23fff}%0A");

</style>
<meta name="robots" content="none"></head><body></body></html>
Expand Down
8 changes: 4 additions & 4 deletions tests/cli/local_files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ mod passing {
r##"<!DOCTYPE html><html lang="en"><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Local HTML file</title>
<link href="data:text/css;charset=utf-8;base64,Ym9keSB7CiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjMDAwOwogICAgY29sb3I6ICNmZmY7Cn0K" rel="stylesheet" type="text/css">
<link href="data:text/css;charset=utf-8,body {%0A background-color: %23000;%0A color: %23fff;%0A}%0A" rel="stylesheet" type="text/css">
<link rel="stylesheet" type="text/css">
<meta name="robots" content="none"></head>

Expand Down Expand Up @@ -209,7 +209,7 @@ document.body.style.color = "red";
// STDOUT should contain HTML with date URL for background-image in it
assert_eq!(
String::from_utf8_lossy(&out.stdout),
r##"<html><head><meta name="robots" content="none"></head><body><div style="background-image: url(&quot;data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGJhc2VQcm9maWxlPSJmdWxsIiB3aWR0aD0iMzAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InJlZCIgLz4KICAgIDxjaXJjbGUgY3g9IjE1MCIgY3k9IjEwMCIgcj0iODAiIGZpbGw9ImdyZWVuIiAvPgogICAgPHRleHQgeD0iMTUwIiB5PSIxMjUiIGZvbnQtc2l6ZT0iNjAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IndoaXRlIj5TVkc8L3RleHQ+Cjwvc3ZnPgo=&quot;)"></div>
r##"<html><head><meta name="robots" content="none"></head><body><div style="background-image: url(&quot;data:image/svg+xml,%3Csvg version=%221.1%22 baseProfile=%22full%22 width=%22300%22 height=%22200%22 xmlns=%22http://www.w3.org/2000/svg%22%3E%0A %3Crect width=%22100%25%22 height=%22100%25%22 fill=%22red%22 /%3E%0A %3Ccircle cx=%22150%22 cy=%22100%22 r=%2280%22 fill=%22green%22 /%3E%0A %3Ctext x=%22150%22 y=%22125%22 font-size=%2260%22 text-anchor=%22middle%22 fill=%22white%22%3ESVG%3C/text%3E%0A%3C/svg%3E%0A&quot;)"></div>
</body></html>
"##
);
Expand Down Expand Up @@ -333,7 +333,7 @@ document.body.style.color = "red";
String::from_utf8_lossy(&out.stdout),
r##"<html><head><meta name="robots" content="none"></head><body>
<svg height="24" width="24">
<image href="data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGJhc2VQcm9maWxlPSJmdWxsIiB3aWR0aD0iMzAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InJlZCIgLz4KICAgIDxjaXJjbGUgY3g9IjE1MCIgY3k9IjEwMCIgcj0iODAiIGZpbGw9ImdyZWVuIiAvPgogICAgPHRleHQgeD0iMTUwIiB5PSIxMjUiIGZvbnQtc2l6ZT0iNjAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IndoaXRlIj5TVkc8L3RleHQ+Cjwvc3ZnPgo=" width="24" height="24">
<image href="data:image/svg+xml,%3Csvg version=%221.1%22 baseProfile=%22full%22 width=%22300%22 height=%22200%22 xmlns=%22http://www.w3.org/2000/svg%22%3E%0A %3Crect width=%22100%25%22 height=%22100%25%22 fill=%22red%22 /%3E%0A %3Ccircle cx=%22150%22 cy=%22100%22 r=%2280%22 fill=%22green%22 /%3E%0A %3Ctext x=%22150%22 y=%22125%22 font-size=%2260%22 text-anchor=%22middle%22 fill=%22white%22%3ESVG%3C/text%3E%0A%3C/svg%3E%0A" width="24" height="24">
</image></svg>
"##.to_owned() + r##"

Expand Down Expand Up @@ -393,7 +393,7 @@ document.body.style.color = "red";
String::from_utf8_lossy(&out.stdout),
r##"<!DOCTYPE html><html lang="en"><head><meta http-equiv="Content-Security-Policy" content="img-src data:;">
<title>Local HTML file</title>
<link href="data:text/css;charset=utf-8;base64,Ym9keSB7CiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjMDAwOwogICAgY29sb3I6ICNGRkY7Cn0K" rel="stylesheet" type="text/css" crossorigin="anonymous">
<link href="data:text/css;charset=utf-8,body {%0A background-color: %23000;%0A color: %23FFF;%0A}%0A" rel="stylesheet" type="text/css" crossorigin="anonymous">
<link href="style.css" rel="stylesheet" type="text/css" crossorigin="anonymous">
<meta name="robots" content="none"></head>

Expand Down
8 changes: 4 additions & 4 deletions tests/cli/noscript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ mod passing {
// STDOUT should contain HTML with no CSS
assert_eq!(
String::from_utf8_lossy(&out.stdout),
"<html><head><meta name=\"robots\" content=\"none\"></head><body><noscript><img src=\"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGJhc2VQcm9maWxlPSJmdWxsIiB3aWR0aD0iMzAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InJlZCIgLz4KICAgIDxjaXJjbGUgY3g9IjE1MCIgY3k9IjEwMCIgcj0iODAiIGZpbGw9ImdyZWVuIiAvPgogICAgPHRleHQgeD0iMTUwIiB5PSIxMjUiIGZvbnQtc2l6ZT0iNjAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IndoaXRlIj5TVkc8L3RleHQ+Cjwvc3ZnPgo=\"></noscript>\n</body></html>\n"
"<html><head><meta name=\"robots\" content=\"none\"></head><body><noscript><img src=\"data:image/svg+xml,%3Csvg version=%221.1%22 baseProfile=%22full%22 width=%22300%22 height=%22200%22 xmlns=%22http://www.w3.org/2000/svg%22%3E%0A %3Crect width=%22100%25%22 height=%22100%25%22 fill=%22red%22 /%3E%0A %3Ccircle cx=%22150%22 cy=%22100%22 r=%2280%22 fill=%22green%22 /%3E%0A %3Ctext x=%22150%22 y=%22125%22 font-size=%2260%22 text-anchor=%22middle%22 fill=%22white%22%3ESVG%3C/text%3E%0A%3C/svg%3E%0A\"></noscript>\n</body></html>\n"
);

// Exit code should be 0
Expand Down Expand Up @@ -69,7 +69,7 @@ mod passing {
// STDOUT should contain HTML with no CSS
assert_eq!(
String::from_utf8_lossy(&out.stdout),
"<html><head><meta name=\"robots\" content=\"none\"></head><body><img src=\"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGJhc2VQcm9maWxlPSJmdWxsIiB3aWR0aD0iMzAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InJlZCIgLz4KICAgIDxjaXJjbGUgY3g9IjE1MCIgY3k9IjEwMCIgcj0iODAiIGZpbGw9ImdyZWVuIiAvPgogICAgPHRleHQgeD0iMTUwIiB5PSIxMjUiIGZvbnQtc2l6ZT0iNjAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IndoaXRlIj5TVkc8L3RleHQ+Cjwvc3ZnPgo=\">\n</body></html>\n"
"<html><head><meta name=\"robots\" content=\"none\"></head><body><img src=\"data:image/svg+xml,%3Csvg version=%221.1%22 baseProfile=%22full%22 width=%22300%22 height=%22200%22 xmlns=%22http://www.w3.org/2000/svg%22%3E%0A %3Crect width=%22100%25%22 height=%22100%25%22 fill=%22red%22 /%3E%0A %3Ccircle cx=%22150%22 cy=%22100%22 r=%2280%22 fill=%22green%22 /%3E%0A %3Ctext x=%22150%22 y=%22125%22 font-size=%2260%22 text-anchor=%22middle%22 fill=%22white%22%3ESVG%3C/text%3E%0A%3C/svg%3E%0A\">\n</body></html>\n"
);

// Exit code should be 0
Expand Down Expand Up @@ -100,7 +100,7 @@ mod passing {
// STDOUT should contain HTML with no CSS
assert_eq!(
String::from_utf8_lossy(&out.stdout),
"<html><head><meta name=\"robots\" content=\"none\"></head><body><h1>JS is not active</h1><img src=\"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGJhc2VQcm9maWxlPSJmdWxsIiB3aWR0aD0iMzAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InJlZCIgLz4KICAgIDxjaXJjbGUgY3g9IjE1MCIgY3k9IjEwMCIgcj0iODAiIGZpbGw9ImdyZWVuIiAvPgogICAgPHRleHQgeD0iMTUwIiB5PSIxMjUiIGZvbnQtc2l6ZT0iNjAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IndoaXRlIj5TVkc8L3RleHQ+Cjwvc3ZnPgo=\">\n</body></html>\n"
"<html><head><meta name=\"robots\" content=\"none\"></head><body><h1>JS is not active</h1><img src=\"data:image/svg+xml,%3Csvg version=%221.1%22 baseProfile=%22full%22 width=%22300%22 height=%22200%22 xmlns=%22http://www.w3.org/2000/svg%22%3E%0A %3Crect width=%22100%25%22 height=%22100%25%22 fill=%22red%22 /%3E%0A %3Ccircle cx=%22150%22 cy=%22100%22 r=%2280%22 fill=%22green%22 /%3E%0A %3Ctext x=%22150%22 y=%22125%22 font-size=%2260%22 text-anchor=%22middle%22 fill=%22white%22%3ESVG%3C/text%3E%0A%3C/svg%3E%0A\">\n</body></html>\n"
);

// Exit code should be 0
Expand Down Expand Up @@ -131,7 +131,7 @@ mod passing {
// STDOUT should contain HTML with no CSS
assert_eq!(
String::from_utf8_lossy(&out.stdout),
r#"<html><head><meta name="robots" content="none"></head><body><script>alert(1);</script><img src="data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGJhc2VQcm9maWxlPSJmdWxsIiB3aWR0aD0iMzAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InJlZCIgLz4KICAgIDxjaXJjbGUgY3g9IjE1MCIgY3k9IjEwMCIgcj0iODAiIGZpbGw9ImdyZWVuIiAvPgogICAgPHRleHQgeD0iMTUwIiB5PSIxMjUiIGZvbnQtc2l6ZT0iNjAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IndoaXRlIj5TVkc8L3RleHQ+Cjwvc3ZnPgo=">
r#"<html><head><meta name="robots" content="none"></head><body><script>alert(1);</script><img src="data:image/svg+xml,%3Csvg version=%221.1%22 baseProfile=%22full%22 width=%22300%22 height=%22200%22 xmlns=%22http://www.w3.org/2000/svg%22%3E%0A %3Crect width=%22100%25%22 height=%22100%25%22 fill=%22red%22 /%3E%0A %3Ccircle cx=%22150%22 cy=%22100%22 r=%2280%22 fill=%22green%22 /%3E%0A %3Ctext x=%22150%22 y=%22125%22 font-size=%2260%22 text-anchor=%22middle%22 fill=%22white%22%3ESVG%3C/text%3E%0A%3C/svg%3E%0A">
</body></html>
"#
);
Expand Down
15 changes: 11 additions & 4 deletions tests/css/embed_css.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,14 @@ mod passing {
("", "p::before{content:'café'}".as_bytes()),
("", b"p::before{content:'caf\xe9'}".as_slice()),
] {
let asset = monolith::url::create_data_url("text/css", charset, bytes, &url, None);
// Base64, which can go anywhere in CSS, including the unquoted url() below
let mut asset = dataurl::DataUrl::new();
asset.set_media_type(Some("text/css")).unwrap();
if !charset.is_empty() {
asset.set_parameter("charset", Some(charset)).unwrap();
}
asset.set_data_encoding(dataurl::DataEncoding::Base64);
asset.set_data(bytes);

for source in [
format!("@import \"{}\";", asset),
Expand Down Expand Up @@ -298,9 +305,9 @@ mod passing {
"\
@charset \"UTF-8\";\n\
\n\
@import \"data:text/css;charset=utf-8;base64,aHRtbHtiYWNrZ3JvdW5kLWNvbG9yOiMwMDB9\";\n\
@import \"data:text/css;charset=utf-8,html{background-color:%23000}\";\n\
\n\
@import url(\"data:text/css;charset=utf-8;base64,aHRtbHtjb2xvcjojZmZmfQ==\")\n\
@import url(\"data:text/css;charset=utf-8,html{color:%23fff}\")\n\
"
);
}
Expand Down Expand Up @@ -421,7 +428,7 @@ mod passing {
";
const CSS_OUT: &str = "\
#language a[href=\"#translations\"]:before {\n\
content: url(\"data:text/plain;base64,\") \"\\a \";\n\
content: url(\"data:text/plain,\") \"\\a \";\n\
white-space: pre }\n\
";

Expand Down
4 changes: 2 additions & 2 deletions tests/session/retrieve_asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ mod passing {
assert_eq!(&charset, "");
assert_eq!(
url::create_data_url(&media_type, &charset, data, &final_url, None),
"data:text/html;base64,dGFyZ2V0",
"data:text/html,target",
);
assert_eq!(
final_url,
Expand Down Expand Up @@ -70,7 +70,7 @@ mod passing {
.unwrap();
assert_eq!(&media_type, "text/javascript");
assert_eq!(&charset, "");
let data_url = "data:text/javascript;base64,ZG9jdW1lbnQuYm9keS5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSAiZ3JlZW4iOwpkb2N1bWVudC5ib2R5LnN0eWxlLmNvbG9yID0gInJlZCI7Cg==";
let data_url = "data:text/javascript,document.body.style.backgroundColor = %22green%22;%0Adocument.body.style.color = %22red%22;%0A";
assert_eq!(
url::create_data_url(&media_type, &charset, data, &final_url, None),
data_url
Expand Down
50 changes: 38 additions & 12 deletions tests/url/create_data_url.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ mod passing {

assert_eq!(
data_url.as_str(),
"data:application/javascript;base64,dmFyIHdvcmQgPSAnaGVsbG8nOwphbGVydCh3b3JkKTsK"
"data:application/javascript,var word = 'hello';%0Aalert(word);%0A"
);
}

Expand All @@ -42,7 +42,7 @@ mod passing {

assert_eq!(
data_url.as_str(),
"data:image/svg+xml;base64,PHN2Zz48L3N2Zz4K"
"data:image/svg+xml,%3Csvg%3E%3C/svg%3E%0A"
);
}

Expand All @@ -61,7 +61,7 @@ mod passing {

assert_eq!(
data_url.as_str(),
"data:application/javascript;charset=utf8;base64,dmFyIHdvcmQgPSAnaGVsbG8nOwphbGVydCh3b3JkKTsK"
"data:application/javascript;charset=utf8,var word = 'hello';%0Aalert(word);%0A"
);
}

Expand All @@ -78,7 +78,7 @@ mod passing {
None,
);

assert_eq!(data_url.as_str(), "data:;base64,");
assert_eq!(data_url.as_str(), "data:,");
}

#[test]
Expand All @@ -94,7 +94,7 @@ mod passing {
None,
);

assert_eq!(data_url.as_str(), "data:;charset=utf8;base64,");
assert_eq!(data_url.as_str(), "data:;charset=utf8,");
}

#[test]
Expand All @@ -110,7 +110,7 @@ mod passing {
None,
);

assert_eq!(data_url.as_str(), "data:text/plain;charset=utf8;base64,");
assert_eq!(data_url.as_str(), "data:text/plain;charset=utf8,");
}

#[test]
Expand All @@ -135,7 +135,7 @@ mod passing {
let data_url =
url::create_data_url("Image/PNG", "", b"", &Url::parse("data:,").unwrap(), None);

assert_eq!(data_url.as_str(), "data:image/png;base64,");
assert_eq!(data_url.as_str(), "data:image/png,");
}

#[test]
Expand All @@ -148,14 +148,14 @@ mod passing {
None,
);

assert_eq!(data_url.as_str(), "data:text/css;charset=utf-8;base64,");
assert_eq!(data_url.as_str(), "data:text/css;charset=utf-8,");
}

#[test]
fn create_data_url_omits_invalid_media_type() {
let data_url = url::create_data_url("wrong", "", b"", &Url::parse("data:,").unwrap(), None);

assert_eq!(data_url.as_str(), "data:;base64,");
assert_eq!(data_url.as_str(), "data:,");
}

#[test]
Expand All @@ -168,7 +168,7 @@ mod passing {
None,
);

assert_eq!(data_url.as_str(), "data:text/css;base64,");
assert_eq!(data_url.as_str(), "data:text/css,");
}

#[test]
Expand All @@ -182,7 +182,7 @@ mod passing {
asset_url.fragment(),
);

assert_eq!(data_url, "data:image/svg+xml;base64,PHN2Zy8+#a%20b");
assert_eq!(data_url, "data:image/svg+xml,%3Csvg/%3E#a%20b");
}

#[test]
Expand All @@ -195,10 +195,36 @@ mod passing {
&Url::parse("data:,").unwrap(),
Some(fragment),
);
let mut expected = Url::parse("data:text/plain;base64,eA==").unwrap();
let mut expected = Url::parse("data:text/plain,x").unwrap();
expected.set_fragment(Some(fragment));

assert_eq!(data_url, expected.as_str(), "{fragment:?}");
}
}

#[test]
fn create_data_url_uses_base64_when_shorter() {
let data_url = url::create_data_url(
"image/png",
"",
[0u8; 16],
&Url::parse("data:,").unwrap(),
None,
);

assert_eq!(data_url, "data:image/png;base64,AAAAAAAAAAAAAAAAAAAAAA==");
}

#[test]
fn create_srcset_data_url_always_uses_base64() {
let data_url = url::create_srcset_data_url(
"image/svg+xml",
"",
b"<svg/>",
&Url::parse("data:,").unwrap(),
Some("a"),
);

assert_eq!(data_url, "data:image/svg+xml;base64,PHN2Zy8+#a");
}
}
Loading