1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-03 12:58:54 -05:00

fix(fetch): proxy body for requests created from other requests (#11093)

Additionally, if the existing `Request`'s body is disturbed, the Request creation
should fail.

This change also updates the step numbers in the Request constructor to match
whatwg/fetch#1249.
This commit is contained in:
Andreu Botella 2021-06-23 16:00:23 +02:00 committed by GitHub
parent 2c4ce26f0b
commit edab21ebab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 45 additions and 19 deletions

View file

@ -19,7 +19,7 @@
const { parseFormData, formDataFromEntries, formDataToBlob } = const { parseFormData, formDataFromEntries, formDataToBlob } =
globalThis.__bootstrap.formData; globalThis.__bootstrap.formData;
const mimesniff = globalThis.__bootstrap.mimesniff; const mimesniff = globalThis.__bootstrap.mimesniff;
const { isReadableStreamDisturbed, errorReadableStream } = const { isReadableStreamDisturbed, errorReadableStream, createProxy } =
globalThis.__bootstrap.streams; globalThis.__bootstrap.streams;
class InnerBody { class InnerBody {
@ -133,6 +133,23 @@
second.length = this.length; second.length = this.length;
return second; 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;
}
} }
/** /**

View file

@ -257,14 +257,16 @@
// 28. // 28.
this[_signal] = abortSignal.newSignal(); this[_signal] = abortSignal.newSignal();
// 29.
if (signal !== null) { if (signal !== null) {
abortSignal.follow(this[_signal], signal); abortSignal.follow(this[_signal], signal);
} }
// 29. // 30.
this[_headers] = headersFromHeaderList(request.headerList, "request"); this[_headers] = headersFromHeaderList(request.headerList, "request");
// 31. // 32.
if (Object.keys(init).length > 0) { if (Object.keys(init).length > 0) {
let headers = headerListFromHeaders(this[_headers]).slice( let headers = headerListFromHeaders(this[_headers]).slice(
0, 0,
@ -280,13 +282,13 @@
fillHeaders(this[_headers], headers); fillHeaders(this[_headers], headers);
} }
// 32. // 33.
let inputBody = null; let inputBody = null;
if (input instanceof Request) { if (input instanceof Request) {
inputBody = input[_body]; inputBody = input[_body];
} }
// 33. // 34.
if ( if (
(request.method === "GET" || request.method === "HEAD") && (request.method === "GET" || request.method === "HEAD") &&
((init.body !== undefined && init.body !== null) || ((init.body !== undefined && init.body !== null) ||
@ -295,10 +297,10 @@
throw new TypeError("Request with GET/HEAD method cannot have body."); throw new TypeError("Request with GET/HEAD method cannot have body.");
} }
// 34. // 35.
let initBody = null; let initBody = null;
// 35. // 36.
if (init.body !== undefined && init.body !== null) { if (init.body !== undefined && init.body !== null) {
const res = extractBody(init.body); const res = extractBody(init.body);
initBody = res.body; initBody = res.body;
@ -307,20 +309,22 @@
} }
} }
// 36. // 37.
const inputOrInitBody = initBody ?? inputBody; const inputOrInitBody = initBody ?? inputBody;
// 38.
const finalBody = inputOrInitBody;
// 39. // 39.
// TODO(lucacasonato): implement this step. Is it needed? let finalBody = inputOrInitBody;
// 40. // 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. // 41.
// TODO(lucacasonato): Extranious? https://github.com/whatwg/fetch/issues/1249 request.body = finalBody;
} }
get method() { get method() {

View file

@ -4246,6 +4246,13 @@
webidl.configurePrototype(WritableStreamDefaultController); webidl.configurePrototype(WritableStreamDefaultController);
/**
* @param {ReadableStream} stream
*/
function createProxy(stream) {
return stream.pipeThrough(new TransformStream());
}
webidl.converters.ReadableStream = webidl webidl.converters.ReadableStream = webidl
.createInterfaceConverter("ReadableStream", ReadableStream); .createInterfaceConverter("ReadableStream", ReadableStream);
webidl.converters.WritableStream = webidl webidl.converters.WritableStream = webidl
@ -4403,6 +4410,7 @@
// Non-Public // Non-Public
isReadableStreamDisturbed, isReadableStreamDisturbed,
errorReadableStream, errorReadableStream,
createProxy,
// Exposed in global runtime scope // Exposed in global runtime scope
ByteLengthQueuingStrategy, ByteLengthQueuingStrategy,
CountQueuingStrategy, CountQueuingStrategy,

View file

@ -81,6 +81,7 @@ declare namespace globalThis {
declare var streams: { declare var streams: {
ReadableStream: typeof ReadableStream; ReadableStream: typeof ReadableStream;
isReadableStreamDisturbed(stream: ReadableStream): boolean; isReadableStreamDisturbed(stream: ReadableStream): boolean;
createProxy<T>(stream: ReadableStream<T>): ReadableStream<T>;
}; };
declare namespace messagePort { declare namespace messagePort {

View file

@ -700,11 +700,7 @@
"api": { "api": {
"request": { "request": {
"request-init-002.any.html": true, "request-init-002.any.html": true,
"request-init-stream.any.html": [ "request-init-stream.any.html": true,
"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-consume-empty.any.html": [ "request-consume-empty.any.html": [
"Consume empty FormData request body as text" "Consume empty FormData request body as text"
], ],