simplify code responsible for processing CSS

pull/256/head
Sunshine 3 years ago
parent 8256d17efd
commit a6ddf1c13a
No known key found for this signature in database
GPG Key ID: B80CA68703CD8AB1

@ -6,7 +6,7 @@ use std::collections::HashMap;
use url::Url;
use crate::opts::Options;
use crate::url::{data_to_data_url, resolve_url};
use crate::url::{create_data_url, resolve_url};
use crate::utils::retrieve_asset;
const CSS_PROPS_WITH_IMAGE_URLS: &[&str] = &[
@ -55,14 +55,6 @@ pub fn embed_css(
.unwrap()
}
pub fn enquote(input: String, double: bool) -> String {
if double {
format!("\"{}\"", input.replace("\"", "\\\""))
} else {
format!("'{}'", input.replace("'", "\\'"))
}
}
pub fn format_ident(ident: &str) -> String {
let mut res: String = String::new();
let _ = serialize_identifier(ident, &mut res);
@ -206,7 +198,7 @@ pub fn process_css<'a>(
depth + 1,
) {
Ok((import_contents, import_final_url, _import_media_type)) => {
let mut import_data_url = data_to_data_url(
let mut import_data_url = create_data_url(
"text/css",
embed_css(
cache,
@ -220,15 +212,18 @@ pub fn process_css<'a>(
&import_final_url,
);
import_data_url.set_fragment(import_full_url.fragment());
result.push_str(enquote(import_data_url.to_string(), false).as_str());
result.push_str(
format_quoted_string(&import_data_url.to_string()).as_str(),
);
}
Err(_) => {
// Keep remote reference if unable to retrieve the asset
if import_full_url.scheme() == "http"
|| import_full_url.scheme() == "https"
{
result
.push_str(enquote(import_full_url.to_string(), false).as_str());
result.push_str(
format_quoted_string(&import_full_url.to_string()).as_str(),
);
}
}
}
@ -240,7 +235,7 @@ pub fn process_css<'a>(
}
if options.no_images && is_image_url_prop(curr_prop.as_str()) {
result.push_str(enquote(str!(empty_image!()), false).as_str());
result.push_str(format_quoted_string(empty_image!()).as_str());
} else {
let resolved_url: Url = resolve_url(&document_url, value);
match retrieve_asset(
@ -253,9 +248,11 @@ pub fn process_css<'a>(
) {
Ok((data, final_url, media_type)) => {
let mut data_url =
data_to_data_url(&media_type, &data, &final_url);
create_data_url(&media_type, &data, &final_url);
data_url.set_fragment(resolved_url.fragment());
result.push_str(enquote(data_url.to_string(), false).as_str());
result.push_str(
format_quoted_string(&data_url.to_string()).as_str(),
);
}
Err(_) => {
// Keep remote reference if unable to retrieve the asset
@ -263,7 +260,8 @@ pub fn process_css<'a>(
|| resolved_url.scheme() == "https"
{
result.push_str(
enquote(resolved_url.to_string(), false).as_str(),
format_quoted_string(&resolved_url.to_string())
.as_str(),
);
}
}
@ -345,7 +343,7 @@ pub fn process_css<'a>(
depth + 1,
) {
Ok((css, final_url, _media_type)) => {
let mut data_url = data_to_data_url(
let mut data_url = create_data_url(
"text/css",
embed_css(
cache,
@ -359,18 +357,19 @@ pub fn process_css<'a>(
&final_url,
);
data_url.set_fragment(full_url.fragment());
result.push_str(enquote(data_url.to_string(), false).as_str());
result.push_str(format_quoted_string(&data_url.to_string()).as_str());
}
Err(_) => {
// Keep remote reference if unable to retrieve the asset
if full_url.scheme() == "http" || full_url.scheme() == "https" {
result.push_str(enquote(full_url.to_string(), false).as_str());
result
.push_str(format_quoted_string(&full_url.to_string()).as_str());
}
}
}
} else {
if is_image_url_prop(curr_prop.as_str()) && options.no_images {
result.push_str(enquote(str!(empty_image!()), false).as_str());
result.push_str(format_quoted_string(empty_image!()).as_str());
} else {
let full_url: Url = resolve_url(&document_url, value);
match retrieve_asset(
@ -382,14 +381,17 @@ pub fn process_css<'a>(
depth + 1,
) {
Ok((data, final_url, media_type)) => {
let mut data_url = data_to_data_url(&media_type, &data, &final_url);
let mut data_url = create_data_url(&media_type, &data, &final_url);
data_url.set_fragment(full_url.fragment());
result.push_str(enquote(data_url.to_string(), false).as_str());
result
.push_str(format_quoted_string(&data_url.to_string()).as_str());
}
Err(_) => {
// Keep remote reference if unable to retrieve the asset
if full_url.scheme() == "http" || full_url.scheme() == "https" {
result.push_str(enquote(full_url.to_string(), false).as_str());
result.push_str(
format_quoted_string(&full_url.to_string()).as_str(),
);
}
}
}

@ -17,7 +17,7 @@ use std::default::Default;
use crate::css::embed_css;
use crate::js::attr_is_event_handler;
use crate::opts::Options;
use crate::url::{clean_url, data_to_data_url, is_url_and_has_protocol, resolve_url};
use crate::url::{clean_url, create_data_url, is_url_and_has_protocol, resolve_url};
use crate::utils::retrieve_asset;
struct SrcSetItem<'a> {
@ -190,7 +190,7 @@ pub fn embed_srcset(
) {
Ok((image_data, image_final_url, image_media_type)) => {
let mut image_data_url =
data_to_data_url(&image_media_type, &image_data, &image_final_url);
create_data_url(&image_media_type, &image_data, &image_final_url);
// Append retreved asset as a data URL
image_data_url.set_fragment(image_full_url.fragment());
result.push_str(image_data_url.as_ref());
@ -534,7 +534,7 @@ pub fn retrieve_and_embed_asset(
options,
depth + 1,
);
let css_data_url = data_to_data_url("text/css", css.as_bytes(), &final_url);
let css_data_url = create_data_url("text/css", css.as_bytes(), &final_url);
set_node_attr(&node, attr_name, Some(css_data_url.to_string()));
@ -559,7 +559,7 @@ pub fn retrieve_and_embed_asset(
)
.unwrap();
let mut frame_data_url = data_to_data_url(&media_type, &frame_data, &final_url);
let mut frame_data_url = create_data_url(&media_type, &frame_data, &final_url);
frame_data_url.set_fragment(resolved_url.fragment());
@ -572,7 +572,7 @@ pub fn retrieve_and_embed_asset(
if node_name == "script" {
media_type = "application/javascript".to_string();
}
let mut data_url = data_to_data_url(&media_type, &data, &final_url);
let mut data_url = create_data_url(&media_type, &data, &final_url);
data_url.set_fragment(resolved_url.fragment());
set_node_attr(node, attr_name, Some(data_url.to_string()));
}

@ -13,7 +13,7 @@ use monolith::html::{
stringify_document, walk_and_embed_assets,
};
use monolith::opts::Options;
use monolith::url::{data_to_data_url, parse_data_url, resolve_url};
use monolith::url::{create_data_url, parse_data_url, resolve_url};
use monolith::utils::retrieve_asset;
mod macros;
@ -266,7 +266,7 @@ fn main() {
0,
) {
Ok((data, final_url, media_type)) => {
let favicon_data_url: Url = data_to_data_url(&media_type, &data, &final_url);
let favicon_data_url: Url = create_data_url(&media_type, &data, &final_url);
dom = add_favicon(&dom.document, favicon_data_url.to_string());
}
Err(_) => {

@ -71,7 +71,7 @@ mod passing {
// STDOUT should contain embedded CSS url()'s
assert_eq!(
std::str::from_utf8(&out.stdout).unwrap(),
"<html><head><style>\n\n @charset \"UTF-8\";\n\n @import \'data:text/css;base64,Ym9keXtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn0K\';\n\n @import url(\'data:text/css;base64,Ym9keXtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn0K\');\n\n @import url(\'data:text/css;base64,Ym9keXtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn0K\');\n\n</style>\n</head><body></body></html>\n"
"<html><head><style>\n\n @charset \"UTF-8\";\n\n @import \"data:text/css;base64,Ym9keXtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn0K\";\n\n @import url(\"data:text/css;base64,Ym9keXtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn0K\");\n\n @import url(\"data:text/css;base64,Ym9keXtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn0K\");\n\n</style>\n</head><body></body></html>\n"
);
// STDERR should list files that got retrieved

@ -193,7 +193,7 @@ mod passing {
// STDOUT should contain HTML with date URL for background-image in it
assert_eq!(
std::str::from_utf8(&out.stdout).unwrap(),
"<html><head></head><body><div style=\"background-image: url('data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGJhc2VQcm9maWxlPSJmdWxsIiB3aWR0aD0iMzAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InJlZCIgLz4KICAgIDxjaXJjbGUgY3g9IjE1MCIgY3k9IjEwMCIgcj0iODAiIGZpbGw9ImdyZWVuIiAvPgogICAgPHRleHQgeD0iMTUwIiB5PSIxMjUiIGZvbnQtc2l6ZT0iNjAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IndoaXRlIj5TVkc8L3RleHQ+Cjwvc3ZnPgo=')\"></div>\n</body></html>\n"
"<html><head></head><body><div style=\"background-image: url(&quot;data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGJhc2VQcm9maWxlPSJmdWxsIiB3aWR0aD0iMzAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InJlZCIgLz4KICAgIDxjaXJjbGUgY3g9IjE1MCIgY3k9IjEwMCIgcj0iODAiIGZpbGw9ImdyZWVuIiAvPgogICAgPHRleHQgeD0iMTUwIiB5PSIxMjUiIGZvbnQtc2l6ZT0iNjAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IndoaXRlIj5TVkc8L3RleHQ+Cjwvc3ZnPgo=&quot;)\"></div>\n</body></html>\n"
);
// STDERR should list files that got retrieved

@ -61,8 +61,8 @@ mod passing {
css::embed_css(cache, &client, &document_url, &STYLE, &options, 0,),
format!(
"/* border: none;*/\
background-image: url('{empty_image}'); \
list-style: url('{empty_image}');\
background-image: url(\"{empty_image}\"); \
list-style: url(\"{empty_image}\");\
width:99.998%; \
margin-top: -20px; \
line-height: -1; \
@ -93,8 +93,8 @@ mod passing {
css::embed_css(cache, &client, &document_url, &STYLE, &options, 0),
format!(
"/* border: none;*/\
background-image: url('{empty_image}'); \
list-style: url('{empty_image}');\
background-image: url(\"{empty_image}\"); \
list-style: url(\"{empty_image}\");\
width:99.998%; \
margin-top: -20px; \
line-height: -1; \
@ -115,7 +115,7 @@ mod passing {
const CSS: &str = "\
#id.class-name:not(:nth-child(3n+0)) {\n \
// border: none;\n \
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=');\n\
background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=\");\n\
}\n\
\n\
html > body {}";
@ -191,9 +191,9 @@ mod passing {
"\
@charset \"UTF-8\";\n\
\n\
@import 'data:text/css;base64,aHRtbHtiYWNrZ3JvdW5kLWNvbG9yOiMwMDB9';\n\
@import \"data:text/css;base64,aHRtbHtiYWNrZ3JvdW5kLWNvbG9yOiMwMDB9\";\n\
\n\
@import url('data:text/css;base64,aHRtbHtjb2xvcjojZmZmfQ==')\n\
@import url(\"data:text/css;base64,aHRtbHtjb2xvcjojZmZmfQ==\")\n\
"
);
}
@ -331,7 +331,7 @@ mod passing {
";
const CSS_OUT: &str = "\
#language a[href=\"#translations\"]:before {\n\
content: url('data:;base64,') \"\\a \";\n\
content: url(\"data:;base64,\") \"\\a \";\n\
white-space: pre }\n\
";

@ -1,53 +0,0 @@
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[cfg(test)]
mod passing {
use crate::css;
#[test]
fn empty_input_single_quotes() {
assert_eq!(css::enquote(str!(""), false), "''");
}
#[test]
fn empty_input_double_quotes() {
assert_eq!(css::enquote(str!(""), true), "\"\"");
}
#[test]
fn apostrophes_single_quotes() {
assert_eq!(
css::enquote(str!("It's a lovely day, don't you think?"), false),
"'It\\'s a lovely day, don\\'t you think?'"
);
}
#[test]
fn apostrophes_double_quotes() {
assert_eq!(
css::enquote(str!("It's a lovely day, don't you think?"), true),
"\"It's a lovely day, don't you think?\""
);
}
#[test]
fn feet_and_inches_single_quotes() {
assert_eq!(
css::enquote(str!("5'2\", 6'5\""), false),
"'5\\'2\", 6\\'5\"'"
);
}
#[test]
fn feet_and_inches_double_quotes() {
assert_eq!(
css::enquote(str!("5'2\", 6'5\""), true),
"\"5'2\\\", 6'5\\\"\""
);
}
}

@ -1,3 +1,2 @@
mod embed_css;
mod enquote;
mod is_image_url_prop;

@ -15,7 +15,7 @@ mod passing {
fn encode_string_with_specific_media_type() {
let mime = "application/javascript";
let data = "var word = 'hello';\nalert(word);\n";
let data_url = url::data_to_data_url(mime, data.as_bytes(), &Url::parse("data:,").unwrap());
let data_url = url::create_data_url(mime, data.as_bytes(), &Url::parse("data:,").unwrap());
assert_eq!(
data_url.as_str(),
@ -26,7 +26,7 @@ mod passing {
#[test]
fn encode_append_fragment() {
let data = "<svg></svg>\n";
let data_url = url::data_to_data_url(
let data_url = url::create_data_url(
"image/svg+xml",
data.as_bytes(),
&Url::parse("data:,").unwrap(),

@ -1,69 +0,0 @@
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[cfg(test)]
mod passing {
use reqwest::Url;
use crate::url;
#[test]
fn http_url() {
assert!(url::is_http_or_https_url(&Url::parse("http://kernel.org").unwrap()));
}
#[test]
fn https_url() {
assert!(url::is_http_or_https_url(&Url::parse("https://www.rust-lang.org/").unwrap()));
}
#[test]
fn http_url_with_backslashes() {
assert!(url::is_http_or_https_url(&Url::parse("http:\\\\freebsd.org\\").unwrap()));
}
}
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
// ██╔════╝██╔══██╗██║██║ ██║████╗ ██║██╔════╝
// █████╗ ███████║██║██║ ██║██╔██╗ ██║██║ ███╗
// ██╔══╝ ██╔══██║██║██║ ██║██║╚██╗██║██║ ██║
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[cfg(test)]
mod failing {
use reqwest::Url;
use crate::url;
#[test]
fn url_with_no_protocol() {
assert!(!url::is_http_or_https_url(&Url::parse("//kernel.org").unwrap()));
}
#[test]
fn dot_slash_filename() {
assert!(!url::is_http_or_https_url(&Url::parse("./index.html").unwrap()));
}
#[test]
fn just_filename() {
assert!(!url::is_http_or_https_url(&Url::parse("some-local-page.htm").unwrap()));
}
#[test]
fn https_ip_port_url() {
assert!(!url::is_http_or_https_url(&Url::parse("ftp://1.2.3.4/www/index.html").unwrap()));
}
#[test]
fn data_url() {
assert!(!url::is_http_or_https_url(
&Url::parse("data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h").unwrap()
));
}
}

@ -48,6 +48,11 @@ mod passing {
assert!(url::is_url_and_has_protocol("https://github.com"));
}
#[test]
fn file() {
assert!(url::is_url_and_has_protocol("file:///tmp/image.png"));
}
#[test]
fn mailto_uppercase() {
assert!(url::is_url_and_has_protocol(
@ -59,6 +64,11 @@ mod passing {
fn empty_data_url() {
assert!(url::is_url_and_has_protocol("data:text/html,"));
}
#[test]
fn empty_data_url_surrounded_by_spaces() {
assert!(url::is_url_and_has_protocol(" data:text/html, "));
}
}
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
@ -74,25 +84,27 @@ mod failing {
#[test]
fn url_with_no_protocol() {
assert!(!url::is_url_and_has_protocol(
"//some-hostname.com/some-file.html"
));
assert_eq!(
url::is_url_and_has_protocol("//some-hostname.com/some-file.html"),
false
);
}
#[test]
fn relative_path() {
assert!(!url::is_url_and_has_protocol(
"some-hostname.com/some-file.html"
));
assert_eq!(
url::is_url_and_has_protocol("some-hostname.com/some-file.html"),
false
);
}
#[test]
fn relative_to_root_path() {
assert!(!url::is_url_and_has_protocol("/some-file.html"));
assert_eq!(url::is_url_and_has_protocol("/some-file.html"), false);
}
#[test]
fn empty_string() {
assert!(!url::is_url_and_has_protocol(""));
assert_eq!(url::is_url_and_has_protocol(""), false);
}
}

@ -1,5 +1,5 @@
mod clean_url;
mod data_to_data_url;
mod create_data_url;
mod is_url_and_has_protocol;
mod parse_data_url;
mod percent_decode;

@ -11,6 +11,34 @@ mod passing {
use crate::url;
#[test]
fn basic_httsp_relative() {
assert_eq!(
url::resolve_url(
&Url::parse("https://www.kernel.org").unwrap(),
"category/signatures.html"
)
.as_str(),
Url::parse("https://www.kernel.org/category/signatures.html")
.unwrap()
.as_str()
);
}
#[test]
fn basic_httsp_absolute() {
assert_eq!(
url::resolve_url(
&Url::parse("https://www.kernel.org").unwrap(),
"/category/signatures.html"
)
.as_str(),
Url::parse("https://www.kernel.org/category/signatures.html")
.unwrap()
.as_str()
);
}
#[test]
fn from_https_to_level_up_relative() {
assert_eq!(
@ -50,7 +78,7 @@ mod passing {
}
#[test]
fn from_https_url_to_relative_root_path() {
fn from_https_url_to_absolute_path() {
assert_eq!(
url::resolve_url(
&Url::parse("https://www.kernel.org/category/signatures.html").unwrap(),
@ -148,22 +176,28 @@ mod passing {
);
}
// #[test]
// fn resolve_from_file_url_to_file_url() {
// assert_eq!(
// if cfg!(windows) {
// url::resolve_url(&Url::parse("file:///c:/index.html").unwrap(), "file:///c:/image.png").as_str()
// } else {
// url::resolve_url(&Url::parse("file:///tmp/index.html").unwrap(), "file:///tmp/image.png")
// .as_str()
// },
// if cfg!(windows) {
// "file:///c:/image.png"
// } else {
// "file:///tmp/image.png"
// }
// );
// }
#[test]
fn resolve_from_file_url_to_file_url() {
if cfg!(windows) {
assert_eq!(
url::resolve_url(
&Url::parse("file:///c:/index.html").unwrap(),
"file:///c:/image.png"
)
.as_str(),
"file:///c:/image.png"
);
} else {
assert_eq!(
url::resolve_url(
&Url::parse("file:///tmp/index.html").unwrap(),
"file:///tmp/image.png"
)
.as_str(),
"file:///tmp/image.png"
);
}
}
}
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗

@ -36,8 +36,8 @@ mod passing {
)
.unwrap();
assert_eq!(
url::data_to_data_url(&media_type, &data, &final_url),
url::data_to_data_url(
url::create_data_url(&media_type, &data, &final_url),
url::create_data_url(
"text/html",
"target".as_bytes(),
&Url::parse("data:text/html;base64,c291cmNl").unwrap()
@ -45,7 +45,7 @@ mod passing {
);
assert_eq!(
final_url,
url::data_to_data_url(
url::create_data_url(
"text/html",
"target".as_bytes(),
&Url::parse("data:text/html;base64,c291cmNl").unwrap()
@ -85,7 +85,7 @@ mod passing {
0,
)
.unwrap();
assert_eq!(url::data_to_data_url("application/javascript", &data, &final_url), Url::parse("data:application/javascript;base64,ZG9jdW1lbnQuYm9keS5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSAiZ3JlZW4iOwpkb2N1bWVudC5ib2R5LnN0eWxlLmNvbG9yID0gInJlZCI7Cg==").unwrap());
assert_eq!(url::create_data_url("application/javascript", &data, &final_url), Url::parse("data:application/javascript;base64,ZG9jdW1lbnQuYm9keS5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSAiZ3JlZW4iOwpkb2N1bWVudC5ib2R5LnN0eWxlLmNvbG9yID0gInJlZCI7Cg==").unwrap());
assert_eq!(
final_url,
Url::parse(&format!(

@ -12,7 +12,7 @@ pub fn clean_url(url: Url) -> Url {
url
}
pub fn data_to_data_url(media_type: &str, data: &[u8], final_asset_url: &Url) -> Url {
pub fn create_data_url(media_type: &str, data: &[u8], final_asset_url: &Url) -> Url {
let media_type: String = if media_type.is_empty() {
detect_media_type(data, &final_asset_url)
} else {

Loading…
Cancel
Save