diff --git a/extensions/fetch/22_body.js b/extensions/fetch/22_body.js index 475af035f7..9b5bf8eff4 100644 --- a/extensions/fetch/22_body.js +++ b/extensions/fetch/22_body.js @@ -19,7 +19,7 @@ const { parseFormData, formDataFromEntries, formDataToBlob } = globalThis.__bootstrap.formData; const mimesniff = globalThis.__bootstrap.mimesniff; - const { isReadableStreamDisturbed, errorReadableStream } = + const { isReadableStreamDisturbed, errorReadableStream, createProxy } = globalThis.__bootstrap.streams; class InnerBody { @@ -133,6 +133,23 @@ second.length = this.length; return second; } + + /** + * @returns {InnerBody} + */ + createProxy() { + let proxyStreamOrStatic; + if (this.streamOrStatic instanceof ReadableStream) { + proxyStreamOrStatic = createProxy(this.streamOrStatic); + } else { + proxyStreamOrStatic = { ...this.streamOrStatic }; + this.streamOrStatic.consumed = true; + } + const proxy = new InnerBody(proxyStreamOrStatic); + proxy.source = this.source; + proxy.length = this.length; + return proxy; + } } /** diff --git a/extensions/fetch/23_request.js b/extensions/fetch/23_request.js index ff2bf1d4ea..93d13e8d8d 100644 --- a/extensions/fetch/23_request.js +++ b/extensions/fetch/23_request.js @@ -257,14 +257,16 @@ // 28. this[_signal] = abortSignal.newSignal(); + + // 29. if (signal !== null) { abortSignal.follow(this[_signal], signal); } - // 29. + // 30. this[_headers] = headersFromHeaderList(request.headerList, "request"); - // 31. + // 32. if (Object.keys(init).length > 0) { let headers = headerListFromHeaders(this[_headers]).slice( 0, @@ -280,13 +282,13 @@ fillHeaders(this[_headers], headers); } - // 32. + // 33. let inputBody = null; if (input instanceof Request) { inputBody = input[_body]; } - // 33. + // 34. if ( (request.method === "GET" || request.method === "HEAD") && ((init.body !== undefined && init.body !== null) || @@ -295,10 +297,10 @@ throw new TypeError("Request with GET/HEAD method cannot have body."); } - // 34. + // 35. let initBody = null; - // 35. + // 36. if (init.body !== undefined && init.body !== null) { const res = extractBody(init.body); initBody = res.body; @@ -307,20 +309,22 @@ } } - // 36. + // 37. const inputOrInitBody = initBody ?? inputBody; - // 38. - const finalBody = inputOrInitBody; - // 39. - // TODO(lucacasonato): implement this step. Is it needed? + let finalBody = inputOrInitBody; // 40. - request.body = finalBody; + if (initBody === null && inputBody !== null) { + if (input[_body] && input[_body].unusable()) { + throw new TypeError("Input request's body is unusable."); + } + finalBody = inputBody.createProxy(); + } // 41. - // TODO(lucacasonato): Extranious? https://github.com/whatwg/fetch/issues/1249 + request.body = finalBody; } get method() { diff --git a/extensions/web/06_streams.js b/extensions/web/06_streams.js index be5eca6bad..127436d43a 100644 --- a/extensions/web/06_streams.js +++ b/extensions/web/06_streams.js @@ -4246,6 +4246,13 @@ webidl.configurePrototype(WritableStreamDefaultController); + /** + * @param {ReadableStream} stream + */ + function createProxy(stream) { + return stream.pipeThrough(new TransformStream()); + } + webidl.converters.ReadableStream = webidl .createInterfaceConverter("ReadableStream", ReadableStream); webidl.converters.WritableStream = webidl @@ -4403,6 +4410,7 @@ // Non-Public isReadableStreamDisturbed, errorReadableStream, + createProxy, // Exposed in global runtime scope ByteLengthQueuingStrategy, CountQueuingStrategy, diff --git a/extensions/web/internal.d.ts b/extensions/web/internal.d.ts index 06976b28bf..bbf529b770 100644 --- a/extensions/web/internal.d.ts +++ b/extensions/web/internal.d.ts @@ -81,6 +81,7 @@ declare namespace globalThis { declare var streams: { ReadableStream: typeof ReadableStream; isReadableStreamDisturbed(stream: ReadableStream): boolean; + createProxy(stream: ReadableStream): ReadableStream; }; declare namespace messagePort { diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json index 3f30e9ca9c..94d9ea81cd 100644 --- a/tools/wpt/expectation.json +++ b/tools/wpt/expectation.json @@ -700,11 +700,7 @@ "api": { "request": { "request-init-002.any.html": true, - "request-init-stream.any.html": [ - "Constructing a Request with a Request on which body.getReader() is called", - "Constructing a Request with a Request on which body.getReader().read() is called", - "Constructing a Request with a Request on which read() and releaseLock() are called" - ], + "request-init-stream.any.html": true, "request-consume-empty.any.html": [ "Consume empty FormData request body as text" ],