Bug 1174106 - Part 3: ImportScripts() in SW should use the same http cache bypass settings as its top level SW script; r?rickychien draft
authorHo-Pang Hsu <hopang.hsu@gmail.com>
Thu, 10 Nov 2016 17:33:52 +0800
changeset 437087 166d2df342a77e562914174fb1d0660647f18ecf
parent 437086 0b3fdb741747d77f50720129d53ec09e8657003c
child 437088 e281c1d92236ae3d93b4e0bd903cfee099fb5241
push id35320
push userbmo:bhsu@mozilla.com
push dateThu, 10 Nov 2016 10:05:34 +0000
reviewersrickychien
bugs1174106
milestone52.0a1
Bug 1174106 - Part 3: ImportScripts() in SW should use the same http cache bypass settings as its top level SW script; r?rickychien MozReview-Commit-ID: AxPStlhMjkQ
dom/workers/ScriptLoader.cpp
dom/workers/ServiceWorkerInfo.cpp
dom/workers/ServiceWorkerInfo.h
dom/workers/ServiceWorkerManager.cpp
dom/workers/ServiceWorkerPrivate.cpp
dom/workers/ServiceWorkerUpdateJob.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/Workers.h
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -216,16 +216,17 @@ ChannelFromScriptURL(nsIPrincipal* princ
   return rv;
 }
 
 struct ScriptLoadInfo
 {
   ScriptLoadInfo()
   : mScriptTextBuf(nullptr)
   , mScriptTextLength(0)
+  , mHttpCacheSetting(WorkerLoadInfo::Normal)
   , mLoadResult(NS_ERROR_NOT_INITIALIZED)
   , mLoadingFinished(false)
   , mExecutionScheduled(false)
   , mExecutionResult(false)
   , mCacheStatus(Uncached)
   { }
 
   ~ScriptLoadInfo()
@@ -256,16 +257,18 @@ struct ScriptLoadInfo
   // The reader stream the cache entry should be filled from, for those cases
   // when we're going to have an mCachePromise.
   nsCOMPtr<nsIInputStream> mCacheReadStream;
 
   nsCOMPtr<nsIChannel> mChannel;
   char16_t* mScriptTextBuf;
   size_t mScriptTextLength;
 
+  WorkerLoadInfo::HttpCacheSetting mHttpCacheSetting;
+
   nsresult mLoadResult;
   bool mLoadingFinished;
   bool mExecutionScheduled;
   bool mExecutionResult;
 
   enum CacheStatus {
     // By default a normal script is just loaded from the network. But for
     // ServiceWorkers, we have to check if the cache contains the script and
@@ -926,16 +929,28 @@ private:
 
     // If we are loading a script for a ServiceWorker then we must not
     // try to intercept it.  If the interception matches the current
     // ServiceWorker's scope then we could deadlock the load.
     if (mWorkerPrivate->IsServiceWorker()) {
       loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
     }
 
+    switch (loadInfo.mHttpCacheSetting) {
+      case WorkerLoadInfo::NoCache:
+        loadFlags |= nsIRequest::VALIDATE_ALWAYS;
+        break;
+      case WorkerLoadInfo::Restore:
+        loadFlags |= nsIRequest::LOAD_BYPASS_CACHE;
+        break;
+      default:
+        // Do nothing
+        break;
+    }
+
     if (!channel) {
       // Only top level workers' main script use the document charset for the
       // script uri encoding. Otherwise, default encoding (UTF-8) is applied.
       bool useDefaultEncoding = !(!parentWorker && IsMainWorkerScript());
       rv = ChannelFromScriptURL(principal, baseURI, parentDoc, loadGroup, ios,
                                 secMan, loadInfo.mURL, IsMainWorkerScript(),
                                 mWorkerScriptType,
                                 mWorkerPrivate->ContentPolicyType(), loadFlags,
@@ -2241,16 +2256,23 @@ LoadMainScript(WorkerPrivate* aWorkerPri
                const nsAString& aScriptURL,
                WorkerScriptType aWorkerScriptType,
                ErrorResult& aRv)
 {
   nsTArray<ScriptLoadInfo> loadInfos;
 
   ScriptLoadInfo* info = loadInfos.AppendElement();
   info->mURL = aScriptURL;
+  // For a service worker, before trying to load the main script here, the new
+  // script has already been loaded into http cache when comparing with the
+  // stale copy in the DOM cache. Thus, we don't have to actually download it
+  // again here.
+  info->mHttpCacheSetting =
+    aWorkerPrivate->IsServiceWorker() ? WorkerLoadInfo::Normal
+                                      : aWorkerPrivate->HttpCacheSetting();
 
   LoadAllScripts(aWorkerPrivate, loadInfos, true, aWorkerScriptType, aRv);
 }
 
 void
 Load(WorkerPrivate* aWorkerPrivate,
      const nsTArray<nsString>& aScriptURLs, WorkerScriptType aWorkerScriptType,
      ErrorResult& aRv)
@@ -2266,16 +2288,17 @@ Load(WorkerPrivate* aWorkerPrivate,
     return;
   }
 
   nsTArray<ScriptLoadInfo> loadInfos;
   loadInfos.SetLength(urlCount);
 
   for (uint32_t index = 0; index < urlCount; index++) {
     loadInfos[index].mURL = aScriptURLs[index];
+    loadInfos[index].mHttpCacheSetting = aWorkerPrivate->HttpCacheSetting();
   }
 
   LoadAllScripts(aWorkerPrivate, loadInfos, false, aWorkerScriptType, aRv);
 }
 
 } // namespace scriptloader
 
 END_WORKERS_NAMESPACE
--- a/dom/workers/ServiceWorkerInfo.cpp
+++ b/dom/workers/ServiceWorkerInfo.cpp
@@ -166,25 +166,27 @@ ServiceWorkerInfo::UpdateState(ServiceWo
   if (mState == ServiceWorkerState::Redundant) {
     serviceWorkerScriptCache::PurgeCache(mPrincipal, mCacheName);
   }
 }
 
 ServiceWorkerInfo::ServiceWorkerInfo(nsIPrincipal* aPrincipal,
                                      const nsACString& aScope,
                                      const nsACString& aScriptSpec,
-                                     const nsAString& aCacheName)
+                                     const nsAString& aCacheName,
+                                     WorkerLoadInfo::HttpCacheSetting aHttpCacheSetting)
   : mPrincipal(aPrincipal)
   , mScope(aScope)
   , mScriptSpec(aScriptSpec)
   , mCacheName(aCacheName)
   , mState(ServiceWorkerState::EndGuard_)
   , mServiceWorkerID(GetNextID())
   , mServiceWorkerPrivate(new ServiceWorkerPrivate(this))
   , mSkipWaitingFlag(false)
+  , mHttpCacheSetting(aHttpCacheSetting)
 {
   MOZ_ASSERT(mPrincipal);
   // cache origin attributes so we can use them off main thread
   mOriginAttributes = BasePrincipal::Cast(mPrincipal)->OriginAttributesRef();
   MOZ_ASSERT(!mScope.IsEmpty());
   MOZ_ASSERT(!mScriptSpec.IsEmpty());
   MOZ_ASSERT(!mCacheName.IsEmpty());
 }
--- a/dom/workers/ServiceWorkerInfo.h
+++ b/dom/workers/ServiceWorkerInfo.h
@@ -40,16 +40,17 @@ private:
   // We hold rawptrs since the ServiceWorker constructor and destructor ensure
   // addition and removal.
   // There is a high chance of there being at least one ServiceWorker
   // associated with this all the time.
   AutoTArray<ServiceWorker*, 1> mInstances;
 
   RefPtr<ServiceWorkerPrivate> mServiceWorkerPrivate;
   bool mSkipWaitingFlag;
+  WorkerLoadInfo::HttpCacheSetting mHttpCacheSetting;
 
   ~ServiceWorkerInfo();
 
   // Generates a unique id for the service worker, with zero being treated as
   // invalid.
   uint64_t
   GetNextID() const;
 
@@ -83,26 +84,33 @@ public:
   }
 
   bool SkipWaitingFlag() const
   {
     AssertIsOnMainThread();
     return mSkipWaitingFlag;
   }
 
+  WorkerLoadInfo::HttpCacheSetting
+  HttpCacheSetting() const
+  {
+    return mHttpCacheSetting;
+  }
+
   void SetSkipWaitingFlag()
   {
     AssertIsOnMainThread();
     mSkipWaitingFlag = true;
   }
 
   ServiceWorkerInfo(nsIPrincipal* aPrincipal,
                     const nsACString& aScope,
                     const nsACString& aScriptSpec,
-                    const nsAString& aCacheName);
+                    const nsAString& aCacheName,
+                    WorkerLoadInfo::HttpCacheSetting aHttpCacheSetting);
 
   ServiceWorkerState
   State() const
   {
     return mState;
   }
 
   const PrincipalOriginAttributes&
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -1692,17 +1692,17 @@ ServiceWorkerManager::LoadRegistration(
       return;
     }
   }
 
   const nsCString& currentWorkerURL = aRegistration.currentWorkerURL();
   if (!currentWorkerURL.IsEmpty()) {
     registration->SetActive(
       new ServiceWorkerInfo(registration->mPrincipal, registration->mScope,
-                            currentWorkerURL, aRegistration.cacheName()));
+                            currentWorkerURL, aRegistration.cacheName(), WorkerLoadInfo::Restore));
     registration->GetActive()->SetActivateStateUncheckedWithoutEvent(ServiceWorkerState::Activated);
   }
 }
 
 void
 ServiceWorkerManager::LoadRegistrations(
                   const nsTArray<ServiceWorkerRegistrationData>& aRegistrations)
 {
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -1700,16 +1700,18 @@ ServiceWorkerPrivate::SpawnWorkerIfNeede
 
   info.mResolvedScriptURI = info.mBaseURI;
   MOZ_ASSERT(!mInfo->CacheName().IsEmpty());
   info.mServiceWorkerCacheName = mInfo->CacheName();
   info.mServiceWorkerID = mInfo->ID();
   info.mLoadGroup = aLoadGroup;
   info.mLoadFailedAsyncRunnable = aLoadFailedRunnable;
 
+  info.mHttpCacheSetting = mInfo->HttpCacheSetting();
+
   rv = info.mBaseURI->GetHost(info.mDomain);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   info.mPrincipal = mInfo->GetPrincipal();
 
   nsContentUtils::StorageAccess access =
--- a/dom/workers/ServiceWorkerUpdateJob.cpp
+++ b/dom/workers/ServiceWorkerUpdateJob.cpp
@@ -408,21 +408,33 @@ ServiceWorkerUpdateJob::ComparisonResult
   if (aInCacheAndEqual) {
     Finish(NS_OK);
     return;
   }
 
   Telemetry::Accumulate(Telemetry::SERVICE_WORKER_UPDATED, 1);
 
   // Begin step 7 of the Update algorithm to evaluate the new script.
+  WorkerLoadInfo::HttpCacheSetting httpCacheSetting = WorkerLoadInfo::Normal;
+  switch (mType) {
+    case Type::Update:
+      httpCacheSetting = WorkerLoadInfo::Restore;
+      break;
+    case Type::Register:
+      httpCacheSetting = mBypassHttpCache ? WorkerLoadInfo::NoCache
+                                          : WorkerLoadInfo::Normal;
+      break;
+    default:
+      MOZ_ASSERT_UNREACHABLE("Can only be triggered by register or update");
+  };
 
   RefPtr<ServiceWorkerInfo> sw =
     new ServiceWorkerInfo(mRegistration->mPrincipal,
                           mRegistration->mScope,
-                          mScriptSpec, aNewCacheName);
+                          mScriptSpec, aNewCacheName, httpCacheSetting);
 
   mRegistration->SetEvaluating(sw);
 
   nsMainThreadPtrHandle<ServiceWorkerUpdateJob> handle(
       new nsMainThreadPtrHolder<ServiceWorkerUpdateJob>(this));
   RefPtr<LifeCycleEventCallback> callback = new ContinueUpdateRunnable(handle);
 
   ServiceWorkerPrivate* workerPrivate = sw->WorkerPrivate();
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1726,16 +1726,17 @@ WorkerLoadInfo::StealFrom(WorkerLoadInfo
   mFromWindow = aOther.mFromWindow;
   mEvalAllowed = aOther.mEvalAllowed;
   mReportCSPViolations = aOther.mReportCSPViolations;
   mXHRParamsAllowed = aOther.mXHRParamsAllowed;
   mPrincipalIsSystem = aOther.mPrincipalIsSystem;
   mStorageAllowed = aOther.mStorageAllowed;
   mServiceWorkersTestingInWindow = aOther.mServiceWorkersTestingInWindow;
   mOriginAttributes = aOther.mOriginAttributes;
+  mHttpCacheSetting = aOther.mHttpCacheSetting;
 }
 
 template <class Derived>
 class WorkerPrivateParent<Derived>::EventTarget final
   : public nsIEventTarget
 {
   // This mutex protects mWorkerPrivate and must be acquired *before* the
   // WorkerPrivate's mutex whenever they must both be held.
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -510,16 +510,22 @@ public:
 
   nsIURI*
   GetResolvedScriptURI() const
   {
     AssertIsOnMainThread();
     return mLoadInfo.mResolvedScriptURI;
   }
 
+  WorkerLoadInfo::HttpCacheSetting
+  HttpCacheSetting() const
+  {
+    return mLoadInfo.mHttpCacheSetting;
+  }
+
   const nsString&
   ServiceWorkerCacheName() const
   {
     MOZ_ASSERT(IsServiceWorker());
     AssertIsOnMainThread();
     return mLoadInfo.mServiceWorkerCacheName;
   }
 
--- a/dom/workers/Workers.h
+++ b/dom/workers/Workers.h
@@ -267,16 +267,24 @@ struct WorkerLoadInfo
   bool mEvalAllowed;
   bool mReportCSPViolations;
   bool mXHRParamsAllowed;
   bool mPrincipalIsSystem;
   bool mStorageAllowed;
   bool mServiceWorkersTestingInWindow;
   PrincipalOriginAttributes mOriginAttributes;
 
+  enum HttpCacheSetting {
+    Normal,
+    NoCache,
+    Restore
+  };
+
+  HttpCacheSetting mHttpCacheSetting;
+
   WorkerLoadInfo();
   ~WorkerLoadInfo();
 
   void StealFrom(WorkerLoadInfo& aOther);
 };
 
 // All of these are implemented in RuntimeService.cpp