refactor: Replace isahc with reqwest

This commit is contained in:
Michael Aaron Murphy 2022-03-27 18:23:51 +02:00 committed by Michael Murphy
parent dbfb3921ae
commit 7b98785c27
3 changed files with 369 additions and 154 deletions

435
Cargo.lock generated
View file

@ -239,12 +239,6 @@ dependencies = [
"system-deps",
]
[[package]]
name = "castaway"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6"
[[package]]
name = "cc"
version = "1.0.73"
@ -296,45 +290,20 @@ dependencies = [
]
[[package]]
name = "crossbeam-utils"
version = "0.8.8"
name = "core-foundation"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
dependencies = [
"cfg-if",
"lazy_static",
"core-foundation-sys",
"libc",
]
[[package]]
name = "curl"
version = "0.4.43"
name = "core-foundation-sys"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37d855aeef205b43f65a5001e0997d81f8efca7badad4fad7d897aa7f0d0651f"
dependencies = [
"curl-sys",
"libc",
"openssl-probe",
"openssl-sys",
"schannel",
"socket2",
"winapi",
]
[[package]]
name = "curl-sys"
version = "0.4.53+curl-7.82.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8092905a5a9502c312f223b2775f57ec5c5b715f9a15ee9d2a8591d1364a0352"
dependencies = [
"cc",
"libc",
"libnghttp2-sys",
"libz-sys",
"openssl-sys",
"pkg-config",
"vcpkg",
"winapi",
]
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "darling"
@ -491,6 +460,21 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "fork"
version = "0.1.19"
@ -890,6 +874,31 @@ dependencies = [
"syn",
]
[[package]]
name = "h2"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62eeb471aa3e3c9197aa4bfeabfe02982f6dc96f750486c0bb0009ac58b26d2b"
dependencies = [
"bytes 1.1.0",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
"http",
"indexmap",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "heck"
version = "0.4.0"
@ -922,6 +931,29 @@ dependencies = [
"itoa",
]
[[package]]
name = "http-body"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6"
dependencies = [
"bytes 1.1.0",
"http",
"pin-project-lite",
]
[[package]]
name = "httparse"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4"
[[package]]
name = "httpdate"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "human-sort"
version = "0.2.2"
@ -934,6 +966,43 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86cce260d758a9aa3d7c4b99d55c815a540f8a37514ba6046ab6be402a157cb0"
[[package]]
name = "hyper"
version = "0.14.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2"
dependencies = [
"bytes 1.1.0",
"futures-channel",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"socket2",
"tokio",
"tower-service",
"tracing",
"want",
]
[[package]]
name = "hyper-tls"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes 1.1.0",
"hyper",
"native-tls",
"tokio",
"tokio-native-tls",
]
[[package]]
name = "ident_case"
version = "1.0.1"
@ -951,6 +1020,16 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "instant"
version = "0.1.12"
@ -961,31 +1040,10 @@ dependencies = [
]
[[package]]
name = "isahc"
version = "1.7.0"
name = "ipnet"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "437f8808009c031df3c1d532c8fd7e3d73239dfe522ebf0b94b5e34d5d01044b"
dependencies = [
"async-channel",
"castaway",
"crossbeam-utils",
"curl",
"curl-sys",
"encoding_rs",
"event-listener",
"futures-lite",
"http",
"log",
"mime",
"once_cell",
"polling",
"slab",
"sluice",
"tracing",
"tracing-futures",
"url",
"waker-fn",
]
checksum = "35e70ee094dc02fd9c13fdad4940090f22dbd6ac7c9e7094a46cf0232a50bc7c"
[[package]]
name = "itoa"
@ -1014,28 +1072,6 @@ version = "0.2.121"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
[[package]]
name = "libnghttp2-sys"
version = "0.1.7+1.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57ed28aba195b38d5ff02b9170cbff627e336a20925e43b4945390401c5dc93f"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "libz-sys"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f35facd4a5673cb5a48822be2be1d4236c1c99cb4113cab7061ac720d5bf859"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "locale_config"
version = "0.3.0"
@ -1144,6 +1180,24 @@ dependencies = [
"getrandom",
]
[[package]]
name = "native-tls"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d"
dependencies = [
"lazy_static",
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "new_mime_guess"
version = "4.0.1"
@ -1227,6 +1281,20 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "openssl"
version = "0.10.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
dependencies = [
"bitflags",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-sys",
]
[[package]]
name = "openssl-probe"
version = "0.1.5"
@ -1404,6 +1472,7 @@ version = "1.1.1"
dependencies = [
"anyhow",
"async-pidfd",
"bytes 1.1.0",
"dirs 4.0.0",
"flume",
"fork",
@ -1412,10 +1481,10 @@ dependencies = [
"gtk",
"human-sort",
"human_format",
"isahc",
"new_mime_guess",
"pop-launcher",
"regex",
"reqwest",
"ron",
"serde",
"serde_json",
@ -1593,6 +1662,51 @@ version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
]
[[package]]
name = "reqwest"
version = "0.11.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46a1f7aa4f35e5e8b4160449f51afc758f0ce6454315a9fa7d0d113e958c41eb"
dependencies = [
"base64",
"bytes 1.1.0",
"encoding_rs",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"hyper",
"hyper-tls",
"ipnet",
"js-sys",
"lazy_static",
"log",
"mime",
"native-tls",
"percent-encoding",
"pin-project-lite",
"serde",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-native-tls",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"winreg",
]
[[package]]
name = "ron"
version = "0.7.0"
@ -1641,6 +1755,29 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "security-framework"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc"
dependencies = [
"bitflags",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "semver"
version = "0.11.0"
@ -1701,6 +1838,18 @@ dependencies = [
"syn",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_with"
version = "1.12.0"
@ -1763,17 +1912,6 @@ version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
[[package]]
name = "sluice"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5"
dependencies = [
"async-channel",
"futures-core",
"futures-io",
]
[[package]]
name = "smallvec"
version = "1.8.0"
@ -1850,6 +1988,20 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af547b166dd1ea4b472165569fc456cfb6818116f854690b0ff205e636523dab"
[[package]]
name = "tempfile"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [
"cfg-if",
"fastrand",
"libc",
"redox_syscall",
"remove_dir_all",
"winapi",
]
[[package]]
name = "thiserror"
version = "1.0.30"
@ -1907,6 +2059,7 @@ dependencies = [
"once_cell",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"winapi",
]
@ -1922,6 +2075,16 @@ dependencies = [
"syn",
]
[[package]]
name = "tokio-native-tls"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
dependencies = [
"native-tls",
"tokio",
]
[[package]]
name = "tokio-stream"
version = "0.1.8"
@ -1933,6 +2096,20 @@ dependencies = [
"tokio",
]
[[package]]
name = "tokio-util"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0"
dependencies = [
"bytes 1.1.0",
"futures-core",
"futures-sink",
"log",
"pin-project-lite",
"tokio",
]
[[package]]
name = "toml"
version = "0.5.8"
@ -1942,6 +2119,12 @@ dependencies = [
"serde",
]
[[package]]
name = "tower-service"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
[[package]]
name = "tracing"
version = "0.1.32"
@ -1949,7 +2132,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f"
dependencies = [
"cfg-if",
"log",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
@ -1976,16 +2158,6 @@ dependencies = [
"valuable",
]
[[package]]
name = "tracing-futures"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
dependencies = [
"pin-project 1.0.10",
"tracing",
]
[[package]]
name = "tracing-log"
version = "0.1.2"
@ -2015,6 +2187,12 @@ dependencies = [
"tracing-log",
]
[[package]]
name = "try-lock"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "ucd-trie"
version = "0.1.3"
@ -2099,6 +2277,16 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
[[package]]
name = "want"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
dependencies = [
"log",
"try-lock",
]
[[package]]
name = "ward"
version = "2.1.0"
@ -2142,6 +2330,18 @@ dependencies = [
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.79"
@ -2171,6 +2371,16 @@ version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2"
[[package]]
name = "web-sys"
version = "0.3.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "wepoll-ffi"
version = "0.1.2"
@ -2202,6 +2412,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "winreg"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]
[[package]]
name = "xdg"
version = "2.4.1"

View file

@ -27,14 +27,15 @@ urlencoding = "2.1.0"
zbus = "2.1.1"
zvariant = "3.1.2"
ward = "2.1.0"
isahc = "1.7.0"
url = "2.2.2"
sysfs-class = "0.1.3"
anyhow = "1.0.56"
flume = "0.10.12"
dirs = "4.0.0"
futures = "0.3.21"
reqwest = "0.11.10"
bytes = "1.1.0"
[dependencies.tokio]
version = "1.17.0"
features = ["fs", "io-std", "macros", "process", "rt"]
features = ["fs", "io-std", "macros", "process", "rt"]

View file

@ -5,11 +5,9 @@ use std::borrow::Cow;
use std::path::{Path, PathBuf};
use std::time::Duration;
use futures::io::AsyncReadExt;
use bytes::Bytes;
use futures::StreamExt;
use isahc::config::{Configurable, RedirectPolicy};
use isahc::http::header::CONTENT_TYPE;
use isahc::{AsyncReadResponseExt, HttpClient};
use reqwest::Client;
use url::Url;
use pop_launcher::*;
@ -41,7 +39,7 @@ pub struct App {
config: Config,
queries: Vec<String>,
out: tokio::io::Stdout,
client: HttpClient,
client: Client,
cache: PathBuf,
}
@ -67,8 +65,7 @@ impl Default for App {
config: config::load(),
queries: Vec::new(),
out: async_stdout(),
client: HttpClient::builder()
.redirect_policy(RedirectPolicy::Follow)
client: Client::builder()
.timeout(Duration::from_secs(1))
.build()
.expect("failed to create http client"),
@ -181,17 +178,17 @@ fn build_query(definition: &Definition, query: &str) -> String {
[prefix, &*definition.query, &*urlencoding::encode(query)].concat()
}
async fn fetch_favicon(url: &str, favicon_path: &Path, client: &HttpClient) -> Option<Vec<u8>> {
let response = client.get_async(url).await;
async fn fetch_favicon(url: &str, favicon_path: &Path, client: &Client) -> Option<Bytes> {
let response = client.get(url).send().await;
match response {
Err(err) => {
tracing::error!("error fetching favicon {}: {}", url, err);
None
}
Ok(mut response) => {
Ok(response) => {
let content_type = response
.headers()
.get(CONTENT_TYPE)
.get(reqwest::header::CONTENT_TYPE)
.and_then(|header| header.to_str().ok())
.unwrap();
@ -203,23 +200,23 @@ async fn fetch_favicon(url: &str, favicon_path: &Path, client: &HttpClient) -> O
);
};
let mut icon = vec![];
if let Err(err) = response.body_mut().read_to_end(&mut icon).await {
tracing::error!("error reading favicon response body: {}", err);
match response.bytes().await {
Ok(icon) => Some(icon),
Err(why) => {
tracing::error!("error reading favicon response body: {}", why);
None
}
}
Some(icon)
}
}
}
// Try to extract a favicon url from html the icon path
// returned can be either absolute or relative to the page domain
async fn favicon_url_from_page_source(domain: &str, client: &HttpClient) -> Option<String> {
async fn favicon_url_from_page_source(domain: &str, client: &Client) -> Option<String> {
let url = format!("https://{}", domain);
match client.get_async(&url).await {
Ok(mut html) => html
match client.get(&url).send().await {
Ok(html) => html
.text()
.await
.ok()
@ -271,14 +268,15 @@ fn parse_favicon(html: &str) -> Option<String> {
#[cfg(test)]
mod test {
use isahc::{HttpClient, ReadResponseExt};
use crate::web::parse_favicon;
use isahc::config::{Configurable, RedirectPolicy};
#[test]
fn should_parse_favicon_url_github() {
let html = isahc::get("https://github.com").unwrap().text().unwrap();
async fn fetch(url: &str) -> String {
reqwest::get(url).await.unwrap().text().await.unwrap()
}
#[tokio::test]
async fn should_parse_favicon_url_github() {
let html = fetch("https://github.com").await;
let icon_url = parse_favicon(&html);
assert_eq!(
@ -287,35 +285,32 @@ mod test {
);
}
#[test]
fn should_parse_favicon_url_ddg() {
#[tokio::test]
async fn should_parse_favicon_url_ddg() {
// Ddg returns a relative path to its favicon
let html = isahc::get("https://duckduckgo.com")
.unwrap()
.text()
.unwrap();
let html = fetch("https://duckduckgo.com").await;
let icon_url = parse_favicon(&html);
assert_eq!(Some("/favicon.ico".to_string()), icon_url);
}
#[test]
fn parse_favicon_url_google_returns_none() {
#[tokio::test]
async fn parse_favicon_url_google_returns_none() {
// Google seems to set its favicon via javascript
// hence there is no way to get the favicon from the page
// source
let html = isahc::get("https://google.com").unwrap().text().unwrap();
let html = fetch("https://google.com").await;
let icon_url = parse_favicon(&html);
assert!(icon_url.is_none());
}
#[test]
fn should_parse_favicon_url_flathub() {
#[tokio::test]
async fn should_parse_favicon_url_flathub() {
// Ensure we don't match the commented icon in flathub page
// <!-- <link rel="icon" type="image/x-icon" href="favicon.ico"> -->
// <link rel="icon" type="image/png" href="/assets/themes/flathub/favicon-32x32.png">
let html = isahc::get("https://flathub.org").unwrap().text().unwrap();
let html = fetch("https://flathub.org").await;
let icon_url = parse_favicon(&html);
assert_eq!(
@ -324,19 +319,19 @@ mod test {
);
}
#[test]
fn should_parse_favicon_url_aliexpress() {
#[tokio::test]
async fn should_parse_favicon_url_aliexpress() {
// Aliexpress icon href start with two slash :`href="//ae01.alicdn.com/images/eng/wholesale/icon/aliexpress.ico"`
let client = HttpClient::builder()
.redirect_policy(RedirectPolicy::Follow)
.build()
.unwrap();
let client = reqwest::Client::new();
let html = client
.get("https://aliexpress.com")
.send()
.await
.unwrap()
.text()
.await
.unwrap();
let icon_url = parse_favicon(&html);