Add CSP support to service workers
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 8 Jan 2018 21:19:24 +0000 (21:19 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 8 Jan 2018 21:19:24 +0000 (21:19 +0000)
https://bugs.webkit.org/show_bug.cgi?id=181385

Patch by Youenn Fablet <youenn@apple.com> on 2018-01-08
Reviewed by Chris Dumez.

LayoutTests/imported/w3c:

* web-platform-tests/service-workers/service-worker/service-worker-csp-connect.https-expected.txt:
* web-platform-tests/service-workers/service-worker/service-worker-csp-default.https-expected.txt:
* web-platform-tests/service-workers/service-worker/service-worker-csp-script.https-expected.txt:

Source/WebCore:

Covered by rebased tests.

Added recovery of CSP information from WorkerScriptLoader.
Added plumbing to pass the CSP information to Service Workers.
Added persistency support for the CSP information.

* workers/WorkerScriptLoader.cpp:
(WebCore::WorkerScriptLoader::loadAsynchronously):
(WebCore::WorkerScriptLoader::didReceiveResponse):
* workers/WorkerScriptLoader.h:
(WebCore::WorkerScriptLoader::contentSecurityPolicy const):
* workers/service/SWClientConnection.cpp:
(WebCore::SWClientConnection::finishedFetchingScript):
(WebCore::SWClientConnection::failedFetchingScript):
* workers/service/SWClientConnection.h:
* workers/service/ServiceWorkerContainer.cpp:
(WebCore::ServiceWorkerContainer::addRegistration):
(WebCore::ServiceWorkerContainer::jobFailedWithException):
(WebCore::ServiceWorkerContainer::jobResolvedWithRegistration):
(WebCore::ServiceWorkerContainer::jobFinishedLoadingScript):
* workers/service/ServiceWorkerContainer.h:
* workers/service/ServiceWorkerContextData.cpp:
(WebCore::ServiceWorkerContextData::isolatedCopy const):
* workers/service/ServiceWorkerContextData.h:
(WebCore::ServiceWorkerContextData::encode const):
(WebCore::ServiceWorkerContextData::decode):
* workers/service/ServiceWorkerFetchResult.h:
(WebCore::ServiceWorkerFetchResult::encode const):
(WebCore::ServiceWorkerFetchResult::decode):
* workers/service/ServiceWorkerGlobalScope.cpp:
(WebCore::ServiceWorkerGlobalScope::create):
* workers/service/ServiceWorkerGlobalScope.h:
* workers/service/ServiceWorkerJob.cpp:
(WebCore::ServiceWorkerJob::notifyFinished):
* workers/service/ServiceWorkerJobClient.h:
* workers/service/context/ServiceWorkerThread.cpp:
(WebCore::ServiceWorkerThread::ServiceWorkerThread):
(WebCore::ServiceWorkerThread::createWorkerGlobalScope):
* workers/service/server/RegistrationDatabase.cpp:
(WebCore::v1RecordsTableSchema):
(WebCore::RegistrationDatabase::openSQLiteDatabase):
(WebCore::RegistrationDatabase::doPushChanges):
(WebCore::RegistrationDatabase::importRecords):
* workers/service/server/SWServer.cpp:
(WebCore::SWServer::updateWorker):
(WebCore::SWServer::installContextData):
* workers/service/server/SWServer.h:
* workers/service/server/SWServerJobQueue.cpp:
(WebCore::SWServerJobQueue::scriptFetchFinished):
* workers/service/server/SWServerWorker.cpp:
(WebCore::SWServerWorker::SWServerWorker):
(WebCore::m_contentSecurityPolicy):
(WebCore::SWServerWorker::contextData const):
* workers/service/server/SWServerWorker.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@226532 268f45cc-cd09-0410-ab3c-d52691b4dbfc

25 files changed:
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/service-worker-csp-connect.https-expected.txt
LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/service-worker-csp-default.https-expected.txt
LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/service-worker-csp-script.https-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/workers/WorkerScriptLoader.cpp
Source/WebCore/workers/WorkerScriptLoader.h
Source/WebCore/workers/service/SWClientConnection.cpp
Source/WebCore/workers/service/SWClientConnection.h
Source/WebCore/workers/service/ServiceWorkerContainer.cpp
Source/WebCore/workers/service/ServiceWorkerContainer.h
Source/WebCore/workers/service/ServiceWorkerContextData.cpp
Source/WebCore/workers/service/ServiceWorkerContextData.h
Source/WebCore/workers/service/ServiceWorkerFetchResult.h
Source/WebCore/workers/service/ServiceWorkerGlobalScope.cpp
Source/WebCore/workers/service/ServiceWorkerGlobalScope.h
Source/WebCore/workers/service/ServiceWorkerJob.cpp
Source/WebCore/workers/service/ServiceWorkerJobClient.h
Source/WebCore/workers/service/context/ServiceWorkerThread.cpp
Source/WebCore/workers/service/server/RegistrationDatabase.cpp
Source/WebCore/workers/service/server/SWServer.cpp
Source/WebCore/workers/service/server/SWServer.h
Source/WebCore/workers/service/server/SWServerJobQueue.cpp
Source/WebCore/workers/service/server/SWServerWorker.cpp
Source/WebCore/workers/service/server/SWServerWorker.h

index 7ba19da..583cc86 100644 (file)
@@ -1,5 +1,16 @@
 2018-01-08  Youenn Fablet  <youenn@apple.com>
 
+        Add CSP support to service workers
+        https://bugs.webkit.org/show_bug.cgi?id=181385
+
+        Reviewed by Chris Dumez.
+
+        * web-platform-tests/service-workers/service-worker/service-worker-csp-connect.https-expected.txt:
+        * web-platform-tests/service-workers/service-worker/service-worker-csp-default.https-expected.txt:
+        * web-platform-tests/service-workers/service-worker/service-worker-csp-script.https-expected.txt:
+
+2018-01-08  Youenn Fablet  <youenn@apple.com>
+
         Use no-cache fetch mode when loading main documents with location.reload()
         https://bugs.webkit.org/show_bug.cgi?id=181285
 
index 0ba364c..f61d262 100644 (file)
@@ -1,6 +1,6 @@
 
 PASS CSP test for connect-src in ServiceWorkerGlobalScope 
 PASS importScripts test for connect-src 
-FAIL Fetch test for connect-src assert_unreached: unexpected rejection: assert_unreached: fetch should fail. Reached unreachable code Reached unreachable code
-FAIL Redirected fetch test for connect-src assert_unreached: unexpected rejection: assert_unreached: Redirected fetch should fail. Reached unreachable code Reached unreachable code
+PASS Fetch test for connect-src 
+PASS Redirected fetch test for connect-src 
 
index 9a03306..f418cb8 100644 (file)
@@ -1,6 +1,6 @@
 
 PASS CSP test for default-src in ServiceWorkerGlobalScope 
-FAIL importScripts test for default-src assert_true: Importing the other origins script should fail. expected true got false
-FAIL Fetch test for default-src assert_unreached: unexpected rejection: assert_unreached: fetch should fail. Reached unreachable code Reached unreachable code
-FAIL Redirected fetch test for default-src assert_unreached: unexpected rejection: assert_unreached: Redirected fetch should fail. Reached unreachable code Reached unreachable code
+PASS importScripts test for default-src 
+PASS Fetch test for default-src 
+PASS Redirected fetch test for default-src 
 
index 7161593..d37a7b5 100644 (file)
@@ -1,6 +1,6 @@
 
 PASS CSP test for script-src in ServiceWorkerGlobalScope 
-FAIL importScripts test for script-src assert_true: Importing the other origins script should fail. expected true got false
+PASS importScripts test for script-src 
 PASS Fetch test for script-src 
 PASS Redirected fetch test for script-src 
 
index 1d5ad55..93cb19f 100644 (file)
@@ -1,5 +1,67 @@
 2018-01-08  Youenn Fablet  <youenn@apple.com>
 
+        Add CSP support to service workers
+        https://bugs.webkit.org/show_bug.cgi?id=181385
+
+        Reviewed by Chris Dumez.
+
+        Covered by rebased tests.
+
+        Added recovery of CSP information from WorkerScriptLoader.
+        Added plumbing to pass the CSP information to Service Workers.
+        Added persistency support for the CSP information.
+
+        * workers/WorkerScriptLoader.cpp:
+        (WebCore::WorkerScriptLoader::loadAsynchronously):
+        (WebCore::WorkerScriptLoader::didReceiveResponse):
+        * workers/WorkerScriptLoader.h:
+        (WebCore::WorkerScriptLoader::contentSecurityPolicy const):
+        * workers/service/SWClientConnection.cpp:
+        (WebCore::SWClientConnection::finishedFetchingScript):
+        (WebCore::SWClientConnection::failedFetchingScript):
+        * workers/service/SWClientConnection.h:
+        * workers/service/ServiceWorkerContainer.cpp:
+        (WebCore::ServiceWorkerContainer::addRegistration):
+        (WebCore::ServiceWorkerContainer::jobFailedWithException):
+        (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration):
+        (WebCore::ServiceWorkerContainer::jobFinishedLoadingScript):
+        * workers/service/ServiceWorkerContainer.h:
+        * workers/service/ServiceWorkerContextData.cpp:
+        (WebCore::ServiceWorkerContextData::isolatedCopy const):
+        * workers/service/ServiceWorkerContextData.h:
+        (WebCore::ServiceWorkerContextData::encode const):
+        (WebCore::ServiceWorkerContextData::decode):
+        * workers/service/ServiceWorkerFetchResult.h:
+        (WebCore::ServiceWorkerFetchResult::encode const):
+        (WebCore::ServiceWorkerFetchResult::decode):
+        * workers/service/ServiceWorkerGlobalScope.cpp:
+        (WebCore::ServiceWorkerGlobalScope::create):
+        * workers/service/ServiceWorkerGlobalScope.h:
+        * workers/service/ServiceWorkerJob.cpp:
+        (WebCore::ServiceWorkerJob::notifyFinished):
+        * workers/service/ServiceWorkerJobClient.h:
+        * workers/service/context/ServiceWorkerThread.cpp:
+        (WebCore::ServiceWorkerThread::ServiceWorkerThread):
+        (WebCore::ServiceWorkerThread::createWorkerGlobalScope):
+        * workers/service/server/RegistrationDatabase.cpp:
+        (WebCore::v1RecordsTableSchema):
+        (WebCore::RegistrationDatabase::openSQLiteDatabase):
+        (WebCore::RegistrationDatabase::doPushChanges):
+        (WebCore::RegistrationDatabase::importRecords):
+        * workers/service/server/SWServer.cpp:
+        (WebCore::SWServer::updateWorker):
+        (WebCore::SWServer::installContextData):
+        * workers/service/server/SWServer.h:
+        * workers/service/server/SWServerJobQueue.cpp:
+        (WebCore::SWServerJobQueue::scriptFetchFinished):
+        * workers/service/server/SWServerWorker.cpp:
+        (WebCore::SWServerWorker::SWServerWorker):
+        (WebCore::m_contentSecurityPolicy):
+        (WebCore::SWServerWorker::contextData const):
+        * workers/service/server/SWServerWorker.h:
+
+2018-01-08  Youenn Fablet  <youenn@apple.com>
+
         Use no-cache fetch mode when loading main documents with location.reload()
         https://bugs.webkit.org/show_bug.cgi?id=181285
 
index 16231bf..de88423 100644 (file)
@@ -134,6 +134,7 @@ void WorkerScriptLoader::didReceiveResponse(unsigned long identifier, const Reso
     m_responseURL = response.url();
     m_responseMIMEType = response.mimeType();
     m_responseEncoding = response.textEncodingName();
+    m_contentSecurityPolicy = ContentSecurityPolicyResponseHeaders { response };
     if (m_client)
         m_client->didReceiveResponse(identifier, response);
 }
index 0b8f2c5..a00fc57 100644 (file)
@@ -26,6 +26,7 @@
 
 #pragma once
 
+#include "ContentSecurityPolicyResponseHeaders.h"
 #include "ResourceError.h"
 #include "ResourceRequest.h"
 #include "ThreadableLoader.h"
@@ -58,6 +59,7 @@ public:
     void notifyError();
 
     String script();
+    const ContentSecurityPolicyResponseHeaders& contentSecurityPolicy() const { return m_contentSecurityPolicy; }
     const URL& url() const { return m_url; }
     const URL& responseURL() const;
     const String& responseMIMEType() const { return m_responseMIMEType; }
@@ -89,6 +91,7 @@ private:
     URL m_url;
     URL m_responseURL;
     String m_responseMIMEType;
+    ContentSecurityPolicyResponseHeaders m_contentSecurityPolicy;
     unsigned long m_identifier { 0 };
     bool m_failed { false };
     bool m_finishing { false };
index 1f3221f..50031d2 100644 (file)
@@ -56,19 +56,19 @@ void SWClientConnection::scheduleJob(ServiceWorkerJob& job)
     scheduleJobInServer(job.data());
 }
 
-void SWClientConnection::finishedFetchingScript(ServiceWorkerJob& job, const String& script)
+void SWClientConnection::finishedFetchingScript(ServiceWorkerJob& job, const String& script, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicy)
 {
     ASSERT(isMainThread());
     ASSERT(m_scheduledJobs.get(job.identifier()) == &job);
 
-    finishFetchingScriptInServer({ job.data().identifier(), job.data().registrationKey(), script, { } });
+    finishFetchingScriptInServer({ job.data().identifier(), job.data().registrationKey(), script, contentSecurityPolicy, { } });
 }
 
 void SWClientConnection::failedFetchingScript(const ServiceWorkerJobDataIdentifier& jobDataIdentifier, const ServiceWorkerRegistrationKey& registrationKey, const ResourceError& error)
 {
     ASSERT(isMainThread());
 
-    finishFetchingScriptInServer({ jobDataIdentifier, registrationKey, { }, error });
+    finishFetchingScriptInServer({ jobDataIdentifier, registrationKey, { }, { }, error });
 }
 
 void SWClientConnection::jobRejectedInServer(const ServiceWorkerJobDataIdentifier& jobDataIdentifier, const ExceptionData& exceptionData)
index 4ae78a3..f903d76 100644 (file)
@@ -69,7 +69,7 @@ public:
     virtual void removeServiceWorkerRegistrationInServer(ServiceWorkerRegistrationIdentifier) = 0;
 
     void scheduleJob(ServiceWorkerJob&);
-    void finishedFetchingScript(ServiceWorkerJob&, const String&);
+    void finishedFetchingScript(ServiceWorkerJob&, const String& script, const ContentSecurityPolicyResponseHeaders&);
     void failedFetchingScript(const ServiceWorkerJobDataIdentifier&, const ServiceWorkerRegistrationKey&, const ResourceError&);
 
     virtual void didResolveRegistrationPromise(const ServiceWorkerRegistrationKey&) = 0;
index 1970f0a..53015a5 100644 (file)
@@ -468,7 +468,7 @@ void ServiceWorkerContainer::startScriptFetchForJob(ServiceWorkerJob& job, Fetch
     job.fetchScriptWithContext(*context, cachePolicy);
 }
 
-void ServiceWorkerContainer::jobFinishedLoadingScript(ServiceWorkerJob& job, const String& script)
+void ServiceWorkerContainer::jobFinishedLoadingScript(ServiceWorkerJob& job, const String& script, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicy)
 {
 #ifndef NDEBUG
     ASSERT(m_creationThread.ptr() == &Thread::current());
@@ -476,8 +476,8 @@ void ServiceWorkerContainer::jobFinishedLoadingScript(ServiceWorkerJob& job, con
 
     LOG(ServiceWorker, "SeviceWorkerContainer %p finished fetching script for job %s", this, job.identifier().loggingString().utf8().data());
 
-    callOnMainThread([connection = m_swConnection, job = makeRef(job), script = script.isolatedCopy()] {
-        connection->finishedFetchingScript(job, script);
+    callOnMainThread([connection = m_swConnection, job = makeRef(job), script = script.isolatedCopy(), contentSecurityPolicy = contentSecurityPolicy.isolatedCopy()] {
+        connection->finishedFetchingScript(job, script, contentSecurityPolicy);
     });
 }
 
index 19d25f5..73bff35 100644 (file)
@@ -89,7 +89,7 @@ private:
     void jobResolvedWithRegistration(ServiceWorkerJob&, ServiceWorkerRegistrationData&&, ShouldNotifyWhenResolved) final;
     void jobResolvedWithUnregistrationResult(ServiceWorkerJob&, bool unregistrationResult) final;
     void startScriptFetchForJob(ServiceWorkerJob&, FetchOptions::Cache) final;
-    void jobFinishedLoadingScript(ServiceWorkerJob&, const String&) final;
+    void jobFinishedLoadingScript(ServiceWorkerJob&, const String& script, const ContentSecurityPolicyResponseHeaders&) final;
     void jobFailedLoadingScript(ServiceWorkerJob&, const ResourceError&, std::optional<Exception>&&) final;
 
     void jobDidFinish(ServiceWorkerJob&);
index 7f0abbe..4c4bf23 100644 (file)
@@ -32,7 +32,7 @@ namespace WebCore {
 
 ServiceWorkerContextData ServiceWorkerContextData::isolatedCopy() const
 {
-    return { jobDataIdentifier, registration.isolatedCopy(), serviceWorkerIdentifier, script.isolatedCopy(), scriptURL.isolatedCopy(), workerType, loadedFromDisk };
+    return { jobDataIdentifier, registration.isolatedCopy(), serviceWorkerIdentifier, script.isolatedCopy(), contentSecurityPolicy.isolatedCopy(), scriptURL.isolatedCopy(), workerType, loadedFromDisk };
 }
 
 } // namespace WebCore
index f3fe0dc..f5a3e09 100644 (file)
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include "ContentSecurityPolicyResponseHeaders.h"
 #include "ServiceWorkerIdentifier.h"
 #include "ServiceWorkerJobDataIdentifier.h"
 #include "ServiceWorkerRegistrationData.h"
@@ -40,10 +41,11 @@ struct ServiceWorkerContextData {
     ServiceWorkerRegistrationData registration;
     ServiceWorkerIdentifier serviceWorkerIdentifier;
     String script;
+    ContentSecurityPolicyResponseHeaders contentSecurityPolicy;
     URL scriptURL;
     WorkerType workerType;
     bool loadedFromDisk;
-    
+
     template<class Encoder> void encode(Encoder&) const;
     template<class Decoder> static std::optional<ServiceWorkerContextData> decode(Decoder&);
     
@@ -53,7 +55,7 @@ struct ServiceWorkerContextData {
 template<class Encoder>
 void ServiceWorkerContextData::encode(Encoder& encoder) const
 {
-    encoder << jobDataIdentifier << registration << serviceWorkerIdentifier << script << scriptURL << workerType << loadedFromDisk;
+    encoder << jobDataIdentifier << registration << serviceWorkerIdentifier << script << contentSecurityPolicy << scriptURL << workerType << loadedFromDisk;
 }
 
 template<class Decoder>
@@ -76,7 +78,11 @@ std::optional<ServiceWorkerContextData> ServiceWorkerContextData::decode(Decoder
     String script;
     if (!decoder.decode(script))
         return std::nullopt;
-    
+
+    ContentSecurityPolicyResponseHeaders contentSecurityPolicy;
+    if (!decoder.decode(contentSecurityPolicy))
+        return std::nullopt;
+
     URL scriptURL;
     if (!decoder.decode(scriptURL))
         return std::nullopt;
@@ -89,7 +95,7 @@ std::optional<ServiceWorkerContextData> ServiceWorkerContextData::decode(Decoder
     if (!decoder.decode(loadedFromDisk))
         return std::nullopt;
 
-    return {{ WTFMove(*jobDataIdentifier), WTFMove(*registration), WTFMove(*serviceWorkerIdentifier), WTFMove(script), WTFMove(scriptURL), workerType, loadedFromDisk}};
+    return {{ WTFMove(*jobDataIdentifier), WTFMove(*registration), WTFMove(*serviceWorkerIdentifier), WTFMove(script), WTFMove(contentSecurityPolicy), WTFMove(scriptURL), workerType, loadedFromDisk }};
 }
 
 } // namespace WebCore
index 714f857..e0a5999 100644 (file)
@@ -27,6 +27,7 @@
 
 #if ENABLE(SERVICE_WORKER)
 
+#include "ContentSecurityPolicyResponseHeaders.h"
 #include "ResourceError.h"
 #include "ServiceWorkerRegistrationKey.h"
 #include "ServiceWorkerTypes.h"
@@ -37,6 +38,7 @@ struct ServiceWorkerFetchResult {
     ServiceWorkerJobDataIdentifier jobDataIdentifier;
     ServiceWorkerRegistrationKey registrationKey;
     String script;
+    ContentSecurityPolicyResponseHeaders contentSecurityPolicy;
     ResourceError scriptError;
 
     template<class Encoder> void encode(Encoder&) const;
@@ -46,7 +48,7 @@ struct ServiceWorkerFetchResult {
 template<class Encoder>
 void ServiceWorkerFetchResult::encode(Encoder& encoder) const
 {
-    encoder << jobDataIdentifier << registrationKey << script << scriptError;
+    encoder << jobDataIdentifier << registrationKey << script << contentSecurityPolicy << scriptError;
 }
 
 template<class Decoder>
@@ -65,6 +67,8 @@ bool ServiceWorkerFetchResult::decode(Decoder& decoder, ServiceWorkerFetchResult
 
     if (!decoder.decode(result.script))
         return false;
+    if (!decoder.decode(result.contentSecurityPolicy))
+        return false;
     if (!decoder.decode(result.scriptError))
         return false;
 
index 48828d9..bbf56a6 100644 (file)
 
 namespace WebCore {
 
+Ref<ServiceWorkerGlobalScope> ServiceWorkerGlobalScope::create(const ServiceWorkerContextData& data, const URL& url, const String& identifier, const String& userAgent, bool isOnline, ServiceWorkerThread& thread, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicy, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, MonotonicTime timeOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider, PAL::SessionID sessionID)
+{
+    auto scope = adoptRef(*new ServiceWorkerGlobalScope { data, url, identifier, userAgent, isOnline, thread, shouldBypassMainWorldContentSecurityPolicy, WTFMove(topOrigin), timeOrigin, connectionProxy, socketProvider, sessionID });
+    scope->applyContentSecurityPolicyResponseHeaders(contentSecurityPolicy);
+    return scope;
+}
+
 ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(const ServiceWorkerContextData& data, const URL& url, const String& identifier, const String& userAgent, bool isOnline, ServiceWorkerThread& thread, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, MonotonicTime timeOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider, PAL::SessionID sessionID)
     : WorkerGlobalScope(url, identifier, userAgent, isOnline, thread, shouldBypassMainWorldContentSecurityPolicy, WTFMove(topOrigin), timeOrigin, connectionProxy, socketProvider, sessionID)
     , m_contextData(crossThreadCopy(data))
index 211431e..1544307 100644 (file)
@@ -43,10 +43,7 @@ class ServiceWorkerThread;
 
 class ServiceWorkerGlobalScope final : public WorkerGlobalScope {
 public:
-    template<typename... Args> static Ref<ServiceWorkerGlobalScope> create(Args&&... args)
-    {
-        return adoptRef(*new ServiceWorkerGlobalScope(std::forward<Args>(args)...));
-    }
+    static Ref<ServiceWorkerGlobalScope> create(const ServiceWorkerContextData&, const URL&, const String& identifier, const String& userAgent, bool isOnline, ServiceWorkerThread&, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, MonotonicTime timeOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*, PAL::SessionID);
 
     ~ServiceWorkerGlobalScope();
 
index e3b0630..6197253 100644 (file)
@@ -142,7 +142,7 @@ void ServiceWorkerJob::notifyFinished()
     ASSERT(m_scriptLoader);
     
     if (!m_scriptLoader->failed())
-        m_client->jobFinishedLoadingScript(*this, m_scriptLoader->script());
+        m_client->jobFinishedLoadingScript(*this, m_scriptLoader->script(), m_scriptLoader->contentSecurityPolicy());
     else {
         auto& error =  m_scriptLoader->error();
         ASSERT(!error.isNull());
index a4cda6c..6737eca 100644 (file)
@@ -32,6 +32,7 @@
 
 namespace WebCore {
 
+class ContentSecurityPolicyResponseHeaders;
 class Exception;
 class ResourceError;
 class ServiceWorkerJob;
@@ -48,7 +49,7 @@ public:
     virtual void jobResolvedWithRegistration(ServiceWorkerJob&, ServiceWorkerRegistrationData&&, ShouldNotifyWhenResolved) = 0;
     virtual void jobResolvedWithUnregistrationResult(ServiceWorkerJob&, bool unregistrationResult) = 0;
     virtual void startScriptFetchForJob(ServiceWorkerJob&, FetchOptions::Cache) = 0;
-    virtual void jobFinishedLoadingScript(ServiceWorkerJob&, const String&) = 0;
+    virtual void jobFinishedLoadingScript(ServiceWorkerJob&, const String& script, const ContentSecurityPolicyResponseHeaders&) = 0;
     virtual void jobFailedLoadingScript(ServiceWorkerJob&, const ResourceError&, std::optional<Exception>&&) = 0;
 
     virtual SWServerConnectionIdentifier connectionIdentifier() = 0;
index d9d7d7c..764bfef 100644 (file)
@@ -71,7 +71,7 @@ private:
 // FIXME: Use valid runtime flags
 
 ServiceWorkerThread::ServiceWorkerThread(const ServiceWorkerContextData& data, PAL::SessionID, String&& userAgent, WorkerLoaderProxy& loaderProxy, WorkerDebuggerProxy& debuggerProxy, IDBClient::IDBConnectionProxy* idbConnectionProxy, SocketProvider* socketProvider)
-    : WorkerThread(data.scriptURL, "serviceworker:" + Inspector::IdentifiersFactory::createIdentifier(), WTFMove(userAgent), NetworkStateNotifier::singleton().onLine(), data.script, loaderProxy, debuggerProxy, DummyServiceWorkerThreadProxy::shared(), WorkerThreadStartMode::Normal, ContentSecurityPolicyResponseHeaders { }, false, SecurityOrigin::create(data.scriptURL).get(), MonotonicTime::now(), idbConnectionProxy, socketProvider, JSC::RuntimeFlags::createAllEnabled(), SessionID::defaultSessionID())
+    : WorkerThread(data.scriptURL, "serviceworker:" + Inspector::IdentifiersFactory::createIdentifier(), WTFMove(userAgent), NetworkStateNotifier::singleton().onLine(), data.script, loaderProxy, debuggerProxy, DummyServiceWorkerThreadProxy::shared(), WorkerThreadStartMode::Normal, data.contentSecurityPolicy, false, SecurityOrigin::create(data.scriptURL).get(), MonotonicTime::now(), idbConnectionProxy, socketProvider, JSC::RuntimeFlags::createAllEnabled(), SessionID::defaultSessionID())
     , m_data(data.isolatedCopy())
     , m_workerObjectProxy(DummyServiceWorkerThreadProxy::shared())
 {
@@ -80,9 +80,9 @@ ServiceWorkerThread::ServiceWorkerThread(const ServiceWorkerContextData& data, P
 
 ServiceWorkerThread::~ServiceWorkerThread() = default;
 
-Ref<WorkerGlobalScope> ServiceWorkerThread::createWorkerGlobalScope(const URL& url, const String& identifier, const String& userAgent, bool isOnline, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, MonotonicTime timeOrigin, PAL::SessionID sessionID)
+Ref<WorkerGlobalScope> ServiceWorkerThread::createWorkerGlobalScope(const URL& url, const String& identifier, const String& userAgent, bool isOnline, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicy, bool shouldBypassMainWorldContentSecurityPolicy, Ref<SecurityOrigin>&& topOrigin, MonotonicTime timeOrigin, PAL::SessionID sessionID)
 {
-    return ServiceWorkerGlobalScope::create(m_data, url, identifier, userAgent, isOnline, *this, shouldBypassMainWorldContentSecurityPolicy, WTFMove(topOrigin), timeOrigin, idbConnectionProxy(), socketProvider(), sessionID);
+    return ServiceWorkerGlobalScope::create(m_data, url, identifier, userAgent, isOnline, *this, contentSecurityPolicy, shouldBypassMainWorldContentSecurityPolicy, WTFMove(topOrigin), timeOrigin, idbConnectionProxy(), socketProvider(), sessionID);
 }
 
 void ServiceWorkerThread::runEventLoop()
index 8710b0e..3c438c9 100644 (file)
 #include <wtf/MainThread.h>
 #include <wtf/NeverDestroyed.h>
 #include <wtf/Scope.h>
+#include <wtf/persistence/PersistentCoders.h>
+#include <wtf/persistence/PersistentDecoder.h>
+#include <wtf/persistence/PersistentEncoder.h>
 
 namespace WebCore {
 
 static const String v1RecordsTableSchema(const String& tableName)
 {
-    return makeString("CREATE TABLE ", tableName, " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE, origin TEXT NOT NULL ON CONFLICT FAIL, scopeURL TEXT NOT NULL ON CONFLICT FAIL, topOrigin TEXT NOT NULL ON CONFLICT FAIL, lastUpdateCheckTime DOUBLE NOT NULL ON CONFLICT FAIL, updateViaCache TEXT NOT NULL ON CONFLICT FAIL, scriptURL TEXT NOT NULL ON CONFLICT FAIL, script TEXT NOT NULL ON CONFLICT FAIL, workerType TEXT NOT NULL ON CONFLICT FAIL)");
+    return makeString("CREATE TABLE ", tableName, " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE, origin TEXT NOT NULL ON CONFLICT FAIL, scopeURL TEXT NOT NULL ON CONFLICT FAIL, topOrigin TEXT NOT NULL ON CONFLICT FAIL, lastUpdateCheckTime DOUBLE NOT NULL ON CONFLICT FAIL, updateViaCache TEXT NOT NULL ON CONFLICT FAIL, scriptURL TEXT NOT NULL ON CONFLICT FAIL, script TEXT NOT NULL ON CONFLICT FAIL, workerType TEXT NOT NULL ON CONFLICT FAIL, contentSecurityPolicy BLOB NOT NULL ON CONFLICT FAIL)");
 }
 
 static const String v1RecordsTableSchema()
@@ -118,7 +121,7 @@ void RegistrationDatabase::openSQLiteDatabase(const String& fullFilename)
     errorMessage = importRecords();
     if (!errorMessage.isNull())
         return;
-    
+
     scopeExit.release();
 }
 
@@ -258,7 +261,7 @@ void RegistrationDatabase::doPushChanges(Vector<ServiceWorkerContextData>&& data
     SQLiteTransaction transaction(*m_database);
     transaction.begin();
 
-    SQLiteStatement sql(*m_database, ASCIILiteral("INSERT INTO Records VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"));
+    SQLiteStatement sql(*m_database, ASCIILiteral("INSERT INTO Records VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
     if (sql.prepare() != SQLITE_OK) {
         RELEASE_LOG_ERROR(ServiceWorker, "Failed to prepare statement to store registration data into records table (%i) - %s", m_database->lastError(), m_database->lastErrorMsg());
         return;
@@ -277,6 +280,9 @@ void RegistrationDatabase::doPushChanges(Vector<ServiceWorkerContextData>&& data
             continue;
         }
 
+        WTF::Persistence::Encoder encoder;
+        data.contentSecurityPolicy.encode(encoder);
+
         if (sql.bindText(1, data.registration.key.toDatabaseKey()) != SQLITE_OK
             || sql.bindText(2, data.registration.scopeURL.protocolHostAndPort()) != SQLITE_OK
             || sql.bindText(3, data.registration.scopeURL.path()) != SQLITE_OK
@@ -286,6 +292,7 @@ void RegistrationDatabase::doPushChanges(Vector<ServiceWorkerContextData>&& data
             || sql.bindText(7, data.scriptURL.string()) != SQLITE_OK
             || sql.bindText(8, data.script) != SQLITE_OK
             || sql.bindText(9, workerTypeToString(data.workerType)) != SQLITE_OK
+            || sql.bindBlob(10, encoder.buffer(), encoder.bufferSize()) != SQLITE_OK
             || sql.step() != SQLITE_DONE) {
             RELEASE_LOG_ERROR(ServiceWorker, "Failed to store registration data into records table (%i) - %s", m_database->lastError(), m_database->lastErrorMsg());
             return;
@@ -318,6 +325,13 @@ String RegistrationDatabase::importRecords()
         auto script = sql.getColumnText(7);
         auto workerType = stringToWorkerType(sql.getColumnText(8));
 
+        Vector<uint8_t> contentSecurityPolicyData;
+        sql.getColumnBlobAsVector(9, contentSecurityPolicyData);
+        WTF::Persistence::Decoder decoder(contentSecurityPolicyData.data(), contentSecurityPolicyData.size());
+        ContentSecurityPolicyResponseHeaders contentSecurityPolicy;
+        if (contentSecurityPolicyData.size() && !ContentSecurityPolicyResponseHeaders::decode(decoder, contentSecurityPolicy))
+            continue;
+
         // Validate the input for this registration.
         // If any part of this input is invalid, let's skip this registration.
         // FIXME: Should we return an error skipping *all* registrations?
@@ -328,7 +342,7 @@ String RegistrationDatabase::importRecords()
         auto registrationIdentifier = generateObjectIdentifier<ServiceWorkerRegistrationIdentifierType>();
         auto serviceWorkerData = ServiceWorkerData { workerIdentifier, scriptURL, ServiceWorkerState::Activated, *workerType, registrationIdentifier };
         auto registration = ServiceWorkerRegistrationData { WTFMove(*key), registrationIdentifier, URL(originURL, scopePath), *updateViaCache, lastUpdateCheckTime, std::nullopt, std::nullopt, WTFMove(serviceWorkerData) };
-        auto contextData = ServiceWorkerContextData { std::nullopt, WTFMove(registration), workerIdentifier, WTFMove(script), WTFMove(scriptURL), *workerType, true };
+        auto contextData = ServiceWorkerContextData { std::nullopt, WTFMove(registration), workerIdentifier, WTFMove(script), WTFMove(contentSecurityPolicy), WTFMove(scriptURL), *workerType, true };
 
         postTaskReply(createCrossThreadTask(*this, &RegistrationDatabase::addRegistrationToStore, WTFMove(contextData)));
     }
index 68addee..0e7b420 100644 (file)
@@ -431,10 +431,10 @@ void SWServer::removeClientServiceWorkerRegistration(Connection& connection, Ser
     registration->removeClientServiceWorkerRegistration(connection.identifier());
 }
 
-void SWServer::updateWorker(Connection&, const ServiceWorkerJobDataIdentifier& jobDataIdentifier, SWServerRegistration& registration, const URL& url, const String& script, WorkerType type)
+void SWServer::updateWorker(Connection&, const ServiceWorkerJobDataIdentifier& jobDataIdentifier, SWServerRegistration& registration, const URL& url, const String& script, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicy, WorkerType type)
 {
     registration.setLastUpdateTime(WallTime::now());
-    tryInstallContextData({ jobDataIdentifier, registration.data(), generateObjectIdentifier<ServiceWorkerIdentifierType>(), script, url, type, false });
+    tryInstallContextData({ jobDataIdentifier, registration.data(), generateObjectIdentifier<ServiceWorkerIdentifierType>(), script, contentSecurityPolicy, url, type, false });
 }
 
 void SWServer::tryInstallContextData(ServiceWorkerContextData&& data)
@@ -478,7 +478,7 @@ void SWServer::installContextData(const ServiceWorkerContextData& data)
     auto* registration = m_registrations.get(data.registration.key);
     RELEASE_ASSERT(registration);
 
-    auto worker = SWServerWorker::create(*this, *registration, connection->identifier(), data.scriptURL, data.script, data.workerType, data.serviceWorkerIdentifier);
+    auto worker = SWServerWorker::create(*this, *registration, connection->identifier(), data.scriptURL, data.script, data.contentSecurityPolicy, data.workerType, data.serviceWorkerIdentifier);
 
     // We don't immediately launch all workers that were just read in from disk,
     // as it is unlikely they will be needed immediately.
index 66d6e5e..4d80776 100644 (file)
@@ -140,7 +140,7 @@ public:
     void postTask(CrossThreadTask&&);
     void postTaskReply(CrossThreadTask&&);
 
-    void updateWorker(Connection&, const ServiceWorkerJobDataIdentifier&, SWServerRegistration&, const URL&, const String& script, WorkerType);
+    void updateWorker(Connection&, const ServiceWorkerJobDataIdentifier&, SWServerRegistration&, const URL&, const String& script, const ContentSecurityPolicyResponseHeaders&, WorkerType);
     void terminateWorker(SWServerWorker&);
     void syncTerminateWorker(SWServerWorker&);
     void fireInstallEvent(SWServerWorker&);
index 8eba7a0..bd8e200 100644 (file)
@@ -96,7 +96,7 @@ void SWServerJobQueue::scriptFetchFinished(SWServer::Connection& connection, con
     }
 
     // FIXME: Support the proper worker type (classic vs module)
-    m_server.updateWorker(connection, job.identifier(), *registration, job.scriptURL, result.script, WorkerType::Classic);
+    m_server.updateWorker(connection, job.identifier(), *registration, job.scriptURL, result.script, result.contentSecurityPolicy, WorkerType::Classic);
 }
 
 // https://w3c.github.io/ServiceWorker/#update-algorithm
index f8ee2de..ff42551 100644 (file)
@@ -43,12 +43,14 @@ SWServerWorker* SWServerWorker::existingWorkerForIdentifier(ServiceWorkerIdentif
     return allWorkers().get(identifier);
 }
 
-SWServerWorker::SWServerWorker(SWServer& server, SWServerRegistration& registration, SWServerToContextConnectionIdentifier contextConnectionIdentifier, const URL& scriptURL, const String& script, WorkerType type, ServiceWorkerIdentifier identifier)
+// FIXME: Use r-value references for script and contentSecurityPolicy
+SWServerWorker::SWServerWorker(SWServer& server, SWServerRegistration& registration, SWServerToContextConnectionIdentifier contextConnectionIdentifier, const URL& scriptURL, const String& script, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicy, WorkerType type, ServiceWorkerIdentifier identifier)
     : m_server(server)
     , m_registrationKey(registration.key())
     , m_contextConnectionIdentifier(contextConnectionIdentifier)
     , m_data { identifier, scriptURL, ServiceWorkerState::Redundant, type, registration.identifier() }
     , m_script(script)
+    , m_contentSecurityPolicy(contentSecurityPolicy)
 {
     m_data.scriptURL.removeFragmentIdentifier();
 
@@ -69,7 +71,7 @@ ServiceWorkerContextData SWServerWorker::contextData() const
     auto* registration = m_server.getRegistration(m_registrationKey);
     ASSERT(registration);
 
-    return { std::nullopt, registration->data(), m_data.identifier, m_script, m_data.scriptURL, m_data.type, false };
+    return { std::nullopt, registration->data(), m_data.identifier, m_script, m_contentSecurityPolicy, m_data.scriptURL, m_data.type, false };
 }
 
 void SWServerWorker::terminate()
index 38c1129..b429b8e 100644 (file)
@@ -104,7 +104,7 @@ public:
     const ClientOrigin& origin() const;
 
 private:
-    SWServerWorker(SWServer&, SWServerRegistration&, SWServerToContextConnectionIdentifier, const URL&, const String& script, WorkerType, ServiceWorkerIdentifier);
+    SWServerWorker(SWServer&, SWServerRegistration&, SWServerToContextConnectionIdentifier, const URL&, const String& script, const ContentSecurityPolicyResponseHeaders&,  WorkerType, ServiceWorkerIdentifier);
 
     void callWhenActivatedHandler(bool success);
 
@@ -113,6 +113,7 @@ private:
     SWServerToContextConnectionIdentifier m_contextConnectionIdentifier;
     ServiceWorkerData m_data;
     String m_script;
+    ContentSecurityPolicyResponseHeaders m_contentSecurityPolicy;
     bool m_hasPendingEvents { false };
     State m_state { State::NotRunning };
     mutable std::optional<ClientOrigin> m_origin;