Skip to content

Commit

Permalink
fix: generally handle empty URLs without crashing
Browse files Browse the repository at this point in the history
  • Loading branch information
falko17 committed Dec 22, 2024
1 parent f71f8fb commit 8532976
Showing 1 changed file with 31 additions and 12 deletions.
43 changes: 31 additions & 12 deletions src/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use sanitize_filename::sanitize;
use serde_json::Value;
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::fmt::Display;
use std::hash::{DefaultHasher, Hash, Hasher};
use std::path::{Path, PathBuf};
use tokio::fs;
Expand Down Expand Up @@ -72,6 +74,17 @@ pub(crate) fn make_data_url(data: &Bytes) -> String {
format!("data:{mime};base64,{}", BASE64_STANDARD.encode(data))
}

#[derive(Debug)]
struct EmptyUrl;

impl Display for EmptyUrl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Empty URL encountered.")
}
}

impl Error for EmptyUrl {}

/// An asset download request.
#[derive(Debug, Hash, Clone, PartialEq, Eq)]
pub(crate) struct AssetDownload {
Expand Down Expand Up @@ -234,7 +247,11 @@ impl AssetCollector {
ignore_inaccessible: bool,
json_ref: JsonReference,
) -> Result<AssetDownload> {
let mut file = PathBuf::from(file_value.as_str().unwrap_or(&self.default_icon_url));
let file_string = file_value.as_str().unwrap_or(&self.default_icon_url);
if file_string.is_empty() {
return Err(EmptyUrl.into());
}
let mut file = PathBuf::from(file_string);
if file.extension().is_none() {
if let Some(ext) = default_extension {
file.set_extension(ext);
Expand Down Expand Up @@ -643,15 +660,13 @@ impl<'a> AssetDownloader<'a> {
// Evidence can contain two types of assets:
// 1.) Icons.
let external = evidence["icon_external"].as_bool();
if evidence["icon"].as_str().is_some_and(|x| !x.is_empty()) {
self.collector.collect_download(
&mut evidence["icon"],
Some(paths.evidence_path()),
external,
Some("png"),
JsonReference::for_case(case_id, format!("/evidence/{i}/icon")),
);
}
self.collector.collect_download(
&mut evidence["icon"],
Some(paths.evidence_path()),
external,
Some("png"),
JsonReference::for_case(case_id, format!("/evidence/{i}/icon")),
);
evidence["icon_external"] = Value::Bool(true);

// 2.) "Check button data", which may be an image or a sound.
Expand Down Expand Up @@ -708,6 +723,7 @@ impl<'a> AssetDownloader<'a> {
) -> Result<()> {
for (i, place) in places.filter_map(|x| x.1.as_object_mut().map(|o| (x.0, o))) {
// Download place background itself.
trace!("{place:?}");
if let Some(background) = place["background"].as_object_mut() {
// This may just be a color instead of an actual image.
// (In the case of default places).
Expand Down Expand Up @@ -937,7 +953,10 @@ impl<'a> AssetDownloader<'a> {
.into_iter()
.chain(failures.iter().map(|e| (None, e)))
{
if asset.as_ref().is_some_and(|x| x.ignore_inaccessible) {
if asset.as_ref().is_some_and(|x| x.ignore_inaccessible)
// Some assets have empty URLs, we don't need to download these.
|| asset.as_ref().is_none() && err.root_cause().is::<EmptyUrl>()
{
continue;
}
error!(
Expand All @@ -950,7 +969,7 @@ impl<'a> AssetDownloader<'a> {
}
);
if !self.ctx.args.continue_on_asset_error {
return Err(anyhow!("Could not download asset: {err}"));
std::process::exit(exitcode::UNAVAILABLE);
}
}

Expand Down

0 comments on commit 8532976

Please sign in to comment.