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:
parent
cbfa98ea0b
commit
5cb1d18439
4 changed files with 37 additions and 11 deletions
|
@ -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"));
|
||||||
|
|
5
cli/tsc/dts/lib.deno.unstable.d.ts
vendored
5
cli/tsc/dts/lib.deno.unstable.d.ts
vendored
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue