Skip to content

Commit

Permalink
refactor(node/http): don't use readablestream for writing to request (d…
Browse files Browse the repository at this point in the history
…enoland#19282)

Refactors the internal usage of a readablestream to write to the
resource directly

---------

Co-authored-by: Bartek Iwańczuk <[email protected]>
  • Loading branch information
crowlKats and bartlomieju authored May 27, 2023
1 parent d0c5ff4 commit be59e93
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 197 deletions.
3 changes: 2 additions & 1 deletion cli/tests/node_compat/config.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,8 @@
"test-child-process-spawnsync-maxbuf.js",
"test-child-process-spawnsync-validation-errors.js",
"test-child-process-spawnsync.js",
"test-client-request-destroy.js",
// TODO(crowlKats): socket is not yet polyfilled
// "test-client-request-destroy.js",
"test-console-async-write-error.js",
"test-console-group.js",
"test-console-log-stdio-broken-dest.js",
Expand Down
20 changes: 0 additions & 20 deletions cli/tests/node_compat/test/parallel/test-client-request-destroy.js

This file was deleted.

15 changes: 14 additions & 1 deletion ext/node/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use deno_core::error::AnyError;
use deno_core::located_script_name;
use deno_core::op;
use deno_core::serde_json;
use deno_core::url::Url;
use deno_core::JsRuntime;
use deno_core::ModuleSpecifier;
use deno_fs::sync::MaybeSend;
Expand Down Expand Up @@ -41,12 +42,24 @@ pub use resolution::NodeResolutionMode;
pub use resolution::NodeResolver;

pub trait NodePermissions {
fn check_net_url(
&mut self,
url: &Url,
api_name: &str,
) -> Result<(), AnyError>;
fn check_read(&self, path: &Path) -> Result<(), AnyError>;
}

pub(crate) struct AllowAllNodePermissions;

impl NodePermissions for AllowAllNodePermissions {
fn check_net_url(
&mut self,
_url: &Url,
_api_name: &str,
) -> Result<(), AnyError> {
Ok(())
}
fn check_read(&self, _path: &Path) -> Result<(), AnyError> {
Ok(())
}
Expand Down Expand Up @@ -206,7 +219,7 @@ deno_core::extension!(deno_node,
ops::zlib::op_zlib_write_async,
ops::zlib::op_zlib_init,
ops::zlib::op_zlib_reset,
ops::http::op_node_http_request,
ops::http::op_node_http_request<P>,
op_node_build_os,
ops::require::op_require_init_paths,
ops::require::op_require_node_module_paths<P>,
Expand Down
12 changes: 10 additions & 2 deletions ext/node/ops/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,17 @@ use reqwest::Body;
use reqwest::Method;

#[op]
pub fn op_node_http_request(
pub fn op_node_http_request<P>(
state: &mut OpState,
method: ByteString,
url: String,
headers: Vec<(ByteString, ByteString)>,
client_rid: Option<u32>,
has_body: bool,
) -> Result<FetchReturn, AnyError> {
) -> Result<FetchReturn, AnyError>
where
P: crate::NodePermissions + 'static,
{
let client = if let Some(rid) = client_rid {
let r = state.resource_table.get::<HttpClientResource>(rid)?;
r.client.clone()
Expand All @@ -42,6 +45,11 @@ pub fn op_node_http_request(
let method = Method::from_bytes(&method)?;
let url = Url::parse(&url)?;

{
let permissions = state.borrow_mut::<P>();
permissions.check_net_url(&url, "ClientRequest")?;
}

let mut header_map = HeaderMap::new();
for (key, value) in headers {
let name = HeaderName::from_bytes(&key)
Expand Down
50 changes: 22 additions & 28 deletions ext/node/polyfills/_http_outgoing.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
// Copyright Joyent and Node contributors. All rights reserved. MIT license.

const core = globalThis.__bootstrap.core;
import { getDefaultHighWaterMark } from "ext:deno_node/internal/streams/state.mjs";
import assert from "ext:deno_node/internal/assert.mjs";
import EE from "ext:deno_node/events.ts";
Expand Down Expand Up @@ -137,12 +138,6 @@ export class OutgoingMessage extends Stream {
this._keepAliveTimeout = 0;

this._onPendingData = nop;

this.stream = new ReadableStream({
start: (controller) => {
this.controller = controller;
},
});
}

get writableFinished() {
Expand Down Expand Up @@ -374,21 +369,30 @@ export class OutgoingMessage extends Stream {
return headers;
}

controller: ReadableStreamDefaultController;
write(
chunk: string | Uint8Array | Buffer,
encoding: string | null,
// TODO(crowlKats): use callback
_callback: () => void,
callback: () => void,
): boolean {
if (typeof chunk === "string") {
chunk = Buffer.from(chunk, encoding);
}
if (chunk instanceof Buffer) {
chunk = new Uint8Array(chunk.buffer);
}
if (
(typeof chunk === "string" && chunk.length > 0) ||
((chunk instanceof Buffer || chunk instanceof Uint8Array) &&
chunk.buffer.byteLength > 0)
) {
if (typeof chunk === "string") {
chunk = Buffer.from(chunk, encoding);
}
if (chunk instanceof Buffer) {
chunk = new Uint8Array(chunk.buffer);
}

this.controller.enqueue(chunk);
core.writeAll(this._bodyWriteRid, chunk).then(() => {
callback?.();
this.emit("drain");
}).catch((e) => {
this._requestSendError = e;
});
}

return false;
}
Expand All @@ -400,18 +404,8 @@ export class OutgoingMessage extends Stream {
}

// deno-lint-ignore no-explicit-any
end(chunk: any, encoding: any, _callback: any) {
if (typeof chunk === "function") {
callback = chunk;
chunk = null;
encoding = null;
} else if (typeof encoding === "function") {
callback = encoding;
encoding = null;
}
// TODO(crowlKats): finish

return this;
end(_chunk: any, _encoding: any, _callback: any) {
notImplemented("OutgoingMessage.end");
}

flushHeaders() {
Expand Down
Loading

0 comments on commit be59e93

Please sign in to comment.