From b7acf975ba5625bc4e48c4ba7358e736544aa9cd Mon Sep 17 00:00:00 2001 From: Shocker Date: Fri, 27 Feb 2026 15:02:41 +0200 Subject: [PATCH 1/4] Fix favicon fetching to check all icon links instead of just the first one --- src/api/icons.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/api/icons.rs b/src/api/icons.rs index 35a1de30..25945378 100644 --- a/src/api/icons.rs +++ b/src/api/icons.rs @@ -534,7 +534,9 @@ async fn download_icon(domain: &str) -> Result<(Bytes, Option<&str>), Error> { use data_url::DataUrl; - for icon in icon_result.iconlist.iter().take(5) { + for (i, icon) in icon_result.iconlist.iter().enumerate() { + let is_last = i == icon_result.iconlist.iter().count() - 1; + if icon.href.starts_with("data:image") { let Ok(datauri) = DataUrl::process(&icon.href) else { continue; @@ -562,11 +564,23 @@ async fn download_icon(domain: &str) -> Result<(Bytes, Option<&str>), Error> { _ => debug!("Extracted icon from data:image uri is invalid"), }; } else { - let res = get_page_with_referer(&icon.href, &icon_result.referer).await?; + debug!("Trying {}", icon.href); + // Make sure all icons are checked before returning error + let res = match get_page_with_referer(&icon.href, &icon_result.referer).await { + Ok(r) => r, + Err(e) if is_last => return Err(e.into()), + Err(e) if CustomHttpClientError::downcast_ref(&e).is_some() => return Err(e.into()), // If blacklisted stop immediately instead of checking the rest of the icons. see explanation and actual handling inside get_icon() + Err(e) => { + warn!("Unable to download icon: {e:?}"); + + // Continue to next icon + continue; + } + }; buffer = stream_to_bytes_limit(res, 5120 * 1024).await?; // 5120KB/5MB for each icon max (Same as icons.bitwarden.net) - // Check if the icon type is allowed, else try an icon from the list. + // Check if the icon type is allowed, else try another icon from the list. icon_type = get_icon_type(&buffer); if icon_type.is_none() { buffer.clear(); From 0d685026eb655b2caf021298014682cc8cea7024 Mon Sep 17 00:00:00 2001 From: Shocker Date: Fri, 27 Feb 2026 19:07:10 +0200 Subject: [PATCH 2/4] revert max icons limit removal --- src/api/icons.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/icons.rs b/src/api/icons.rs index 25945378..94b15ffe 100644 --- a/src/api/icons.rs +++ b/src/api/icons.rs @@ -534,8 +534,8 @@ async fn download_icon(domain: &str) -> Result<(Bytes, Option<&str>), Error> { use data_url::DataUrl; - for (i, icon) in icon_result.iconlist.iter().enumerate() { - let is_last = i == icon_result.iconlist.iter().count() - 1; + for (i, icon) in icon_result.iconlist.iter().take(5).enumerate() { + let is_last = i == icon_result.iconlist.iter().take(5).count() - 1; if icon.href.starts_with("data:image") { let Ok(datauri) = DataUrl::process(&icon.href) else { From 757b6fcacfcb21ad220fca4b6180c4ee53ad18a6 Mon Sep 17 00:00:00 2001 From: Shocker Date: Tue, 7 Apr 2026 19:19:48 +0300 Subject: [PATCH 3/4] optimize code --- src/api/icons.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/api/icons.rs b/src/api/icons.rs index 94b15ffe..fb4b57ac 100644 --- a/src/api/icons.rs +++ b/src/api/icons.rs @@ -534,9 +534,8 @@ async fn download_icon(domain: &str) -> Result<(Bytes, Option<&str>), Error> { use data_url::DataUrl; - for (i, icon) in icon_result.iconlist.iter().take(5).enumerate() { - let is_last = i == icon_result.iconlist.iter().take(5).count() - 1; - + let mut icons = icon_result.iconlist.iter().take(5).peekable(); + while let Some(icon) = icons.next() { if icon.href.starts_with("data:image") { let Ok(datauri) = DataUrl::process(&icon.href) else { continue; @@ -568,7 +567,7 @@ async fn download_icon(domain: &str) -> Result<(Bytes, Option<&str>), Error> { // Make sure all icons are checked before returning error let res = match get_page_with_referer(&icon.href, &icon_result.referer).await { Ok(r) => r, - Err(e) if is_last => return Err(e.into()), + Err(e) if icons.peek().is_none() => return Err(e.into()), Err(e) if CustomHttpClientError::downcast_ref(&e).is_some() => return Err(e.into()), // If blacklisted stop immediately instead of checking the rest of the icons. see explanation and actual handling inside get_icon() Err(e) => { warn!("Unable to download icon: {e:?}"); From e235aea44d73a867f3e1066241f7c54d03dc5caa Mon Sep 17 00:00:00 2001 From: Shocker Date: Tue, 7 Apr 2026 19:44:26 +0300 Subject: [PATCH 4/4] code formatting --- src/api/icons.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/icons.rs b/src/api/icons.rs index fb4b57ac..4e0b6791 100644 --- a/src/api/icons.rs +++ b/src/api/icons.rs @@ -567,11 +567,11 @@ async fn download_icon(domain: &str) -> Result<(Bytes, Option<&str>), Error> { // Make sure all icons are checked before returning error let res = match get_page_with_referer(&icon.href, &icon_result.referer).await { Ok(r) => r, - Err(e) if icons.peek().is_none() => return Err(e.into()), - Err(e) if CustomHttpClientError::downcast_ref(&e).is_some() => return Err(e.into()), // If blacklisted stop immediately instead of checking the rest of the icons. see explanation and actual handling inside get_icon() + Err(e) if icons.peek().is_none() => return Err(e), + Err(e) if CustomHttpClientError::downcast_ref(&e).is_some() => return Err(e), // If blacklisted stop immediately instead of checking the rest of the icons. see explanation and actual handling inside get_icon() Err(e) => { warn!("Unable to download icon: {e:?}"); - + // Continue to next icon continue; }