diff options
author | David Sherret <dsherret@users.noreply.github.com> | 2023-05-01 16:42:05 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-01 16:42:05 -0400 |
commit | 913176313b6869eeb29b8d48e0c8d80227fa6544 (patch) | |
tree | cc0128b36ea9b22207a3dd41a401ae4ecd131e74 /cli/http_util.rs | |
parent | ecc70eb58fd5531f3b93402cf781e93ef2bb4d64 (diff) |
perf: lazily create RootCertStore (#18938)
Diffstat (limited to 'cli/http_util.rs')
-rw-r--r-- | cli/http_util.rs | 72 |
1 files changed, 54 insertions, 18 deletions
diff --git a/cli/http_util.rs b/cli/http_util.rs index b01732ca9..7c17e8e1e 100644 --- a/cli/http_util.rs +++ b/cli/http_util.rs @@ -15,8 +15,9 @@ use deno_runtime::deno_fetch::create_http_client; use deno_runtime::deno_fetch::reqwest; use deno_runtime::deno_fetch::reqwest::header::LOCATION; use deno_runtime::deno_fetch::reqwest::Response; -use deno_runtime::deno_tls::rustls::RootCertStore; +use deno_runtime::deno_tls::RootCertStoreProvider; use std::collections::HashMap; +use std::sync::Arc; use std::time::Duration; use std::time::SystemTime; @@ -217,34 +218,68 @@ impl CacheSemantics { } } -#[derive(Debug, Clone)] -pub struct HttpClient(reqwest::Client); +pub struct HttpClient { + root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>, + unsafely_ignore_certificate_errors: Option<Vec<String>>, + cell: once_cell::sync::OnceCell<reqwest::Client>, +} + +impl std::fmt::Debug for HttpClient { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("HttpClient") + .field( + "unsafely_ignore_certificate_errors", + &self.unsafely_ignore_certificate_errors, + ) + .finish() + } +} impl HttpClient { pub fn new( - root_cert_store: Option<RootCertStore>, + root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>, unsafely_ignore_certificate_errors: Option<Vec<String>>, - ) -> Result<Self, AnyError> { - Ok(HttpClient::from_client(create_http_client( - get_user_agent(), - root_cert_store, - vec![], - None, + ) -> Self { + Self { + root_cert_store_provider, unsafely_ignore_certificate_errors, - None, - )?)) + cell: Default::default(), + } } + #[cfg(test)] pub fn from_client(client: reqwest::Client) -> Self { - Self(client) + let result = Self { + root_cert_store_provider: Default::default(), + unsafely_ignore_certificate_errors: Default::default(), + cell: Default::default(), + }; + result.cell.set(client).unwrap(); + result + } + + fn client(&self) -> Result<&reqwest::Client, AnyError> { + self.cell.get_or_try_init(|| { + create_http_client( + get_user_agent(), + match &self.root_cert_store_provider { + Some(provider) => Some(provider.get_or_try_init()?.clone()), + None => None, + }, + vec![], + None, + self.unsafely_ignore_certificate_errors.clone(), + None, + ) + }) } /// Do a GET request without following redirects. pub fn get_no_redirect<U: reqwest::IntoUrl>( &self, url: U, - ) -> reqwest::RequestBuilder { - self.0.get(url) + ) -> Result<reqwest::RequestBuilder, AnyError> { + Ok(self.client()?.get(url)) } pub async fn download_text<U: reqwest::IntoUrl>( @@ -306,12 +341,13 @@ impl HttpClient { url: U, ) -> Result<Response, AnyError> { let mut url = url.into_url()?; - let mut response = self.get_no_redirect(url.clone()).send().await?; + let mut response = self.get_no_redirect(url.clone())?.send().await?; let status = response.status(); if status.is_redirection() { for _ in 0..5 { let new_url = resolve_redirect_from_response(&url, &response)?; - let new_response = self.get_no_redirect(new_url.clone()).send().await?; + let new_response = + self.get_no_redirect(new_url.clone())?.send().await?; let status = new_response.status(); if status.is_redirection() { response = new_response; @@ -357,7 +393,7 @@ mod test { #[tokio::test] async fn test_http_client_download_redirect() { let _http_server_guard = test_util::http_server(); - let client = HttpClient::new(None, None).unwrap(); + let client = HttpClient::new(None, None); // make a request to the redirect server let text = client |