ReadableStream should be cancelled on aborting fetch streaming upload (#44847)

Following https://fetch.spec.whatwg.org/#abort-fetch, this CL
lets FetchManager cancels the body ReadableStream with error.
This also fixes fetch itself rejects with the error as well.

Fixed: 40071725
Change-Id: Iaed204b1facd1ef94047cd5342ad3eb1ce6aa260
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5261357
Reviewed-by: Adam Rice <ricea@chromium.org>
Commit-Queue: Yoichi Osato <yoichio@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1268209}

Co-authored-by: Yoichi Osato <yoichio@chromium.org>
diff --git a/fetch/api/basic/request-upload.h2.any.js b/fetch/api/basic/request-upload.h2.any.js
index eedc2bf..6812227 100644
--- a/fetch/api/basic/request-upload.h2.any.js
+++ b/fetch/api/basic/request-upload.h2.any.js
@@ -184,3 +184,26 @@
   await promise_rejects_js(t, TypeError, fetch(url, { method, body, duplex }));
 }, "Streaming upload should fail on a 401 response");
 
+promise_test(async (t) => {
+  const abortMessage = 'foo abort';
+  let streamCancelPromise = new Promise(async res => {
+    var stream = new ReadableStream({
+      cancel: function(reason) {
+        res(reason);
+      }
+    });
+    let abortController = new AbortController();
+    let fetchPromise = promise_rejects_exactly(t, abortMessage, fetch('', {
+                                                 method: 'POST',
+                                                 body: stream,
+                                                 duplex: 'half',
+                                                 signal: abortController.signal
+                                               }));
+    abortController.abort(abortMessage);
+    await fetchPromise;
+  });
+
+  let cancelReason = await streamCancelPromise;
+  assert_equals(
+      cancelReason, abortMessage, 'ReadableStream.cancel should be called.');
+}, 'ReadbleStream should be closed on signal.abort');