From 06e14d93e8e20a5c09f3e5cf6f44df9c748fe133 Mon Sep 17 00:00:00 2001 From: tsctx <91457664+tsctx@users.noreply.github.com> Date: Fri, 1 Mar 2024 23:48:43 +0900 Subject: [PATCH] WIP --- lib/web/fetch/body.js | 37 ++++++++++++++++++++++++++----------- lib/web/fetch/index.js | 2 +- lib/web/fetch/request.js | 15 +++++++++------ lib/web/fetch/response.js | 14 ++++++++------ 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/lib/web/fetch/body.js b/lib/web/fetch/body.js index 932df3e6532..c6219d0ab3a 100644 --- a/lib/web/fetch/body.js +++ b/lib/web/fetch/body.js @@ -27,6 +27,10 @@ const File = NativeFile ?? UndiciFile const textEncoder = new TextEncoder() const textDecoder = new TextDecoder() +// https://github.com/nodejs/node/issues/44985 +// fix-patch: https://github.com/nodejs/node/pull/51526 +const needReadableStreamTee = util.nodeMajor <= 20 || (util.nodeMajor === 21 && util.nodeMinor <= 6) + // https://fetch.spec.whatwg.org/#concept-bodyinit-extract function extractBody (object, keepalive = false) { // 1. Let stream be null. @@ -125,17 +129,21 @@ function extractBody (object, keepalive = false) { for (const [name, value] of object) { if (typeof value === 'string') { - const chunk = textEncoder.encode(prefix + - `; name="${escape(normalizeLinefeeds(name))}"` + - `\r\n\r\n${normalizeLinefeeds(value)}\r\n`) + const chunk = textEncoder.encode( + `${prefix}; name="${escape( + normalizeLinefeeds(name) + )}"\r\n\r\n${normalizeLinefeeds(value)}\r\n` + ) blobParts.push(chunk) length += chunk.byteLength } else { - const chunk = textEncoder.encode(`${prefix}; name="${escape(normalizeLinefeeds(name))}"` + - (value.name ? `; filename="${escape(value.name)}"` : '') + '\r\n' + - `Content-Type: ${ + const chunk = textEncoder.encode( + `${prefix}; name="${escape(normalizeLinefeeds(name))}"${ + value.name ? `; filename="${escape(value.name)}"` : '' + }\r\nContent-Type: ${ value.type || 'application/octet-stream' - }\r\n\r\n`) + }\r\n\r\n` + ) blobParts.push(chunk, value, rn) if (typeof value.size === 'number') { length += chunk.byteLength + value.size + rn.byteLength @@ -276,16 +284,23 @@ function cloneBody (body) { // 1. Let « out1, out2 » be the result of teeing body’s stream. const [out1, out2] = body.stream.tee() const out2Clone = structuredClone(out2, { transfer: [out2] }) - // This, for whatever reasons, unrefs out2Clone which allows - // the process to exit by itself. - const [, finalClone] = out2Clone.tee() + let streamClone + + if (needReadableStreamTee) { + // This, for whatever reasons, unrefs out2Clone which allows + // the process to exit by itself. + const { 1: finalClone } = out2Clone.tee() + streamClone = finalClone + } else { + streamClone = out2Clone + } // 2. Set body’s stream to out1. body.stream = out1 // 3. Return a body whose stream is out2 and other members are copied from body. return { - stream: finalClone, + stream: streamClone, length: body.length, source: body.source } diff --git a/lib/web/fetch/index.js b/lib/web/fetch/index.js index 37e269fbc93..2385ad12a5f 100644 --- a/lib/web/fetch/index.js +++ b/lib/web/fetch/index.js @@ -1475,7 +1475,7 @@ async function httpNetworkOrCacheFetch ( // user agents should append `User-Agent`/default `User-Agent` value to // httpRequest’s header list. if (!httpRequest.headersList.contains('user-agent', true)) { - httpRequest.headersList.append('user-agent', defaultUserAgent) + httpRequest.headersList.append('user-agent', defaultUserAgent, true) } // 15. If httpRequest’s cache mode is "default" and httpRequest’s header diff --git a/lib/web/fetch/request.js b/lib/web/fetch/request.js index afe92499267..db182e9a5a9 100644 --- a/lib/web/fetch/request.js +++ b/lib/web/fetch/request.js @@ -50,7 +50,7 @@ class Request { webidl.argumentLengthCheck(arguments, 1, { header: 'Request constructor' }) - input = webidl.converters.RequestInfo(input) + input = webidl.converters.RequestInfo_DOMString(input) init = webidl.converters.RequestInit(init) // https://html.spec.whatwg.org/multipage/webappapis.html#environment-settings-object @@ -467,7 +467,8 @@ class Request { // list, append header’s name/header’s value to this’s headers. if (headers instanceof HeadersList) { for (const [key, val] of headers) { - headersList.append(key, val) + // Note: The header names are already in lowercase. + headersList.append(key, val, true) } // Note: Copy the `set-cookie` meta-data. headersList.cookies = headers.cookies @@ -892,16 +893,18 @@ webidl.converters.Request = webidl.interfaceConverter( ) // https://fetch.spec.whatwg.org/#requestinfo -webidl.converters.RequestInfo = function (V) { + +// DOMString is used because the value is converted to a USVString in `new URL()`. +webidl.converters.RequestInfo_DOMString = function (V) { if (typeof V === 'string') { - return webidl.converters.USVString(V) + return webidl.converters.DOMString(V) } if (V instanceof Request) { return webidl.converters.Request(V) } - return webidl.converters.USVString(V) + return webidl.converters.DOMString(V) } webidl.converters.AbortSignal = webidl.interfaceConverter( @@ -921,7 +924,7 @@ webidl.converters.RequestInit = webidl.dictionaryConverter([ { key: 'body', converter: webidl.nullableConverter( - webidl.converters.BodyInit + webidl.converters.BodyInit_DOMString ) }, { diff --git a/lib/web/fetch/response.js b/lib/web/fetch/response.js index e31f619590f..3f48448da92 100644 --- a/lib/web/fetch/response.js +++ b/lib/web/fetch/response.js @@ -77,7 +77,8 @@ class Response { webidl.argumentLengthCheck(arguments, 1, { header: 'Response.redirect' }) - url = webidl.converters.USVString(url) + // DOMString is used because the value is converted to a USVString in `new URL()`. + url = webidl.converters.DOMString(url) status = webidl.converters['unsigned short'](status) // 1. Let parsedURL be the result of parsing url with current settings @@ -120,7 +121,7 @@ class Response { } if (body !== null) { - body = webidl.converters.BodyInit(body) + body = webidl.converters.BodyInit_DOMString(body) } init = webidl.converters.ResponseInit(init) @@ -516,9 +517,10 @@ webidl.converters.URLSearchParams = webidl.interfaceConverter( ) // https://fetch.spec.whatwg.org/#typedefdef-xmlhttprequestbodyinit -webidl.converters.XMLHttpRequestBodyInit = function (V) { + +webidl.converters.XMLHttpRequestBodyInit_DOMString = function (V) { if (typeof V === 'string') { - return webidl.converters.USVString(V) + return webidl.converters.DOMString(V) } if (isBlobLike(V)) { @@ -541,7 +543,7 @@ webidl.converters.XMLHttpRequestBodyInit = function (V) { } // https://fetch.spec.whatwg.org/#bodyinit -webidl.converters.BodyInit = function (V) { +webidl.converters.BodyInit_DOMString = function (V) { if (V instanceof ReadableStream) { return webidl.converters.ReadableStream(V) } @@ -552,7 +554,7 @@ webidl.converters.BodyInit = function (V) { return V } - return webidl.converters.XMLHttpRequestBodyInit(V) + return webidl.converters.XMLHttpRequestBodyInit_DOMString(V) } webidl.converters.ResponseInit = webidl.dictionaryConverter([