mirror of
https://github.com/denoland/deno.git
synced 2024-12-24 08:09:08 -05:00
fix: fallback to default UA and CA data for Deno.createHttpClient() (#9830)
This commit is contained in:
parent
fb5a2786ec
commit
7d12dd1899
5 changed files with 69 additions and 57 deletions
|
@ -1063,6 +1063,27 @@ MNf4EgWfK+tZMnuqfpfO9740KzfcVoMNo4QJD4yn5YxroUOO/Azi
|
|||
},
|
||||
);
|
||||
|
||||
unitTest(
|
||||
{ perms: { net: true } },
|
||||
async function fetchCustomClientUserAgent(): Promise<
|
||||
void
|
||||
> {
|
||||
const data = "Hello World";
|
||||
const client = Deno.createHttpClient({});
|
||||
const response = await fetch("http://localhost:4545/echo_server", {
|
||||
client,
|
||||
method: "POST",
|
||||
body: new TextEncoder().encode(data),
|
||||
});
|
||||
assertEquals(
|
||||
response.headers.get("user-agent"),
|
||||
`Deno/${Deno.version.deno}`,
|
||||
);
|
||||
await response.text();
|
||||
client.close();
|
||||
},
|
||||
);
|
||||
|
||||
unitTest(
|
||||
{
|
||||
perms: { net: true },
|
||||
|
|
|
@ -23,8 +23,10 @@ use deno_core::RcRef;
|
|||
use deno_core::Resource;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
|
||||
use reqwest::header::HeaderMap;
|
||||
use reqwest::header::HeaderName;
|
||||
use reqwest::header::HeaderValue;
|
||||
use reqwest::header::USER_AGENT;
|
||||
use reqwest::redirect::Policy;
|
||||
use reqwest::Body;
|
||||
use reqwest::Client;
|
||||
|
@ -80,6 +82,11 @@ pub fn init(isolate: &mut JsRuntime) {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct HttpClientDefaults {
|
||||
pub user_agent: String,
|
||||
pub ca_data: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
pub trait FetchPermissions {
|
||||
fn check_net_url(&self, _url: &Url) -> Result<(), AnyError>;
|
||||
fn check_read(&self, _p: &Path) -> Result<(), AnyError>;
|
||||
|
@ -399,31 +406,53 @@ where
|
|||
permissions.check_read(&PathBuf::from(ca_file))?;
|
||||
}
|
||||
|
||||
let client =
|
||||
create_http_client(args.ca_file.as_deref(), args.ca_data.as_deref())
|
||||
let defaults = state.borrow::<HttpClientDefaults>();
|
||||
|
||||
let cert_data =
|
||||
get_cert_data(args.ca_file.as_deref(), args.ca_data.as_deref())?;
|
||||
let client = create_http_client(
|
||||
defaults.user_agent.clone(),
|
||||
cert_data.or_else(|| defaults.ca_data.clone()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let rid = state.resource_table.add(HttpClientResource::new(client));
|
||||
Ok(json!(rid))
|
||||
}
|
||||
|
||||
/// Create new instance of async reqwest::Client. This client supports
|
||||
/// proxies and doesn't follow redirects.
|
||||
fn create_http_client(
|
||||
fn get_cert_data(
|
||||
ca_file: Option<&str>,
|
||||
ca_data: Option<&str>,
|
||||
) -> Result<Client, AnyError> {
|
||||
let mut builder = Client::builder().redirect(Policy::none()).use_rustls_tls();
|
||||
) -> Result<Option<Vec<u8>>, AnyError> {
|
||||
if let Some(ca_data) = ca_data {
|
||||
let ca_data_vec = ca_data.as_bytes().to_vec();
|
||||
let cert = reqwest::Certificate::from_pem(&ca_data_vec)?;
|
||||
builder = builder.add_root_certificate(cert);
|
||||
Ok(Some(ca_data.as_bytes().to_vec()))
|
||||
} else if let Some(ca_file) = ca_file {
|
||||
let mut buf = Vec::new();
|
||||
File::open(ca_file)?.read_to_end(&mut buf)?;
|
||||
let cert = reqwest::Certificate::from_pem(&buf)?;
|
||||
Ok(Some(buf))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create new instance of async reqwest::Client. This client supports
|
||||
/// proxies and doesn't follow redirects.
|
||||
pub fn create_http_client(
|
||||
user_agent: String,
|
||||
ca_data: Option<Vec<u8>>,
|
||||
) -> Result<Client, AnyError> {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert(USER_AGENT, user_agent.parse().unwrap());
|
||||
let mut builder = Client::builder()
|
||||
.redirect(Policy::none())
|
||||
.default_headers(headers)
|
||||
.use_rustls_tls();
|
||||
|
||||
if let Some(ca_data) = ca_data {
|
||||
let cert = reqwest::Certificate::from_pem(&ca_data)?;
|
||||
builder = builder.add_root_certificate(cert);
|
||||
}
|
||||
|
||||
builder
|
||||
.build()
|
||||
.map_err(|e| generic_error(format!("Unable to build http client: {}", e)))
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::generic_error;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_fetch::reqwest;
|
||||
use deno_fetch::reqwest::header::HeaderMap;
|
||||
use deno_fetch::reqwest::header::USER_AGENT;
|
||||
use deno_fetch::reqwest::redirect::Policy;
|
||||
use deno_fetch::reqwest::Client;
|
||||
|
||||
/// Create new instance of async reqwest::Client. This client supports
|
||||
/// proxies and doesn't follow redirects.
|
||||
pub fn create_http_client(
|
||||
user_agent: String,
|
||||
ca_data: Option<Vec<u8>>,
|
||||
) -> Result<Client, AnyError> {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert(USER_AGENT, user_agent.parse().unwrap());
|
||||
let mut builder = Client::builder()
|
||||
.redirect(Policy::none())
|
||||
.default_headers(headers)
|
||||
.use_rustls_tls();
|
||||
|
||||
if let Some(ca_data) = ca_data {
|
||||
let cert = reqwest::Certificate::from_pem(&ca_data)?;
|
||||
builder = builder.add_root_certificate(cert);
|
||||
}
|
||||
|
||||
builder
|
||||
.build()
|
||||
.map_err(|e| generic_error(format!("Unable to build http client: {}", e)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn create_test_client() {
|
||||
create_http_client("test_client".to_string(), None).unwrap();
|
||||
}
|
||||
}
|
|
@ -19,7 +19,6 @@ pub use deno_websocket;
|
|||
pub mod colors;
|
||||
pub mod errors;
|
||||
pub mod fs_util;
|
||||
pub mod http_util;
|
||||
pub mod inspector;
|
||||
pub mod js;
|
||||
pub mod metrics;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::http_util;
|
||||
use crate::permissions::Permissions;
|
||||
use deno_fetch::reqwest;
|
||||
use deno_fetch::HttpClientDefaults;
|
||||
|
||||
pub fn init(
|
||||
rt: &mut deno_core::JsRuntime,
|
||||
|
@ -12,7 +12,12 @@ pub fn init(
|
|||
let op_state = rt.op_state();
|
||||
let mut state = op_state.borrow_mut();
|
||||
state.put::<reqwest::Client>({
|
||||
http_util::create_http_client(user_agent, ca_data).unwrap()
|
||||
deno_fetch::create_http_client(user_agent.clone(), ca_data.clone())
|
||||
.unwrap()
|
||||
});
|
||||
state.put::<HttpClientDefaults>(HttpClientDefaults {
|
||||
ca_data,
|
||||
user_agent,
|
||||
});
|
||||
}
|
||||
super::reg_json_sync(rt, "op_fetch", deno_fetch::op_fetch::<Permissions>);
|
||||
|
|
Loading…
Reference in a new issue