Bug 1303025 - Accept null for body param in constructor of Response. r?bkelly draft
authorXidorn Quan <me@upsuper.org>
Sat, 13 Jan 2018 14:20:50 +1100
changeset 720015 f5454dc5de4d83cf2e304db1071e3f1e218b0ba8
parent 718845 4db166f0442dddc5b9011c722d7499501fedf283
child 745959 b47d12cb8264d854d69f1009326f4065408493cc
push id95429
push userxquan@mozilla.com
push dateSat, 13 Jan 2018 07:02:49 +0000
reviewersbkelly
bugs1303025
milestone59.0a1
Bug 1303025 - Accept null for body param in constructor of Response. r?bkelly MozReview-Commit-ID: LeEFcQzPJlv
dom/fetch/Response.cpp
dom/fetch/Response.h
dom/webidl/Response.webidl
testing/web-platform/tests/fetch/api/response/response-init-002.html
--- a/dom/fetch/Response.cpp
+++ b/dom/fetch/Response.cpp
@@ -135,17 +135,17 @@ Response::Redirect(const GlobalObject& a
     return nullptr;
   }
 
   if (aStatus != 301 && aStatus != 302 && aStatus != 303 && aStatus != 307 && aStatus != 308) {
     aRv.ThrowRangeError<MSG_INVALID_REDIRECT_STATUSCODE_ERROR>();
     return nullptr;
   }
 
-  Optional<fetch::ResponseBodyInit> body;
+  Optional<Nullable<fetch::ResponseBodyInit>> body;
   ResponseInit init;
   init.mStatus = aStatus;
   RefPtr<Response> r = Response::Constructor(aGlobal, body, init, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   r->GetInternalHeaders()->Set(NS_LITERAL_CSTRING("Location"),
@@ -156,17 +156,17 @@ Response::Redirect(const GlobalObject& a
   r->GetInternalHeaders()->SetGuard(HeadersGuardEnum::Immutable, aRv);
   MOZ_ASSERT(!aRv.Failed());
 
   return r.forget();
 }
 
 /*static*/ already_AddRefed<Response>
 Response::Constructor(const GlobalObject& aGlobal,
-                      const Optional<fetch::ResponseBodyInit>& aBody,
+                      const Optional<Nullable<fetch::ResponseBodyInit>>& aBody,
                       const ResponseInit& aInit, ErrorResult& aRv)
 {
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
 
   if (aInit.mStatus < 200 || aInit.mStatus > 599) {
     aRv.ThrowRangeError<MSG_INVALID_RESPONSE_STATUSCODE_ERROR>();
     return nullptr;
   }
@@ -222,29 +222,29 @@ Response::Constructor(const GlobalObject
     }
 
     internalResponse->Headers()->Fill(*headers->GetInternalHeaders(), aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
   }
 
-  if (aBody.WasPassed()) {
+  if (aBody.WasPassed() && !aBody.Value().IsNull()) {
     if (aInit.mStatus == 204 || aInit.mStatus == 205 || aInit.mStatus == 304) {
       aRv.ThrowTypeError<MSG_RESPONSE_NULL_STATUS_WITH_BODY>();
       return nullptr;
     }
 
     nsCString contentTypeWithCharset;
     nsCOMPtr<nsIInputStream> bodyStream;
     int64_t bodySize = InternalResponse::UNKNOWN_BODY_SIZE;
 
-    if (aBody.Value().IsReadableStream()) {
-      const ReadableStream& readableStream =
-        aBody.Value().GetAsReadableStream();
+    const fetch::ResponseBodyInit& body = aBody.Value().Value();
+    if (body.IsReadableStream()) {
+      const ReadableStream& readableStream = body.GetAsReadableStream();
 
       JS::Rooted<JSObject*> readableStreamObj(aGlobal.Context(),
                                               readableStream.Obj());
 
       if (JS::ReadableStreamIsDisturbed(readableStreamObj) ||
           JS::ReadableStreamIsLocked(readableStreamObj) ||
           !JS::ReadableStreamIsReadable(readableStreamObj)) {
         aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
@@ -283,17 +283,17 @@ Response::Constructor(const GlobalObject
                                         getter_AddRefs(r->mFetchStreamReader),
                                         getter_AddRefs(bodyStream));
         if (NS_WARN_IF(aRv.Failed())) {
           return nullptr;
         }
       }
     } else {
       uint64_t size = 0;
-      aRv = ExtractByteStreamFromBody(aBody.Value(),
+      aRv = ExtractByteStreamFromBody(body,
                                       getter_AddRefs(bodyStream),
                                       contentTypeWithCharset,
                                       size);
       if (NS_WARN_IF(aRv.Failed())) {
         return nullptr;
       }
 
       bodySize = size;
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -115,17 +115,17 @@ public:
   static already_AddRefed<Response>
   Error(const GlobalObject& aGlobal);
 
   static already_AddRefed<Response>
   Redirect(const GlobalObject& aGlobal, const nsAString& aUrl, uint16_t aStatus, ErrorResult& aRv);
 
   static already_AddRefed<Response>
   Constructor(const GlobalObject& aGlobal,
-              const Optional<fetch::ResponseBodyInit>& aBody,
+              const Optional<Nullable<fetch::ResponseBodyInit>>& aBody,
               const ResponseInit& aInit, ErrorResult& rv);
 
   nsIGlobalObject* GetParentObject() const
   {
     return mOwner;
   }
 
   already_AddRefed<Response>
--- a/dom/webidl/Response.webidl
+++ b/dom/webidl/Response.webidl
@@ -4,17 +4,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * https://fetch.spec.whatwg.org/#response-class
  */
 
 // This should be Constructor(optional BodyInit... but BodyInit doesn't include
 // ReadableStream yet because we don't want to expose Streams API to Request.
-[Constructor(optional (Blob or BufferSource or FormData or URLSearchParams or ReadableStream or USVString) body, optional ResponseInit init),
+[Constructor(optional (Blob or BufferSource or FormData or URLSearchParams or ReadableStream or USVString)? body, optional ResponseInit init),
  Exposed=(Window,Worker)]
 interface Response {
   [NewObject] static Response error();
   [Throws,
    NewObject] static Response redirect(USVString url, optional unsigned short status = 302);
 
   readonly attribute ResponseType type;
 
--- a/testing/web-platform/tests/fetch/api/response/response-init-002.html
+++ b/testing/web-platform/tests/fetch/api/response/response-init-002.html
@@ -60,11 +60,16 @@
 
       promise_test(function(test) {
         var response = new Response("This is my fork", {"headers" : [["Content-Type", ""]]});
         return response.blob().then(function(blob) {
           assert_equals(blob.type, "", "Blob type should be the empty string");
         });
       }, "Testing empty Response Content-Type header");
 
+      test(function() {
+        var response = new Response(null, {status: 204});
+        assert_equals(response.body, null);
+      }, "Testing null Response body");
+
     </script>
   </body>
 </html>