1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-25 15:29:32 -05:00

feat: Deno.createHttpClient allowHost (#19689)

This adds an option to allow using the host header in a fetch call.
Closes https://github.com/denoland/deno/issues/16840
Ref https://github.com/denoland/deno/issues/11017
This commit is contained in:
Leo Kettmeir 2023-07-28 09:01:06 +02:00 committed by GitHub
parent cbfa98ea0b
commit 5cb1d18439
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 11 deletions

View file

@ -1569,6 +1569,25 @@ Deno.test(
}, },
); );
Deno.test(
{ permissions: { net: true, read: true } },
async function createHttpClientAllowHost() {
const client = Deno.createHttpClient({
allowHost: true,
});
const res = await fetch("http://localhost:4545/echo_server", {
headers: {
"host": "example.com",
},
client,
});
assert(res.ok);
assertEquals(res.headers.get("host"), "example.com");
await res.body?.cancel();
client.close();
},
);
Deno.test({ permissions: { read: false } }, async function fetchFilePerm() { Deno.test({ permissions: { read: false } }, async function fetchFilePerm() {
await assertRejects(async () => { await assertRejects(async () => {
await fetch(import.meta.resolve("../testdata/subdir/json_1.json")); await fetch(import.meta.resolve("../testdata/subdir/json_1.json"));

View file

@ -837,6 +837,11 @@ declare namespace Deno {
* @default {true} * @default {true}
*/ */
http2?: boolean; http2?: boolean;
/** Whether setting the host header is allowed or not.
*
* @default {false}
*/
allowHost?: boolean;
} }
/** **UNSTABLE**: New API, yet to be vetted. /** **UNSTABLE**: New API, yet to be vetted.

View file

@ -237,11 +237,11 @@ pub fn op_fetch<FP>(
where where
FP: FetchPermissions + 'static, FP: FetchPermissions + 'static,
{ {
let client = if let Some(rid) = client_rid { let (client, allow_host) = if let Some(rid) = client_rid {
let r = state.resource_table.get::<HttpClientResource>(rid)?; let r = state.resource_table.get::<HttpClientResource>(rid)?;
r.client.clone() (r.client.clone(), r.allow_host)
} else { } else {
get_or_create_client_from_state(state)? (get_or_create_client_from_state(state)?, false)
}; };
let method = Method::from_bytes(&method)?; let method = Method::from_bytes(&method)?;
@ -334,7 +334,7 @@ where
let v = HeaderValue::from_bytes(&value) let v = HeaderValue::from_bytes(&value)
.map_err(|err| type_error(err.to_string()))?; .map_err(|err| type_error(err.to_string()))?;
if !matches!(name, HOST | CONTENT_LENGTH) { if (name != HOST || allow_host) && name != CONTENT_LENGTH {
header_map.append(name, v); header_map.append(name, v);
} }
} }
@ -761,6 +761,7 @@ impl Resource for FetchResponseResource {
pub struct HttpClientResource { pub struct HttpClientResource {
pub client: Client, pub client: Client,
pub allow_host: bool,
} }
impl Resource for HttpClientResource { impl Resource for HttpClientResource {
@ -770,8 +771,8 @@ impl Resource for HttpClientResource {
} }
impl HttpClientResource { impl HttpClientResource {
fn new(client: Client) -> Self { fn new(client: Client, allow_host: bool) -> Self {
Self { client } Self { client, allow_host }
} }
} }
@ -795,6 +796,8 @@ pub struct CreateHttpClientArgs {
http1: bool, http1: bool,
#[serde(default = "default_true")] #[serde(default = "default_true")]
http2: bool, http2: bool,
#[serde(default)]
allow_host: bool,
} }
fn default_true() -> bool { fn default_true() -> bool {
@ -860,7 +863,9 @@ where
}, },
)?; )?;
let rid = state.resource_table.add(HttpClientResource::new(client)); let rid = state
.resource_table
.add(HttpClientResource::new(client, args.allow_host));
Ok(rid) Ok(rid)
} }

View file

@ -728,10 +728,7 @@ async fn main_server(
req: Request<Body>, req: Request<Body>,
) -> Result<Response<Body>, hyper::http::Error> { ) -> Result<Response<Body>, hyper::http::Error> {
return match (req.method(), req.uri().path()) { return match (req.method(), req.uri().path()) {
( (_, "/echo_server") => {
&hyper::Method::POST | &hyper::Method::PATCH | &hyper::Method::PUT,
"/echo_server",
) => {
let (parts, body) = req.into_parts(); let (parts, body) = req.into_parts();
let mut response = Response::new(body); let mut response = Response::new(body);