From 6130cb70a3d39581d237438fc1ef6a9de952b29b Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 4 Jul 2022 07:41:52 +0530 Subject: [PATCH] perf(ext/http): lazy load headers (#15055) --- ext/fetch/23_request.js | 37 +++++++++++++++++++++++++++++++------ ext/http/01_http.js | 4 ++-- ext/http/lib.rs | 21 +++++++++++++++++---- 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/ext/fetch/23_request.js b/ext/fetch/23_request.js index b61f46c61d..3058db6f71 100644 --- a/ext/fetch/23_request.js +++ b/ext/fetch/23_request.js @@ -43,6 +43,8 @@ const _request = Symbol("request"); const _headers = Symbol("headers"); + const _getHeaders = Symbol("get headers"); + const _headersCache = Symbol("headers cache"); const _signal = Symbol("signal"); const _mimeType = Symbol("mime type"); const _body = Symbol("body"); @@ -52,7 +54,7 @@ * @property {string} method * @property {() => string} url * @property {() => string} currentUrl - * @property {[string, string][]} headerList + * @property {() => [string, string][]} headerList * @property {null | typeof __window.bootstrap.fetchBody.InnerBody} body * @property {"follow" | "error" | "manual"} redirectMode * @property {number} redirectCount @@ -64,7 +66,7 @@ /** * @param {string} method * @param {string} url - * @param {[string, string][]} headerList + * @param {() => [string, string][]} headerList * @param {typeof __window.bootstrap.fetchBody.InnerBody} body * @param {boolean} maybeBlob * @returns @@ -76,7 +78,16 @@ } return { method, - headerList, + headerListInner: null, + get headerList() { + if (this.headerListInner === null) { + this.headerListInner = headerList(); + } + return this.headerListInner; + }, + set headerList(value) { + this.headerListInner = value; + }, body, redirectMode: "follow", redirectCount: 0, @@ -167,7 +178,21 @@ /** @type {InnerRequest} */ [_request]; /** @type {Headers} */ - [_headers]; + [_headersCache]; + [_getHeaders]; + + /** @type {Headers} */ + get [_headers]() { + if (this[_headersCache] === undefined) { + this[_headersCache] = this[_getHeaders](); + } + return this[_headersCache]; + } + + set [_headers](value) { + this[_headersCache] = value; + } + /** @type {AbortSignal} */ [_signal]; get [_mimeType]() { @@ -210,7 +235,7 @@ // 5. if (typeof input === "string") { const parsedURL = new URL(input, baseURL); - request = newInnerRequest("GET", parsedURL.href, [], null, true); + request = newInnerRequest("GET", parsedURL.href, () => [], null, true); } else { // 6. if (!ObjectPrototypeIsPrototypeOf(RequestPrototype, input)) { throw new TypeError("Unreachable"); @@ -451,7 +476,7 @@ const request = webidl.createBranded(Request); request[_request] = inner; request[_signal] = signal; - request[_headers] = headersFromHeaderList(inner.headerList, guard); + request[_getHeaders] = () => headersFromHeaderList(inner.headerList, guard); return request; } diff --git a/ext/http/01_http.js b/ext/http/01_http.js index de546285d3..877342428e 100644 --- a/ext/http/01_http.js +++ b/ext/http/01_http.js @@ -111,7 +111,7 @@ return null; } - const [streamRid, method, headersList, url] = nextRequest; + const [streamRid, method, url] = nextRequest; SetPrototypeAdd(this.managedResources, streamRid); /** @type {ReadableStream | undefined} */ @@ -126,7 +126,7 @@ const innerRequest = newInnerRequest( method, url, - headersList, + () => core.opSync("op_http_headers", streamRid), body !== null ? new InnerBody(body) : null, false, ); diff --git a/ext/http/lib.rs b/ext/http/lib.rs index 918e48120c..ce41a7ef2f 100644 --- a/ext/http/lib.rs +++ b/ext/http/lib.rs @@ -79,6 +79,7 @@ pub fn init() -> Extension { op_http_accept::decl(), op_http_read::decl(), op_http_write_headers::decl(), + op_http_headers::decl(), op_http_write::decl(), op_http_write_resource::decl(), op_http_shutdown::decl(), @@ -365,8 +366,6 @@ struct NextRequestResponse( // This is a String rather than a ByteString because reqwest will only return // the method as a str which is guaranteed to be ASCII-only. String, - // headers: - Vec<(ByteString, ByteString)>, // url: String, ); @@ -403,12 +402,11 @@ async fn op_http_accept( }); let method = request.method().to_string(); - let headers = req_headers(request); let url = req_url(request, conn.scheme(), conn.addr()); let stream_rid = state.borrow_mut().resource_table.add_rc(stream); - let r = NextRequestResponse(stream_rid, method, headers, url); + let r = NextRequestResponse(stream_rid, method, url); Ok(Some(r)) } @@ -561,6 +559,21 @@ async fn op_http_write_headers( } } +#[op] +fn op_http_headers( + state: &mut OpState, + rid: u32, +) -> Result, AnyError> { + let stream = state.resource_table.get::(rid)?; + let rd = RcRef::map(&stream, |r| &r.rd) + .try_borrow() + .ok_or_else(|| http_error("already in use"))?; + match &*rd { + HttpRequestReader::Headers(request) => Ok(req_headers(request)), + _ => unreachable!(), + } +} + fn http_response( data: Option, compressing: bool,