From 97430912ce1f522b6f956520b9a3ec17f1b09de9 Mon Sep 17 00:00:00 2001 From: Ariel Fridman Date: Mon, 2 Jun 2025 14:19:16 +0300 Subject: [PATCH] Fix breaking changes caused by move to ureq 3 None of the changes cause any logic changes (I think). They just deal with stuff changed/deprecated in ureq 3. --- crates/typst-cli/src/update.rs | 6 ++-- crates/typst-kit/src/download.rs | 60 +++++++++++++++++++++----------- crates/typst-kit/src/package.rs | 6 ++-- 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/crates/typst-cli/src/update.rs b/crates/typst-cli/src/update.rs index ec8ca71e8..06d1814e9 100644 --- a/crates/typst-cli/src/update.rs +++ b/crates/typst-cli/src/update.rs @@ -145,10 +145,10 @@ impl Release { }; match downloader.download(&url) { - Ok(response) => response.into_json().map_err(|err| { + Ok(mut response) => response.body_mut().read_json().map_err(|err| { eco_format!("failed to parse release information ({err})") }), - Err(ureq::Error::Status(404, _)) => { + Err(ureq::Error::StatusCode(404)) => { bail!("release not found (searched at {url})") } Err(err) => bail!("failed to download release ({err})"), @@ -175,7 +175,7 @@ impl Release { &mut PrintDownload("release"), ) { Ok(data) => data, - Err(ureq::Error::Status(404, _)) => { + Err(ureq::Error::StatusCode(404)) => { bail!("asset not found (searched for {})", asset.name); } Err(err) => bail!("failed to download asset ({err})"), diff --git a/crates/typst-kit/src/download.rs b/crates/typst-kit/src/download.rs index a4d49b4f3..5805a81f0 100644 --- a/crates/typst-kit/src/download.rs +++ b/crates/typst-kit/src/download.rs @@ -13,9 +13,8 @@ use std::sync::Arc; use std::time::{Duration, Instant}; use ecow::EcoString; -use native_tls::{Certificate, TlsConnector}; use once_cell::sync::OnceCell; -use ureq::Response; +use ureq::tls::{Certificate, RootCerts, TlsProvider}; /// Manages progress reporting for downloads. pub trait Progress { @@ -57,7 +56,7 @@ pub struct DownloadState { pub struct Downloader { user_agent: EcoString, cert_path: Option, - cert: OnceCell, + cert: OnceCell>, } impl Downloader { @@ -82,7 +81,10 @@ impl Downloader { } /// Crates a new downloader with the given user agent and certificate. - pub fn with_cert(user_agent: impl Into, cert: Certificate) -> Self { + pub fn with_cert( + user_agent: impl Into, + cert: Certificate<'static>, + ) -> Self { Self { user_agent: user_agent.into(), cert_path: None, @@ -96,7 +98,7 @@ impl Downloader { /// - Returns `None` if `--cert` and `TYPST_CERT` are not set. /// - Returns `Some(Ok(cert))` if the certificate was loaded successfully. /// - Returns `Some(Err(err))` if an error occurred while loading the certificate. - pub fn cert(&self) -> Option> { + pub fn cert(&self) -> Option>> { self.cert_path.as_ref().map(|path| { self.cert.get_or_try_init(|| { let pem = std::fs::read(path)?; @@ -107,31 +109,42 @@ impl Downloader { /// Download binary data from the given url. #[allow(clippy::result_large_err)] - pub fn download(&self, url: &str) -> Result { - let mut builder = ureq::AgentBuilder::new(); - let mut tls = TlsConnector::builder(); + pub fn download( + &self, + url: &str, + ) -> Result, ureq::Error> { + let mut builder = ureq::config::Config::builder(); // Set user agent. builder = builder.user_agent(&self.user_agent); // Get the network proxy config from the environment and apply it. if let Some(proxy) = env_proxy::for_url_str(url) - .to_url() - .and_then(|url| ureq::Proxy::new(url).ok()) + .to_string() + .and_then(|url| ureq::Proxy::new(&url).ok()) { - builder = builder.proxy(proxy); + builder = builder.proxy(Some(proxy)); } // Apply a custom CA certificate if present. - if let Some(cert) = self.cert() { - tls.add_root_certificate(cert?.clone()); - } + let maybe_cert = self.cert().transpose()?.cloned().map_or( + RootCerts::PlatformVerifier, + |cert| { + let certs = vec![cert]; + RootCerts::Specific(Arc::new(certs)) + }, + ); // Configure native TLS. - let connector = tls.build().map_err(io::Error::other)?; - builder = builder.tls_connector(Arc::new(connector)); + let tls_config = ureq::tls::TlsConfig::builder() + .provider(TlsProvider::NativeTls) + .root_certs(maybe_cert); - builder.build().get(url).call() + builder = builder.tls_config(tls_config.build()); + + let agent = ureq::Agent::new_with_config(builder.build()); + + agent.get(url).call() } /// Download binary data from the given url and report its progress. @@ -170,7 +183,7 @@ const SAMPLES: usize = 5; /// over a websocket and reports its progress. struct RemoteReader<'p> { /// The reader returned by the ureq::Response. - reader: Box, + reader: ureq::BodyReader<'static>, /// The download state, holding download metadata for progress reporting. state: DownloadState, /// The instant at which progress was last reported. @@ -184,13 +197,18 @@ impl<'p> RemoteReader<'p> { /// /// The 'Content-Length' header is used as a size hint for read /// optimization, if present. - fn from_response(response: Response, progress: &'p mut dyn Progress) -> Self { + fn from_response( + response: ureq::http::Response, + progress: &'p mut dyn Progress, + ) -> Self { let content_len: Option = response - .header("Content-Length") + .headers() + .get("Content-Length") + .and_then(|header| header.to_str().ok()) .and_then(|header| header.parse().ok()); Self { - reader: response.into_reader(), + reader: response.into_body().into_reader(), last_progress: None, state: DownloadState { content_len, diff --git a/crates/typst-kit/src/package.rs b/crates/typst-kit/src/package.rs index 584ec83c0..292d1f823 100644 --- a/crates/typst-kit/src/package.rs +++ b/crates/typst-kit/src/package.rs @@ -150,10 +150,10 @@ impl PackageStorage { .get_or_try_init(|| { let url = format!("{DEFAULT_REGISTRY}/{DEFAULT_NAMESPACE}/index.json"); match self.downloader.download(&url) { - Ok(response) => response.into_json().map_err(|err| { + Ok(mut response) => response.body_mut().read_json().map_err(|err| { eco_format!("failed to parse package index: {err}") }), - Err(ureq::Error::Status(404, _)) => { + Err(ureq::Error::StatusCode(404)) => { bail!("failed to fetch package index (not found)") } Err(err) => bail!("failed to fetch package index ({err})"), @@ -181,7 +181,7 @@ impl PackageStorage { let data = match self.downloader.download_with_progress(&url, progress) { Ok(data) => data, - Err(ureq::Error::Status(404, _)) => { + Err(ureq::Error::StatusCode(404)) => { if let Ok(version) = self.determine_latest_version(&spec.versionless()) { return Err(PackageError::VersionNotFound(spec.clone(), version)); } else {