diff --git a/ext/node/ops/http.rs b/ext/node/ops/http.rs
index 57bcf69a47..1da630f97e 100644
--- a/ext/node/ops/http.rs
+++ b/ext/node/ops/http.rs
@@ -113,6 +113,9 @@ pub enum ConnError {
#[error("Invalid URL {0}")]
InvalidUrl(Url),
#[class(type)]
+ #[error("Invalid Path {0}")]
+ InvalidPath(String),
+ #[class(type)]
#[error(transparent)]
InvalidHeaderName(#[from] http::header::InvalidHeaderName),
#[class(type)]
@@ -150,6 +153,7 @@ pub async fn op_node_http_request_with_conn
(
state: Rc>,
#[serde] method: ByteString,
#[string] url: String,
+ #[string] request_path: Option,
#[serde] headers: Vec<(ByteString, ByteString)>,
#[smi] body: Option,
#[smi] conn_rid: ResourceId,
@@ -247,11 +251,17 @@ where
*request.method_mut() = method.clone();
let path = url_parsed.path();
let query = url_parsed.query();
- *request.uri_mut() = query
- .map(|q| format!("{}?{}", path, q))
- .unwrap_or_else(|| path.to_string())
- .parse()
- .map_err(|_| ConnError::InvalidUrl(url_parsed.clone()))?;
+ if let Some(request_path) = request_path {
+ *request.uri_mut() = request_path
+ .parse()
+ .map_err(|_| ConnError::InvalidPath(request_path.clone()))?;
+ } else {
+ *request.uri_mut() = query
+ .map(|q| format!("{}?{}", path, q))
+ .unwrap_or_else(|| path.to_string())
+ .parse()
+ .map_err(|_| ConnError::InvalidUrl(url_parsed.clone()))?;
+ }
*request.headers_mut() = header_map;
if let Some((username, password)) = maybe_authority {
diff --git a/ext/node/polyfills/http.ts b/ext/node/polyfills/http.ts
index dd94c9d025..0438f9af22 100644
--- a/ext/node/polyfills/http.ts
+++ b/ext/node/polyfills/http.ts
@@ -479,6 +479,7 @@ class ClientRequest extends OutgoingMessage {
this._req = await op_node_http_request_with_conn(
this.method,
url,
+ this._createRequestPath(),
headers,
this._bodyWriteRid,
baseConnRid,
@@ -817,6 +818,15 @@ class ClientRequest extends OutgoingMessage {
return url.href;
}
+ _createRequestPath(): string | undefined {
+ // If the path starts with protocol, pass this to op_node_http_request_with_conn
+ // This will be used as Request.uri in hyper for supporting http proxy
+ if (this.path?.startsWith("http://") || this.path?.startsWith("https://")) {
+ return this.path;
+ }
+ return undefined;
+ }
+
setTimeout(msecs: number, callback?: () => void) {
if (msecs === 0) {
if (this._timeout) {
diff --git a/tests/unit_node/http_test.ts b/tests/unit_node/http_test.ts
index b4f0d260aa..54803ab995 100644
--- a/tests/unit_node/http_test.ts
+++ b/tests/unit_node/http_test.ts
@@ -1892,3 +1892,27 @@ Deno.test("[node/http] an error with DNS propagates to request object", async ()
});
await promise;
});
+
+Deno.test("[node/http] supports proxy http request", async () => {
+ const { promise, resolve } = Promise.withResolvers();
+ const server = Deno.serve({ port: 0, onListen }, (req) => {
+ console.log("server received", req.url);
+ assertEquals(req.url, "http://example.com/");
+ return new Response("ok");
+ });
+
+ function onListen({ port }: { port: number }) {
+ http.request({
+ host: "localhost",
+ port,
+ path: "http://example.com",
+ }, async (res) => {
+ assertEquals(res.statusCode, 200);
+ assertEquals(await text(res), "ok");
+ resolve();
+ server.shutdown();
+ }).end();
+ }
+ await promise;
+ await server.finished;
+});