Bug 1119044 - Fetch API WebIDL Fixes. r=bkelly,baku
☠☠ backed out by 6e25d9da86de ☠ ☠
authorNikhil Marathe <nsm.nikhil@gmail.com>
Wed, 07 Jan 2015 16:24:40 -0800
changeset 250727 88970726eb6bf1d649b51ec068c1c4ace3023f9e
parent 250726 9c30db22ea97b2ae48430268c45d825bc07cec26
child 250728 6e25d9da86de04c45f8bfdb505f9253d2442eeb3
push id4610
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:32:55 +0000
treeherdermozilla-beta@4df54044d9ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbkelly, baku
bugs1119044
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1119044 - Fetch API WebIDL Fixes. r=bkelly,baku Add various [SameObject]/[NewObject] annotations. Adds RequestCache enum. Ensures that cors-with-forced-preflight is translated to cors in getter. Reject cors-with-forced-preflight as a valid mode value in Request constructor.
dom/fetch/InternalRequest.cpp
dom/fetch/InternalRequest.h
dom/fetch/Request.cpp
dom/fetch/Request.h
dom/webidl/Request.webidl
dom/webidl/Response.webidl
dom/workers/test/fetch/worker_test_request.js
--- a/dom/fetch/InternalRequest.cpp
+++ b/dom/fetch/InternalRequest.cpp
@@ -27,16 +27,17 @@ InternalRequest::GetRequestConstructorCo
   copy->mHeaders = new InternalHeaders(*mHeaders);
 
   copy->mBodyStream = mBodyStream;
   copy->mPreserveContentCodings = true;
 
   copy->mContext = nsIContentPolicy::TYPE_FETCH;
   copy->mMode = mMode;
   copy->mCredentialsMode = mCredentialsMode;
+  copy->mCacheMode = mCacheMode;
   return copy.forget();
 }
 
 InternalRequest::~InternalRequest()
 {
 }
 
 } // namespace dom
--- a/dom/fetch/InternalRequest.h
+++ b/dom/fetch/InternalRequest.h
@@ -57,16 +57,17 @@ public:
     : mMethod("GET")
     , mHeaders(new InternalHeaders(HeadersGuardEnum::None))
     , mContextFrameType(FRAMETYPE_NONE)
     , mReferrerType(REFERRER_CLIENT)
     , mMode(RequestMode::No_cors)
     , mCredentialsMode(RequestCredentials::Omit)
     , mResponseTainting(RESPONSETAINT_BASIC)
     , mRedirectCount(0)
+    , mCacheMode(RequestCache::Default)
     , mAuthenticationFlag(false)
     , mForceOriginHeader(false)
     , mManualRedirect(false)
     , mPreserveContentCodings(false)
       // FIXME(nsm): This should be false by default, but will lead to the
       // algorithm never loading data: URLs right now. See Bug 1018872 about
       // how certain contexts will override it to set it to true. Fetch
       // specification does not handle this yet.
@@ -86,16 +87,17 @@ public:
     , mContext(aOther.mContext)
     , mContextFrameType(aOther.mContextFrameType)
     , mReferrerType(aOther.mReferrerType)
     , mReferrerURL(aOther.mReferrerURL)
     , mMode(aOther.mMode)
     , mCredentialsMode(aOther.mCredentialsMode)
     , mResponseTainting(aOther.mResponseTainting)
     , mRedirectCount(aOther.mRedirectCount)
+    , mCacheMode(aOther.mCacheMode)
     , mAuthenticationFlag(aOther.mAuthenticationFlag)
     , mForceOriginHeader(aOther.mForceOriginHeader)
     , mManualRedirect(aOther.mManualRedirect)
     , mPreserveContentCodings(aOther.mPreserveContentCodings)
     , mSameOriginDataURL(aOther.mSameOriginDataURL)
     , mSandboxedStorageAreaURLs(aOther.mSandboxedStorageAreaURLs)
     , mSkipServiceWorker(aOther.mSkipServiceWorker)
     , mSynchronous(aOther.mSynchronous)
@@ -195,16 +197,22 @@ public:
   }
 
   void
   SetResponseTainting(ResponseTainting aTainting)
   {
     mResponseTainting = aTainting;
   }
 
+  RequestCache
+  GetCacheMode() const
+  {
+    return mCacheMode;
+  }
+
   nsContentPolicyType
   GetContext() const
   {
     return mContext;
   }
 
   bool
   UnsafeRequest() const
@@ -273,16 +281,17 @@ private:
   ReferrerType mReferrerType;
 
   // When mReferrerType is REFERRER_URL.
   nsCString mReferrerURL;
 
   RequestMode mMode;
   RequestCredentials mCredentialsMode;
   ResponseTainting mResponseTainting;
+  RequestCache mCacheMode;
 
   uint32_t mRedirectCount;
 
   bool mAuthenticationFlag;
   bool mForceOriginHeader;
   bool mManualRedirect;
   bool mPreserveContentCodings;
   bool mSameOriginDataURL;
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -123,16 +123,26 @@ Request::Constructor(const GlobalObject&
         return nullptr;
       }
     }
     request->SetURL(NS_ConvertUTF16toUTF8(requestURL));
     fallbackMode = RequestMode::Cors;
     fallbackCredentials = RequestCredentials::Omit;
   }
 
+  // CORS-with-forced-preflight is not publicly exposed and should not be
+  // considered a valid value.
+  if (aInit.mMode.WasPassed() &&
+      aInit.mMode.Value() == RequestMode::Cors_with_forced_preflight) {
+    NS_NAMED_LITERAL_STRING(sourceDescription, "'mode' member of RequestInit");
+    NS_NAMED_LITERAL_STRING(value, "cors-with-forced-preflight");
+    NS_NAMED_LITERAL_STRING(type, "RequestMode");
+    aRv.ThrowTypeError(MSG_INVALID_ENUM_VALUE, &sourceDescription, &value, &type);
+    return nullptr;
+  }
   RequestMode mode = aInit.mMode.WasPassed() ? aInit.mMode.Value() : fallbackMode;
   RequestCredentials credentials =
     aInit.mCredentials.WasPassed() ? aInit.mCredentials.Value()
                                    : fallbackCredentials;
 
   if (mode != RequestMode::EndGuard_) {
     request->SetMode(mode);
   }
--- a/dom/fetch/Request.h
+++ b/dom/fetch/Request.h
@@ -51,25 +51,34 @@ public:
   GetMethod(nsCString& aMethod) const
   {
     aMethod = mRequest->mMethod;
   }
 
   RequestMode
   Mode() const
   {
+    if (mRequest->mMode == RequestMode::Cors_with_forced_preflight) {
+      return RequestMode::Cors;
+    }
     return mRequest->mMode;
   }
 
   RequestCredentials
   Credentials() const
   {
     return mRequest->mCredentialsMode;
   }
 
+  RequestCache
+  Cache() const
+  {
+    return mRequest->GetCacheMode();
+  }
+
   void
   GetReferrer(DOMString& aReferrer) const
   {
     if (mRequest->ReferrerIsNone()) {
       aReferrer.AsAString() = EmptyString();
       return;
     }
 
--- a/dom/webidl/Request.webidl
+++ b/dom/webidl/Request.webidl
@@ -10,29 +10,40 @@
 typedef (Request or USVString) RequestInfo;
 
 [Constructor(RequestInfo input, optional RequestInit init),
  Exposed=(Window,Worker),
  Func="mozilla::dom::Headers::PrefEnabled"]
 interface Request {
   readonly attribute ByteString method;
   readonly attribute USVString url;
-  readonly attribute Headers headers;
+  [SameObject] readonly attribute Headers headers;
 
+  // FIXME(nsm) Bug 1119037: readonly attribute RequestContext context;
   readonly attribute DOMString referrer;
   readonly attribute RequestMode mode;
   readonly attribute RequestCredentials credentials;
+  readonly attribute RequestCache cache;
 
-  Request clone();
+  [NewObject] Request clone();
 };
-
 Request implements Body;
 
 dictionary RequestInit {
   ByteString method;
   HeadersInit headers;
   BodyInit body;
   RequestMode mode;
   RequestCredentials credentials;
+  RequestCache cache;
 };
 
+// FIXME(nsm): Bug 1119037 Implement RequestContext.
+
+// cors-with-forced-preflight is internal to the Fetch spec, but adding it here
+// allows us to use the various conversion conveniences offered by the WebIDL
+// codegen. The Request constructor has explicit checks to prevent it being
+// passed as a valid value, while Request.mode never returns it. Since enums
+// are only exposed as strings to client JS, this has the same effect as not
+// exposing it at all.
 enum RequestMode { "same-origin", "no-cors", "cors", "cors-with-forced-preflight" };
 enum RequestCredentials { "omit", "same-origin", "include" };
+enum RequestCache { "default", "no-store", "reload", "no-cache", "force-cache", "only-if-cached" };
--- a/dom/webidl/Response.webidl
+++ b/dom/webidl/Response.webidl
@@ -6,29 +6,28 @@
  * The origin of this IDL file is
  * https://fetch.spec.whatwg.org/#response-class
  */
 
 [Constructor(optional BodyInit body, optional ResponseInit init),
  Exposed=(Window,Worker),
  Func="mozilla::dom::Headers::PrefEnabled"]
 interface Response {
-  static Response error();
-  static Response redirect(USVString url, optional unsigned short status = 302);
+  [NewObject] static Response error();
+  [NewObject] static Response redirect(USVString url, optional unsigned short status = 302);
 
   readonly attribute ResponseType type;
 
   readonly attribute USVString url;
   readonly attribute unsigned short status;
   readonly attribute ByteString statusText;
-  readonly attribute Headers headers;
+  [SameObject] readonly attribute Headers headers;
 
-  Response clone();
+  [NewObject] Response clone();
 };
-
 Response implements Body;
 
 dictionary ResponseInit {
   unsigned short status = 200;
   // WebIDL spec doesn't allow default values for ByteString.
   ByteString statusText;
   HeadersInit headers;
 };
--- a/dom/workers/test/fetch/worker_test_request.js
+++ b/dom/workers/test/fetch/worker_test_request.js
@@ -200,25 +200,48 @@ function testBodyExtraction() {
     return newReq().arrayBuffer().then(function(v) {
       ok(v instanceof ArrayBuffer, "Should resolve to ArrayBuffer");
       var dec = new TextDecoder();
       is(dec.decode(new Uint8Array(v)), text, "UTF-8 decoded ArrayBuffer should match original");
     });
   })
 }
 
+// mode cannot be set to "CORS-with-forced-preflight" from javascript.
+function testModeCorsPreflightEnumValue() {
+  try {
+    var r = new Request(".", { mode: "cors-with-forced-preflight" });
+    ok(false, "Creating Request with mode cors-with-forced-preflight should fail.");
+  } catch(e) {
+    ok(true, "Creating Request with mode cors-with-forced-preflight should fail.");
+    // Also ensure that the error message matches error messages for truly
+    // invalid strings.
+    var invalidMode = "not-in-requestmode-enum";
+    var invalidExc;
+    try {
+      var r = new Request(".", { mode: invalidMode });
+    } catch(e) {
+      invalidExc = e;
+    }
+    var expectedMessage = invalidExc.message.replace(invalidMode, 'cors-with-forced-preflight');
+    is(e.message, expectedMessage,
+       "mode cors-with-forced-preflight should throw same error as invalid RequestMode strings.");
+  }
+}
+
 onmessage = function() {
   var done = function() { postMessage({ type: 'finish' }) }
 
   testDefaultCtor();
   testClone();
   testSimpleUrlParse();
   testUrlFragment();
   testMethod();
   testBug1109574();
+  testModeCorsPreflightEnumValue();
 
   Promise.resolve()
     .then(testBodyCreation)
     .then(testBodyUsed)
     .then(testBodyExtraction)
     .then(testUsedRequest)
     // Put more promise based tests here.
     .then(done)