Bug 1174106 - Part 2: Load the top level SW script with http cache bypass settings; r?rickychien draft
authorHo-Pang Hsu <hopang.hsu@gmail.com>
Thu, 10 Nov 2016 17:33:52 +0800
changeset 437086 0b3fdb741747d77f50720129d53ec09e8657003c
parent 437085 f892f03b0ee62c3ff19e0a0da399b35ab91a552d
child 437087 166d2df342a77e562914174fb1d0660647f18ecf
push id35320
push userbmo:bhsu@mozilla.com
push dateThu, 10 Nov 2016 10:05:34 +0000
reviewersrickychien
bugs1174106
milestone52.0a1
Bug 1174106 - Part 2: Load the top level SW script with http cache bypass settings; r?rickychien MozReview-Commit-ID: 97GFyga1GOy
dom/interfaces/base/nsIServiceWorkerManager.idl
dom/workers/ServiceWorkerContainer.cpp
dom/workers/ServiceWorkerManager.cpp
dom/workers/ServiceWorkerRegisterJob.cpp
dom/workers/ServiceWorkerRegisterJob.h
dom/workers/ServiceWorkerScriptCache.cpp
dom/workers/ServiceWorkerScriptCache.h
dom/workers/ServiceWorkerUpdateJob.cpp
dom/workers/ServiceWorkerUpdateJob.h
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl
+++ b/dom/interfaces/base/nsIServiceWorkerManager.idl
@@ -93,17 +93,20 @@ interface nsIServiceWorkerManager : nsIS
   /**
    * 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.
    *
    * Returns a Promise.
    */
-  nsISupports register(in mozIDOMWindow aWindow, in nsIURI aScope, in nsIURI aScriptURI);
+  nsISupports register(in mozIDOMWindow aWindow,
+                       in nsIURI aScope,
+                       in nsIURI aScriptURI,
+                       in bool aBypassHttpCache);
 
   /**
    * Unregister an existing ServiceWorker registration for `aScope`.
    * It keeps aCallback alive until the operation is concluded.
    */
   void unregister(in nsIPrincipal aPrincipal,
                   in nsIServiceWorkerUnregisterCallback aCallback,
                   in DOMString aScope);
--- a/dom/workers/ServiceWorkerContainer.cpp
+++ b/dom/workers/ServiceWorkerContainer.cpp
@@ -202,19 +202,24 @@ ServiceWorkerContainer::Register(const n
     }
 
     aRv = CheckForSlashEscapedCharsInPath(scopeURI);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
   }
 
+  // TODO: Add spec link here
+  bool bypassHttpCache =
+    aOptions.mUseCache.WasPassed() ? !aOptions.mUseCache.Value() : true;
+
   // The spec says that the "client" passed to Register() must be the global
   // where the ServiceWorkerContainer was retrieved from.
-  aRv = swm->Register(GetOwner(), scopeURI, scriptURI, getter_AddRefs(promise));
+  aRv = swm->Register(GetOwner(), scopeURI, scriptURI, bypassHttpCache,
+                      getter_AddRefs(promise));
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   RefPtr<Promise> ret = static_cast<Promise*>(promise.get());
   MOZ_ASSERT(ret);
   return ret.forget();
 }
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -486,16 +486,17 @@ IsFromAuthenticatedOrigin(nsIDocument* a
 }
 
 // If we return an error code here, the ServiceWorkerContainer will
 // automatically reject the Promise.
 NS_IMETHODIMP
 ServiceWorkerManager::Register(mozIDOMWindow* aWindow,
                                nsIURI* aScopeURI,
                                nsIURI* aScriptURI,
+                               bool aBypassHttpCache,
                                nsISupports** aPromise)
 {
   AssertIsOnMainThread();
 
   if (NS_WARN_IF(!aWindow)) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
@@ -612,17 +613,17 @@ ServiceWorkerManager::Register(mozIDOMWi
   // Create a load group that is separate from, yet related to, the document's load group.
   // This allows checks for interfaces like nsILoadContext to yield the values used by the
   // the document, yet will not cancel the update job if the document's load group is cancelled.
   nsCOMPtr<nsILoadGroup> loadGroup = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
   MOZ_ALWAYS_SUCCEEDS(loadGroup->SetNotificationCallbacks(ir));
 
   RefPtr<ServiceWorkerRegisterJob> job =
     new ServiceWorkerRegisterJob(documentPrincipal, cleanedScope, spec,
-                                 loadGroup);
+                                 loadGroup, aBypassHttpCache);
   job->AppendResultCallback(cb);
   queue->ScheduleJob(job);
 
   AssertIsOnMainThread();
   Telemetry::Accumulate(Telemetry::SERVICE_WORKER_REGISTRATIONS, 1);
 
   promise.forget(aPromise);
   return NS_OK;
--- a/dom/workers/ServiceWorkerRegisterJob.cpp
+++ b/dom/workers/ServiceWorkerRegisterJob.cpp
@@ -10,19 +10,20 @@
 
 namespace mozilla {
 namespace dom {
 namespace workers {
 
 ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(nsIPrincipal* aPrincipal,
                                                    const nsACString& aScope,
                                                    const nsACString& aScriptSpec,
-                                                   nsILoadGroup* aLoadGroup)
+                                                   nsILoadGroup* aLoadGroup,
+                                                   bool aBypassHttpCache)
   : ServiceWorkerUpdateJob(Type::Register, aPrincipal, aScope, aScriptSpec,
-                           aLoadGroup)
+                           aLoadGroup, aBypassHttpCache)
 {
 }
 
 void
 ServiceWorkerRegisterJob::AsyncExecute()
 {
   AssertIsOnMainThread();
 
@@ -40,17 +41,17 @@ ServiceWorkerRegisterJob::AsyncExecute()
     // it to disk again.  We preemptively removed it earlier during
     // unregister so that closing the window by shutting down the browser
     // results in the registration being gone on restart.
     if (registration->mPendingUninstall) {
       swm->StoreRegistration(mPrincipal, registration);
     }
     registration->mPendingUninstall = false;
     RefPtr<ServiceWorkerInfo> newest = registration->Newest();
-    if (newest && mScriptSpec.Equals(newest->ScriptSpec())) {
+    if (!mBypassHttpCache && newest && mScriptSpec.Equals(newest->ScriptSpec())) {
       SetRegistration(registration);
       Finish(NS_OK);
       return;
     }
   } else {
     registration = swm->CreateNewRegistration(mScope, mPrincipal);
   }
 
--- a/dom/workers/ServiceWorkerRegisterJob.h
+++ b/dom/workers/ServiceWorkerRegisterJob.h
@@ -17,17 +17,18 @@ namespace workers {
 // but then uses ServiceWorkerUpdateJob to implement the Update and Install
 // spec algorithms.
 class ServiceWorkerRegisterJob final : public ServiceWorkerUpdateJob
 {
 public:
   ServiceWorkerRegisterJob(nsIPrincipal* aPrincipal,
                            const nsACString& aScope,
                            const nsACString& aScriptSpec,
-                           nsILoadGroup* aLoadGroup);
+                           nsILoadGroup* aLoadGroup,
+                           bool aBypassHttpCache);
 
 private:
   // Implement the Register algorithm steps and then call the parent class
   // Update() to complete the job execution.
   virtual void
   AsyncExecute() override;
 
   virtual ~ServiceWorkerRegisterJob();
--- a/dom/workers/ServiceWorkerScriptCache.cpp
+++ b/dom/workers/ServiceWorkerScriptCache.cpp
@@ -92,17 +92,20 @@ public:
   explicit CompareNetwork(CompareManager* aManager)
     : mManager(aManager)
   {
     MOZ_ASSERT(aManager);
     AssertIsOnMainThread();
   }
 
   nsresult
-  Initialize(nsIPrincipal* aPrincipal, const nsAString& aURL, nsILoadGroup* aLoadGroup);
+  Initialize(nsIPrincipal* aPrincipal,
+             const nsAString& aURL,
+             nsILoadGroup* aLoadGroup,
+             bool aBypassHttpCache);
 
   void
   Abort()
   {
     AssertIsOnMainThread();
 
     MOZ_ASSERT(mChannel);
     mChannel->Cancel(NS_BINDING_ABORTED);
@@ -245,17 +248,18 @@ public:
     , mInCache(false)
   {
     AssertIsOnMainThread();
     MOZ_ASSERT(aRegistration);
   }
 
   nsresult
   Initialize(nsIPrincipal* aPrincipal, const nsAString& aURL,
-             const nsAString& aCacheName, nsILoadGroup* aLoadGroup)
+             const nsAString& aCacheName, nsILoadGroup* aLoadGroup,
+             bool aBypassHttpCache)
   {
     AssertIsOnMainThread();
     MOZ_ASSERT(aPrincipal);
 
     mURL = aURL;
 
     // Always create a CacheStorage since we want to write the network entry to
     // the cache even if there isn't an existing one.
@@ -266,17 +270,17 @@ public:
     mCacheStorage = CreateCacheStorage(jsapi.cx(), aPrincipal, result, &mSandbox);
     if (NS_WARN_IF(result.Failed())) {
       MOZ_ASSERT(!result.IsErrorWithMessage());
       Cleanup();
       return result.StealNSResult();
     }
 
     mCN = new CompareNetwork(this);
-    nsresult rv = mCN->Initialize(aPrincipal, aURL, aLoadGroup);
+    nsresult rv = mCN->Initialize(aPrincipal, aURL, aLoadGroup, aBypassHttpCache);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       Cleanup();
       return rv;
     }
 
     if (!aCacheName.IsEmpty()) {
       mCC = new CompareCache(this);
       rv = mCC->Initialize(aPrincipal, aURL, aCacheName);
@@ -600,17 +604,17 @@ private:
   bool mNetworkFinished;
   bool mCacheFinished;
   bool mInCache;
 };
 
 NS_IMPL_ISUPPORTS0(CompareManager)
 
 nsresult
-CompareNetwork::Initialize(nsIPrincipal* aPrincipal, const nsAString& aURL, nsILoadGroup* aLoadGroup)
+CompareNetwork::Initialize(nsIPrincipal* aPrincipal, const nsAString& aURL, nsILoadGroup* aLoadGroup, bool aBypassHttpCache)
 {
   MOZ_ASSERT(aPrincipal);
   AssertIsOnMainThread();
 
   nsCOMPtr<nsIURI> uri;
   nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, nullptr);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -624,16 +628,20 @@ CompareNetwork::Initialize(nsIPrincipal*
 
   nsLoadFlags flags = nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     mManager->GetRegistration();
   if (registration->IsLastUpdateCheckTimeOverOneDay()) {
     flags |= nsIRequest::LOAD_BYPASS_CACHE;
   }
 
+  if (aBypassHttpCache) {
+    flags |= nsIRequest::VALIDATE_ALWAYS;
+  }
+
   // Note that because there is no "serviceworker" RequestContext type, we can
   // use the TYPE_INTERNAL_SCRIPT content policy types when loading a service
   // worker.
   rv = NS_NewChannel(getter_AddRefs(mChannel),
                      uri, aPrincipal,
                      nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
                      nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER,
                      loadGroup,
@@ -1041,27 +1049,28 @@ GenerateCacheName(nsAString& aName)
 
   return NS_OK;
 }
 
 nsresult
 Compare(ServiceWorkerRegistrationInfo* aRegistration,
         nsIPrincipal* aPrincipal, const nsAString& aCacheName,
         const nsAString& aURL, CompareCallback* aCallback,
-        nsILoadGroup* aLoadGroup)
+        nsILoadGroup* aLoadGroup, bool aBypassHttpCache)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aRegistration);
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(!aURL.IsEmpty());
   MOZ_ASSERT(aCallback);
 
   RefPtr<CompareManager> cm = new CompareManager(aRegistration, aCallback);
 
-  nsresult rv = cm->Initialize(aPrincipal, aURL, aCacheName, aLoadGroup);
+  nsresult rv = cm->Initialize(aPrincipal, aURL, aCacheName, aLoadGroup,
+                               aBypassHttpCache);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
 } // namespace serviceWorkerScriptCache
--- a/dom/workers/ServiceWorkerScriptCache.h
+++ b/dom/workers/ServiceWorkerScriptCache.h
@@ -43,17 +43,18 @@ public:
 
   NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0;
   NS_IMETHOD_(MozExternalRefCountType) Release() = 0;
 };
 
 nsresult
 Compare(ServiceWorkerRegistrationInfo* aRegistration,
         nsIPrincipal* aPrincipal, const nsAString& aCacheName,
-        const nsAString& aURL, CompareCallback* aCallback, nsILoadGroup* aLoadGroup);
+        const nsAString& aURL, CompareCallback* aCallback,
+        nsILoadGroup* aLoadGroup, bool mBypassHttpCache);
 
 } // namespace serviceWorkerScriptCache
 
 } // namespace workers
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_workers_ServiceWorkerScriptCache_h
--- a/dom/workers/ServiceWorkerUpdateJob.cpp
+++ b/dom/workers/ServiceWorkerUpdateJob.cpp
@@ -180,18 +180,20 @@ ServiceWorkerUpdateJob::GetRegistration(
   RefPtr<ServiceWorkerRegistrationInfo> ref = mRegistration;
   return ref.forget();
 }
 
 ServiceWorkerUpdateJob::ServiceWorkerUpdateJob(Type aType,
                                                nsIPrincipal* aPrincipal,
                                                const nsACString& aScope,
                                                const nsACString& aScriptSpec,
-                                               nsILoadGroup* aLoadGroup)
+                                               nsILoadGroup* aLoadGroup,
+                                               bool aBypassHttpCache)
   : ServiceWorkerJob(aType, aPrincipal, aScope, aScriptSpec)
+  , mBypassHttpCache(aBypassHttpCache)
   , mLoadGroup(aLoadGroup)
 {
 }
 
 ServiceWorkerUpdateJob::~ServiceWorkerUpdateJob()
 {
 }
 
@@ -306,17 +308,17 @@ ServiceWorkerUpdateJob::Update()
     cacheName = workerInfo->CacheName();
   }
 
   RefPtr<CompareCallback> callback = new CompareCallback(this);
 
   nsresult rv =
     serviceWorkerScriptCache::Compare(mRegistration, mPrincipal, cacheName,
                                       NS_ConvertUTF8toUTF16(mScriptSpec),
-                                      callback, mLoadGroup);
+                                      callback, mLoadGroup, mBypassHttpCache);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     FailUpdateJob(rv);
     return;
   }
 }
 
 void
 ServiceWorkerUpdateJob::ComparisonResult(nsresult aStatus,
--- a/dom/workers/ServiceWorkerUpdateJob.h
+++ b/dom/workers/ServiceWorkerUpdateJob.h
@@ -31,17 +31,18 @@ public:
   GetRegistration() const;
 
 protected:
   // Construct an update job that is overriden as another job type.
   ServiceWorkerUpdateJob(Type aType,
                          nsIPrincipal* aPrincipal,
                          const nsACString& aScope,
                          const nsACString& aScriptSpec,
-                         nsILoadGroup* aLoadGroup);
+                         nsILoadGroup* aLoadGroup,
+                         bool mBypassHttpCache);
 
   virtual ~ServiceWorkerUpdateJob();
 
   // FailUpdateJob() must be called if an update job needs Finish() with
   // an error.
   void
   FailUpdateJob(ErrorResult& aRv);
 
@@ -61,16 +62,18 @@ protected:
 
   // Execute the bulk of the update job logic using the registration defined
   // by a previous SetRegistration() call.  This can be called by the overriden
   // AsyncExecute() to complete the job.  The Update() method will always call
   // Finish().  This method corresponds to the spec Update algorithm.
   void
   Update();
 
+  bool mBypassHttpCache;
+
 private:
   class CompareCallback;
   class ContinueUpdateRunnable;
   class ContinueInstallRunnable;
 
   // Utility method called after a script is loaded and compared to
   // our current cached script.
   void