summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/fetch/lib.rs73
-rw-r--r--ext/net/lib.rs17
-rw-r--r--ext/net/ops_tls.rs9
-rw-r--r--ext/tls/lib.rs8
-rw-r--r--ext/websocket/lib.rs22
5 files changed, 89 insertions, 40 deletions
diff --git a/ext/fetch/lib.rs b/ext/fetch/lib.rs
index 17f30d8ed..51688a6fc 100644
--- a/ext/fetch/lib.rs
+++ b/ext/fetch/lib.rs
@@ -3,7 +3,16 @@
mod byte_stream;
mod fs_fetch_handler;
-use data_url::DataUrl;
+use std::borrow::Cow;
+use std::cell::RefCell;
+use std::cmp::min;
+use std::convert::From;
+use std::path::Path;
+use std::path::PathBuf;
+use std::pin::Pin;
+use std::rc::Rc;
+use std::sync::Arc;
+
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::futures::stream::Peekable;
@@ -29,6 +38,9 @@ use deno_core::ResourceId;
use deno_core::ZeroCopyBuf;
use deno_tls::rustls::RootCertStore;
use deno_tls::Proxy;
+use deno_tls::RootCertStoreProvider;
+
+use data_url::DataUrl;
use http::header::CONTENT_LENGTH;
use http::Uri;
use reqwest::header::HeaderMap;
@@ -46,14 +58,6 @@ use reqwest::RequestBuilder;
use reqwest::Response;
use serde::Deserialize;
use serde::Serialize;
-use std::borrow::Cow;
-use std::cell::RefCell;
-use std::cmp::min;
-use std::convert::From;
-use std::path::Path;
-use std::path::PathBuf;
-use std::pin::Pin;
-use std::rc::Rc;
use tokio::sync::mpsc;
// Re-export reqwest and data_url
@@ -67,7 +71,7 @@ use crate::byte_stream::MpscByteStream;
#[derive(Clone)]
pub struct Options {
pub user_agent: String,
- pub root_cert_store: Option<RootCertStore>,
+ pub root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>,
pub proxy: Option<Proxy>,
pub request_builder_hook:
Option<fn(RequestBuilder) -> Result<RequestBuilder, AnyError>>,
@@ -76,11 +80,20 @@ pub struct Options {
pub file_fetch_handler: Rc<dyn FetchHandler>,
}
+impl Options {
+ pub fn root_cert_store(&self) -> Result<Option<RootCertStore>, AnyError> {
+ Ok(match &self.root_cert_store_provider {
+ Some(provider) => Some(provider.get_or_try_init()?.clone()),
+ None => None,
+ })
+ }
+}
+
impl Default for Options {
fn default() -> Self {
Self {
user_agent: "".to_string(),
- root_cert_store: None,
+ root_cert_store_provider: None,
proxy: None,
request_builder_hook: None,
unsafely_ignore_certificate_errors: None,
@@ -111,18 +124,7 @@ deno_core::extension!(deno_fetch,
options: Options,
},
state = |state, options| {
- state.put::<Options>(options.options.clone());
- state.put::<reqwest::Client>({
- create_http_client(
- &options.options.user_agent,
- options.options.root_cert_store,
- vec![],
- options.options.proxy,
- options.options.unsafely_ignore_certificate_errors,
- options.options.client_cert_chain_and_key
- )
- .unwrap()
- });
+ state.put::<Options>(options.options);
},
);
@@ -189,6 +191,26 @@ pub struct FetchReturn {
cancel_handle_rid: Option<ResourceId>,
}
+pub fn get_or_create_client_from_state(
+ state: &mut OpState,
+) -> Result<reqwest::Client, AnyError> {
+ if let Some(client) = state.try_borrow::<reqwest::Client>() {
+ Ok(client.clone())
+ } else {
+ let options = state.borrow::<Options>();
+ let client = create_http_client(
+ &options.user_agent,
+ options.root_cert_store()?,
+ vec![],
+ options.proxy.clone(),
+ options.unsafely_ignore_certificate_errors.clone(),
+ options.client_cert_chain_and_key.clone(),
+ )?;
+ state.put::<reqwest::Client>(client.clone());
+ Ok(client)
+ }
+}
+
#[op]
pub fn op_fetch<FP>(
state: &mut OpState,
@@ -207,8 +229,7 @@ where
let r = state.resource_table.get::<HttpClientResource>(rid)?;
r.client.clone()
} else {
- let client = state.borrow::<reqwest::Client>();
- client.clone()
+ get_or_create_client_from_state(state)?
};
let method = Method::from_bytes(&method)?;
@@ -632,7 +653,7 @@ where
let client = create_http_client(
&options.user_agent,
- options.root_cert_store.clone(),
+ options.root_cert_store()?,
ca_certs,
args.proxy,
options.unsafely_ignore_certificate_errors.clone(),
diff --git a/ext/net/lib.rs b/ext/net/lib.rs
index ff67186b0..912b0723e 100644
--- a/ext/net/lib.rs
+++ b/ext/net/lib.rs
@@ -11,10 +11,12 @@ pub mod resolve_addr;
use deno_core::error::AnyError;
use deno_core::OpState;
use deno_tls::rustls::RootCertStore;
+use deno_tls::RootCertStoreProvider;
use std::cell::RefCell;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;
+use std::sync::Arc;
pub trait NetPermissions {
fn check_net<T: AsRef<str>>(
@@ -67,7 +69,16 @@ pub fn get_declaration() -> PathBuf {
#[derive(Clone)]
pub struct DefaultTlsOptions {
- pub root_cert_store: Option<RootCertStore>,
+ pub root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>,
+}
+
+impl DefaultTlsOptions {
+ pub fn root_cert_store(&self) -> Result<Option<RootCertStore>, AnyError> {
+ Ok(match &self.root_cert_store_provider {
+ Some(provider) => Some(provider.get_or_try_init()?.clone()),
+ None => None,
+ })
+ }
}
/// `UnsafelyIgnoreCertificateErrors` is a wrapper struct so it can be placed inside `GothamState`;
@@ -113,13 +124,13 @@ deno_core::extension!(deno_net,
],
esm = [ "01_net.js", "02_tls.js" ],
options = {
- root_cert_store: Option<RootCertStore>,
+ root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>,
unstable: bool,
unsafely_ignore_certificate_errors: Option<Vec<String>>,
},
state = |state, options| {
state.put(DefaultTlsOptions {
- root_cert_store: options.root_cert_store,
+ root_cert_store_provider: options.root_cert_store_provider,
});
state.put(UnstableChecker { unstable: options.unstable });
state.put(UnsafelyIgnoreCertificateErrors(
diff --git a/ext/net/ops_tls.rs b/ext/net/ops_tls.rs
index 8a7757066..b9b37b328 100644
--- a/ext/net/ops_tls.rs
+++ b/ext/net/ops_tls.rs
@@ -813,14 +813,10 @@ where
.try_borrow::<UnsafelyIgnoreCertificateErrors>()
.and_then(|it| it.0.clone());
- // TODO(@justinmchase): Ideally the certificate store is created once
- // and not cloned. The store should be wrapped in Arc<T> to reduce
- // copying memory unnecessarily.
let root_cert_store = state
.borrow()
.borrow::<DefaultTlsOptions>()
- .root_cert_store
- .clone();
+ .root_cert_store()?;
let resource_rc = state
.borrow_mut()
@@ -912,8 +908,7 @@ where
let root_cert_store = state
.borrow()
.borrow::<DefaultTlsOptions>()
- .root_cert_store
- .clone();
+ .root_cert_store()?;
let hostname_dns = ServerName::try_from(&*addr.hostname)
.map_err(|_| invalid_hostname(&addr.hostname))?;
let connect_addr = resolve_addr(&addr.hostname, addr.port)
diff --git a/ext/tls/lib.rs b/ext/tls/lib.rs
index 123d35acf..3034e2ae9 100644
--- a/ext/tls/lib.rs
+++ b/ext/tls/lib.rs
@@ -34,6 +34,14 @@ use std::io::Cursor;
use std::sync::Arc;
use std::time::SystemTime;
+/// Lazily resolves the root cert store.
+///
+/// This was done because the root cert store is not needed in all cases
+/// and takes a bit of time to initialize.
+pub trait RootCertStoreProvider: Send + Sync {
+ fn get_or_try_init(&self) -> Result<&RootCertStore, AnyError>;
+}
+
// This extension has no runtime apis, it only exports some shared native functions.
deno_core::extension!(deno_tls);
diff --git a/ext/websocket/lib.rs b/ext/websocket/lib.rs
index 2ce141fc9..e03a13789 100644
--- a/ext/websocket/lib.rs
+++ b/ext/websocket/lib.rs
@@ -19,6 +19,7 @@ use deno_core::ZeroCopyBuf;
use deno_net::raw::take_network_stream_resource;
use deno_net::raw::NetworkStream;
use deno_tls::create_client_config;
+use deno_tls::RootCertStoreProvider;
use http::header::CONNECTION;
use http::header::UPGRADE;
use http::HeaderName;
@@ -54,7 +55,17 @@ use fastwebsockets::WebSocket;
mod stream;
#[derive(Clone)]
-pub struct WsRootStore(pub Option<RootCertStore>);
+pub struct WsRootStoreProvider(Option<Arc<dyn RootCertStoreProvider>>);
+
+impl WsRootStoreProvider {
+ pub fn get_or_try_init(&self) -> Result<Option<RootCertStore>, AnyError> {
+ Ok(match &self.0 {
+ Some(provider) => Some(provider.get_or_try_init()?.clone()),
+ None => None,
+ })
+ }
+}
+
#[derive(Clone)]
pub struct WsUserAgent(pub String);
@@ -181,7 +192,10 @@ where
.borrow()
.try_borrow::<UnsafelyIgnoreCertificateErrors>()
.and_then(|it| it.0.clone());
- let root_cert_store = state.borrow().borrow::<WsRootStore>().0.clone();
+ let root_cert_store = state
+ .borrow()
+ .borrow::<WsRootStoreProvider>()
+ .get_or_try_init()?;
let user_agent = state.borrow().borrow::<WsUserAgent>().0.clone();
let uri: Uri = url.parse()?;
let mut request = Request::builder().method(Method::GET).uri(
@@ -525,7 +539,7 @@ deno_core::extension!(deno_websocket,
esm = [ "01_websocket.js", "02_websocketstream.js" ],
options = {
user_agent: String,
- root_cert_store: Option<RootCertStore>,
+ root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>,
unsafely_ignore_certificate_errors: Option<Vec<String>>
},
state = |state, options| {
@@ -533,7 +547,7 @@ deno_core::extension!(deno_websocket,
state.put(UnsafelyIgnoreCertificateErrors(
options.unsafely_ignore_certificate_errors,
));
- state.put::<WsRootStore>(WsRootStore(options.root_cert_store));
+ state.put::<WsRootStoreProvider>(WsRootStoreProvider(options.root_cert_store_provider));
},
);