summaryrefslogtreecommitdiff
path: root/ext/http/http_next.rs
diff options
context:
space:
mode:
authorMatt Mastracci <matthew@mastracci.com>2023-08-17 07:52:37 -0600
committerGitHub <noreply@github.com>2023-08-17 07:52:37 -0600
commit23ff0e722e3c4b0827940853c53c5ee2ede5ec9f (patch)
tree1521ffd2ac5e803224546cb349b3905925b9b5ff /ext/http/http_next.rs
parent0960e895da1275792c1f38999f6a185c864edb3f (diff)
feat(ext/web): resourceForReadableStream (#20180)
Extracted from fast streams work. This is a resource wrapper for `ReadableStream`, allowing us to treat all `ReadableStream` instances as resources, and remove special paths in both `fetch` and `serve`. Performance with a ReadableStream response yields ~18% improvement: ``` return new Response(new ReadableStream({ start(controller) { controller.enqueue(new Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100])); controller.close(); } }) ``` This patch: ``` 12:36 $ third_party/prebuilt/mac/wrk http://localhost:8080 Running 10s test @ http://localhost:8080 2 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 99.96us 100.03us 6.65ms 98.84% Req/Sec 47.73k 2.43k 51.02k 89.11% 959308 requests in 10.10s, 117.10MB read Requests/sec: 94978.71 Transfer/sec: 11.59MB ``` main: ``` Running 10s test @ http://localhost:8080 2 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 163.03us 685.51us 19.73ms 99.27% Req/Sec 39.50k 3.98k 66.11k 95.52% 789582 requests in 10.10s, 82.83MB read Requests/sec: 78182.65 Transfer/sec: 8.20MB ```
Diffstat (limited to 'ext/http/http_next.rs')
-rw-r--r--ext/http/http_next.rs48
1 files changed, 25 insertions, 23 deletions
diff --git a/ext/http/http_next.rs b/ext/http/http_next.rs
index 2e9b315ca..60ef83b0f 100644
--- a/ext/http/http_next.rs
+++ b/ext/http/http_next.rs
@@ -10,7 +10,6 @@ use crate::request_properties::HttpPropertyExtractor;
use crate::response_body::Compression;
use crate::response_body::ResponseBytes;
use crate::response_body::ResponseBytesInner;
-use crate::response_body::V8StreamHttpResponseBody;
use crate::slab::slab_drop;
use crate::slab::slab_get;
use crate::slab::slab_init;
@@ -30,6 +29,7 @@ use deno_core::task::JoinHandle;
use deno_core::v8;
use deno_core::AsyncRefCell;
use deno_core::AsyncResult;
+use deno_core::BufView;
use deno_core::ByteString;
use deno_core::CancelFuture;
use deno_core::CancelHandle;
@@ -573,6 +573,7 @@ fn ensure_vary_accept_encoding(hmap: &mut HeaderMap) {
fn set_response(
slab_id: SlabId,
length: Option<usize>,
+ status: u16,
response_fn: impl FnOnce(Compression) -> ResponseBytesInner,
) {
let mut http = slab_get(slab_id);
@@ -583,7 +584,14 @@ fn set_response(
length,
response.headers_mut(),
);
- response.body_mut().initialize(response_fn(compression))
+ response.body_mut().initialize(response_fn(compression));
+
+ // The Javascript code should never provide a status that is invalid here (see 23_response.js), so we
+ // will quitely ignore invalid values.
+ if let Ok(code) = StatusCode::from_u16(status) {
+ *response.status_mut() = code;
+ }
+ http.complete();
}
#[op2(fast)]
@@ -592,6 +600,7 @@ pub fn op_http_set_response_body_resource(
#[smi] slab_id: SlabId,
#[smi] stream_rid: ResourceId,
auto_close: bool,
+ status: u16,
) -> Result<(), AnyError> {
// If the stream is auto_close, we will hold the last ref to it until the response is complete.
let resource = if auto_close {
@@ -603,6 +612,7 @@ pub fn op_http_set_response_body_resource(
set_response(
slab_id,
resource.size_hint().1.map(|s| s as usize),
+ status,
move |compression| {
ResponseBytesInner::from_resource(compression, resource, auto_close)
},
@@ -612,42 +622,34 @@ pub fn op_http_set_response_body_resource(
}
#[op2(fast)]
-#[smi]
-pub fn op_http_set_response_body_stream(
- state: &mut OpState,
- #[smi] slab_id: SlabId,
-) -> Result<ResourceId, AnyError> {
- // TODO(mmastrac): what should this channel size be?
- let (tx, rx) = tokio::sync::mpsc::channel(1);
- set_response(slab_id, None, |compression| {
- ResponseBytesInner::from_v8(compression, rx)
- });
-
- Ok(state.resource_table.add(V8StreamHttpResponseBody::new(tx)))
-}
-
-#[op2(fast)]
pub fn op_http_set_response_body_text(
#[smi] slab_id: SlabId,
#[string] text: String,
+ status: u16,
) {
if !text.is_empty() {
- set_response(slab_id, Some(text.len()), |compression| {
+ set_response(slab_id, Some(text.len()), status, |compression| {
ResponseBytesInner::from_vec(compression, text.into_bytes())
});
+ } else {
+ op_http_set_promise_complete::call(slab_id, status);
}
}
-#[op2(fast)]
+// Skipping `fast` because we prefer an owned buffer here.
+#[op2]
pub fn op_http_set_response_body_bytes(
#[smi] slab_id: SlabId,
- #[buffer] buffer: &[u8],
+ #[buffer] buffer: JsBuffer,
+ status: u16,
) {
if !buffer.is_empty() {
- set_response(slab_id, Some(buffer.len()), |compression| {
- ResponseBytesInner::from_slice(compression, buffer)
+ set_response(slab_id, Some(buffer.len()), status, |compression| {
+ ResponseBytesInner::from_bufview(compression, BufView::from(buffer))
});
- };
+ } else {
+ op_http_set_promise_complete::call(slab_id, status);
+ }
}
#[op2(async)]