1
0
Fork 0
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:
Aaron O'Mullan 2021-03-18 23:54:26 +01:00 committed by GitHub
parent fb5a2786ec
commit 7d12dd1899
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 69 additions and 57 deletions

View file

@ -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 },

View file

@ -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)))

View file

@ -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();
}
}

View file

@ -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;

View file

@ -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>);