From 554d6ba649d1211c30772988f99e9488cc01ca01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Og=C3=B3rek?= Date: Fri, 2 Jun 2023 17:59:16 +0200 Subject: [PATCH] perf(ext/http): Use flat list of headers for multiple set/get methods (#19336) This PR attempts to resolve the first item on the list from https://github.com/denoland/deno/issues/19330 which is about using a flat list of interleaved key/value pairs, instead of a nested array of tuples. I can tackle some more if you can provide a quick example of using raw v8 arrays, cc @mmastrac --- ext/http/00_serve.js | 9 +++++++-- ext/http/http_next.rs | 28 ++++++++++++---------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/ext/http/00_serve.js b/ext/http/00_serve.js index d84244ee4b..dbdc227056 100644 --- a/ext/http/00_serve.js +++ b/ext/http/00_serve.js @@ -334,7 +334,12 @@ class InnerRequest { if (this.#slabId === undefined) { throw new TypeError("request closed"); } - return op_http_get_request_headers(this.#slabId); + const headers = []; + const reqHeaders = op_http_get_request_headers(this.#slabId); + for (let i = 0; i < reqHeaders.length; i += 2) { + headers.push([reqHeaders[i], reqHeaders[i + 1]]); + } + return headers; } get slabId() { @@ -570,7 +575,7 @@ function mapToCallback(context, callback, onError) { if (headers.length == 1) { op_http_set_response_header(req, headers[0][0], headers[0][1]); } else { - op_http_set_response_headers(req, headers); + op_http_set_response_headers(req, headers.flat()); } } diff --git a/ext/http/http_next.rs b/ext/http/http_next.rs index 7a02757c00..9ec9e12c9d 100644 --- a/ext/http/http_next.rs +++ b/ext/http/http_next.rs @@ -256,12 +256,11 @@ pub fn op_http_get_request_header( } #[op] -pub fn op_http_get_request_headers( - slab_id: SlabId, -) -> Vec<(ByteString, ByteString)> { +pub fn op_http_get_request_headers(slab_id: SlabId) -> Vec { let http = slab_get(slab_id); let headers = &http.request_parts().headers; - let mut vec = Vec::with_capacity(headers.len()); + // Two slots for each header key/value pair + let mut vec = Vec::with_capacity(headers.len() * 2); let mut cookies: Option> = None; for (name, value) in headers { if name == COOKIE { @@ -272,7 +271,8 @@ pub fn op_http_get_request_headers( } } else { let name: &[u8] = name.as_ref(); - vec.push((name.into(), value.as_bytes().into())) + vec.push(name.into()); + vec.push(value.as_bytes().into()); } } @@ -283,11 +283,10 @@ pub fn op_http_get_request_headers( // TODO(mmastrac): This should probably happen on the JS side on-demand if let Some(cookies) = cookies { let cookie_sep = "; ".as_bytes(); - vec.push(( - ByteString::from(COOKIE.as_str()), - ByteString::from(cookies.join(cookie_sep)), - )); + vec.push(ByteString::from(COOKIE.as_str())); + vec.push(ByteString::from(cookies.join(cookie_sep))); } + vec } @@ -313,18 +312,15 @@ pub fn op_http_set_response_header(slab_id: SlabId, name: &str, value: &str) { } #[op] -pub fn op_http_set_response_headers( - slab_id: SlabId, - headers: Vec<(ByteString, ByteString)>, -) { +pub fn op_http_set_response_headers(slab_id: SlabId, headers: Vec) { let mut http = slab_get(slab_id); // TODO(mmastrac): Invalid headers should be handled? let resp_headers = http.response().headers_mut(); resp_headers.reserve(headers.len()); - for (name, value) in headers { + for header in headers.chunks_exact(2) { // These are valid latin-1 strings - let name = HeaderName::from_bytes(&name).unwrap(); - let value = HeaderValue::from_bytes(&value).unwrap(); + let name = HeaderName::from_bytes(&header[0]).unwrap(); + let value = HeaderValue::from_bytes(&header[1]).unwrap(); resp_headers.append(name, value); } }