Bug 1134330 - Mark fetch events as reloads appropriately. r=smaug
authorJosh Matthews <josh@joshmatthews.net>
Mon, 23 Mar 2015 13:36:44 -0400
changeset 265444 283cce9dbda09a6d67bd431bcfa299df0e213496
parent 265443 cef88d7252a117b3a50fbc34c2cddcdee17e9a1c
child 265445 1aa2afb3de8f616bbadc0539428b00c5649a613b
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1134330
milestone39.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 1134330 - Mark fetch events as reloads appropriately. r=smaug
docshell/base/nsDocShell.cpp
dom/interfaces/base/nsIServiceWorkerManager.idl
dom/workers/ServiceWorkerManager.cpp
dom/workers/test/serviceworkers/fetch_event_worker.js
dom/workers/test/serviceworkers/test_fetch_event.html
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -13990,17 +13990,18 @@ nsDocShell::ChannelIntercepted(nsIInterc
 
   if (!isNavigation) {
     doc = GetDocument();
     if (!doc) {
       return NS_ERROR_NOT_AVAILABLE;
     }
   }
 
-  return swm->DispatchFetchEvent(doc, aChannel);
+  bool isReload = mLoadType & LOAD_CMD_RELOAD;
+  return swm->DispatchFetchEvent(doc, aChannel, isReload);
 }
 
 NS_IMETHODIMP
 nsDocShell::SetPaymentRequestId(const nsAString& aPaymentRequestId)
 {
   mPaymentRequestId = aPaymentRequestId;
   return NS_OK;
 }
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl
+++ b/dom/interfaces/base/nsIServiceWorkerManager.idl
@@ -14,17 +14,17 @@ interface nsIURI;
 interface nsIServiceWorkerUnregisterCallback : nsISupports
 {
   // aState is true if the unregistration succeded.
   // It's false if this ServiceWorkerRegistration doesn't exist.
   [noscript] void UnregisterSucceeded(in bool aState);
   [noscript] void UnregisterFailed();
 };
 
-[builtinclass, uuid(706c3e6b-c9d2-4857-893d-4b4845fec48f)]
+[builtinclass, uuid(e4c8baa5-237a-4bf6-82d4-ea06eb4b76ba)]
 interface nsIServiceWorkerManager : nsISupports
 {
   /**
    * Registers a ServiceWorker with script loaded from `aScriptURI` to act as
    * the ServiceWorker for aScope.  Requires a valid entry settings object on
    * the stack. This means you must call this from content code 'within'
    * a window.
    *
@@ -54,17 +54,18 @@ interface nsIServiceWorkerManager : nsIS
 
   // Returns true if a ServiceWorker is available for the scope of aURI.
   bool isAvailableForURI(in nsIURI aURI);
 
   // Returns true if a given document is currently controlled by a ServiceWorker
   bool isControlled(in nsIDocument aDocument);
 
   // Cause a fetch event to be dispatched to the worker global associated with the given document.
-  void dispatchFetchEvent(in nsIDocument aDoc, in nsIInterceptedChannel aChannel);
+  void dispatchFetchEvent(in nsIDocument aDoc, in nsIInterceptedChannel aChannel,
+                          in boolean aIsReload);
 
   // aTarget MUST be a ServiceWorkerRegistration.
   [noscript] void AddRegistrationEventListener(in DOMString aScope, in nsIDOMEventTarget aTarget);
   [noscript] void RemoveRegistrationEventListener(in DOMString aScope, in nsIDOMEventTarget aTarget);
 
   /**
    * Call this to request that document `aDoc` be controlled by a ServiceWorker
    * if a registration exists for it's scope.
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -2130,21 +2130,23 @@ class FetchEventRunnable : public Worker
   nsAutoPtr<ServiceWorkerClientInfo> mClientInfo;
   nsCString mSpec;
   nsCString mMethod;
   bool mIsReload;
 public:
   FetchEventRunnable(WorkerPrivate* aWorkerPrivate,
                      nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
                      nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
-                     nsAutoPtr<ServiceWorkerClientInfo>& aClientInfo)
+                     nsAutoPtr<ServiceWorkerClientInfo>& aClientInfo,
+                     bool aIsReload)
     : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
     , mInterceptedChannel(aChannel)
     , mServiceWorker(aServiceWorker)
     , mClientInfo(aClientInfo)
+    , mIsReload(aIsReload)
   {
     MOZ_ASSERT(aWorkerPrivate);
   }
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_IMETHOD
   VisitHeader(const nsACString& aHeader, const nsACString& aValue) override
@@ -2173,19 +2175,16 @@ public:
 
     rv = httpChannel->GetRequestMethod(mMethod);
     NS_ENSURE_SUCCESS(rv, rv);
 
     uint32_t loadFlags;
     rv = channel->GetLoadFlags(&loadFlags);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    //TODO(jdm): we should probably include reload-ness in the loadinfo or as a separate load flag
-    mIsReload = false;
-
     rv = httpChannel->VisitRequestHeaders(this);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
@@ -2275,17 +2274,18 @@ private:
     }
     return true;
   }
 };
 
 NS_IMPL_ISUPPORTS_INHERITED(FetchEventRunnable, WorkerRunnable, nsIHttpHeaderVisitor)
 
 NS_IMETHODIMP
-ServiceWorkerManager::DispatchFetchEvent(nsIDocument* aDoc, nsIInterceptedChannel* aChannel)
+ServiceWorkerManager::DispatchFetchEvent(nsIDocument* aDoc, nsIInterceptedChannel* aChannel,
+                                         bool aIsReload)
 {
   MOZ_ASSERT(aChannel);
   nsCOMPtr<nsISupports> serviceWorker;
 
   bool isNavigation = false;
   nsresult rv = aChannel->GetIsNavigation(&isNavigation);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -2325,17 +2325,17 @@ ServiceWorkerManager::DispatchFetchEvent
     new nsMainThreadPtrHolder<nsIInterceptedChannel>(aChannel, false));
 
   nsRefPtr<ServiceWorker> sw = static_cast<ServiceWorker*>(serviceWorker.get());
   nsMainThreadPtrHandle<ServiceWorker> serviceWorkerHandle(
     new nsMainThreadPtrHolder<ServiceWorker>(sw));
 
   // clientInfo is null if we don't have a controlled document
   nsRefPtr<FetchEventRunnable> event =
-    new FetchEventRunnable(sw->GetWorkerPrivate(), handle, serviceWorkerHandle, clientInfo);
+    new FetchEventRunnable(sw->GetWorkerPrivate(), handle, serviceWorkerHandle, clientInfo, aIsReload);
   rv = event->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   AutoJSAPI api;
   api.Init();
   if (NS_WARN_IF(!event->Dispatch(api.cx()))) {
     return NS_ERROR_FAILURE;
   }
--- a/dom/workers/test/serviceworkers/fetch_event_worker.js
+++ b/dom/workers/test/serviceworkers/fetch_event_worker.js
@@ -1,8 +1,10 @@
+var seenIndex = false;
+
 onfetch = function(ev) {
   if (ev.request.url.contains("synthesized.txt")) {
     ev.respondWith(Promise.resolve(
       new Response("synthesized response body", {})
     ));
   }
 
   else if (ev.request.url.contains("synthesized-404.txt")) {
@@ -110,9 +112,23 @@ onfetch = function(ev) {
 
   else if (ev.request.url.contains("hello-after-extracting.gz")) {
     ev.respondWith(fetch("fetch/deliver-gzip.sjs").then(function(res) {
       return res.text().then(function(body) {
         return new Response(body, { status: res.status, statusText: res.statusText, headers: res.headers });
       });
     }));
   }
+
+  else if (ev.request.url.contains("index.html")) {
+    if (seenIndex) {
+        var body = "<script>" +
+                     "opener.postMessage({status: 'ok', result: " + ev.isReload + "," +
+                                         "message: 'reload status should be indicated'}, '*');" +
+                     "opener.postMessage({status: 'done'}, '*');" +
+                   "</script>";
+        ev.respondWith(new Response(body, {headers: {'Content-Type': 'text/html'}}));
+    } else {
+      seenIndex = true;
+      ev.respondWith(fetch(ev.request.url));
+    }
+  }
 }
--- a/dom/workers/test/serviceworkers/test_fetch_event.html
+++ b/dom/workers/test/serviceworkers/test_fetch_event.html
@@ -22,23 +22,29 @@
       return new Promise(function(resolve) {
         swr.installing.onstatechange = resolve;
       });
     });
   }
 
   function testController() {
     var p = new Promise(function(resolve, reject) {
+      var reloaded = false;
       window.onmessage = function(e) {
         if (e.data.status == "ok") {
           ok(e.data.result, e.data.message);
         } else if (e.data.status == "done") {
-          window.onmessage = null;
-          w.close();
-          resolve();
+          if (reloaded) {
+            window.onmessage = null;
+            w.close();
+            resolve();
+          } else {
+            w.location.reload();
+            reloaded = true;
+          }
         }
       }
     });
 
     var w = window.open("fetch/index.html");
     return p;
   }