Enable ServiceWorker to fetch resources
https://bugs.webkit.org/show_bug.cgi?id=178673

Patch by Youenn Fablet <youenn@apple.com> on 2017-10-25
Reviewed by Brady Eidson.

Source/WebCore:

Test: http/tests/workers/service/service-worker-fetch.html

Allow reusing of EmptyFrameLoaderClient for network loading in WebKit Service Worker environment.
Allow overriding the creation of a document loader, pageID, frameID and sessionID getters.

Allow the possibility to create synthetic documents for all ports.

Beefing up ServiceWorkerThreadProxy as it owns a Document and a Page that do nothing but server
the purpose of loading resources for a service worker thread.

* WebCore.xcodeproj/project.pbxproj:
* loader/DocumentLoader.h:
(WebCore::DocumentLoader::setResponse):
* loader/EmptyClients.cpp:
(WebCore::EmptyFrameLoaderClient::sessionID const):
(WebCore::EmptyFrameLoaderClient::createNetworkingContext):
(WebCore::createEmptyFrameNetworkingContext):
* loader/EmptyClients.h:
* loader/EmptyFrameLoaderClient.h: Added.
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::initForSynthesizedDocument):
* loader/FrameLoader.h:
* loader/FrameLoaderClient.h:
* workers/service/context/ServiceWorkerThread.cpp:
(WebCore::ServiceWorkerThread::ServiceWorkerThread):
(WebCore::m_workerObjectProxy):
* workers/service/context/ServiceWorkerThread.h:
* workers/service/context/ServiceWorkerThreadProxy.cpp:
(WebCore::ServiceWorkerThreadProxy::create):
(WebCore::createPageForServiceWorker):
(WebCore::ServiceWorkerThreadProxy::ServiceWorkerThreadProxy):
(WebCore::ServiceWorkerThreadProxy::postTaskToLoader):
* workers/service/context/ServiceWorkerThreadProxy.h:
Test: http/tests/workers/service/service-worker-fetch.html

Source/WebKit:

ServiceWorkerContextManager makes use of the new ServiceWorkerThreadProxy.
It creates the necessary environment for the thread to make use of network loads, web sockets and cache storage.
Fetch is functional with these changes.

ServiceWorkerProcessProxy is introduced as a UIProcess proxy to the service worker process.
This process proxy is responsible to give the pageID used by all service worker thread instances for network loads.
ServiceWorkerContextManager is responsible to give a unique frameID for all service worker threads.
This is necessary as these two ids are currently needed for any network load.

ServiceWorkerThreadProxy creates its own FrameLoaderClient which is now used to get pageID, frameID and sessionID.

* UIProcess/ServiceWorkerProcessProxy.cpp: Added.
(WebKit::ServiceWorkerProcessProxy::ServiceWorkerProcessProxy):
(WebKit::m_serviceWorkerPageID):
(WebKit::ServiceWorkerProcessProxy::~ServiceWorkerProcessProxy):
(WebKit::ServiceWorkerProcessProxy::start):
* UIProcess/ServiceWorkerProcessProxy.h: Added.
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::getWorkerContextProcessConnection):
(WebKit::WebProcessPool::createNewWebProcess):
(WebKit::WebProcessPool::initializeNewWebProcess):
(WebKit::WebProcessPool::disconnectProcess):
(WebKit::WebProcessPool::createNewWebProcessRespectingProcessCountLimit):
(WebKit::WebProcessPool::createWebPage):
* UIProcess/WebProcessPool.h:
* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::generatePageID):
* UIProcess/WebProcessProxy.h:
* WebKit.xcodeproj/project.pbxproj:
* WebProcess/Network/WebLoaderStrategy.cpp:
(WebKit::WebLoaderStrategy::scheduleLoad):
(WebKit::WebLoaderStrategy::scheduleLoadFromNetworkProcess):
(WebKit::WebLoaderStrategy::startPingLoad):
* WebProcess/Network/WebLoaderStrategy.h:
* WebProcess/Storage/ServiceWorkerContextManager.cpp:
(WebKit::ServiceWorkerContextManager::ServiceWorkerContextManager):
(WebKit::ServiceWorkerContextManager::startServiceWorker):
(WebKit::ServiceWorkerContextManager::startFetch):
* WebProcess/Storage/ServiceWorkerContextManager.h:
* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::pageID const):
(WebKit::WebFrameLoaderClient::frameID const):
(WebKit::WebFrameLoaderClient::sessionID const):
* WebProcess/WebCoreSupport/WebFrameLoaderClient.h:
* WebProcess/WebProcess.cpp:
(WebKit::WebProcess::getWorkerContextConnection):
* WebProcess/WebProcess.h:
* WebProcess/WebProcess.messages.in:

Source/WebKitLegacy/mac:

* WebCoreSupport/WebFrameLoaderClient.mm:
(WebFrameLoaderClient::pageID const):
(WebFrameLoaderClient::frameID const):
(WebFrameLoaderClient::sessionID const):

Added implementation to the new getters.
They are noop in the context of WK1.

Source/WebKitLegacy/win:

Added implementation to the new getters.
They are noop in the context of WK1.

* WebCoreSupport/WebFrameLoaderClient.cpp:
(WebFrameLoaderClient::pageID const):
(WebFrameLoaderClient::frameID const):
(WebFrameLoaderClient::sessionID const):
* WebCoreSupport/WebFrameLoaderClient.h:

LayoutTests:

* http/tests/workers/service/resources/service-worker-fetch-worker.js: Added.
* http/tests/workers/service/resources/service-worker-fetch.js: Added.
* http/tests/workers/service/service-worker-fetch-expected.txt: Added.
* http/tests/workers/service/service-worker-fetch.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@223981 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/loader/EmptyFrameLoaderClient.h b/Source/WebCore/loader/EmptyFrameLoaderClient.h
new file mode 100644
index 0000000..06ee247
--- /dev/null
+++ b/Source/WebCore/loader/EmptyFrameLoaderClient.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FrameLoaderClient.h"
+
+namespace WebCore {
+
+class WEBCORE_EXPORT EmptyFrameLoaderClient : public FrameLoaderClient {
+    Ref<DocumentLoader> createDocumentLoader(const ResourceRequest&, const SubstituteData&) override;
+
+    void frameLoaderDestroyed() final { }
+
+    uint64_t frameID() const override { return 0; }
+    uint64_t pageID() const override { return 0; }
+    PAL::SessionID sessionID() const override;
+
+    bool hasWebView() const final { return true; } // mainly for assertions
+
+    void makeRepresentation(DocumentLoader*) final { }
+#if PLATFORM(IOS)
+    bool forceLayoutOnRestoreFromPageCache() final { return false; }
+#endif
+    void forceLayoutForNonHTML() final { }
+
+    void setCopiesOnScroll() final { }
+
+    void detachedFromParent2() final { }
+    void detachedFromParent3() final { }
+
+    void convertMainResourceLoadToDownload(DocumentLoader*, PAL::SessionID, const ResourceRequest&, const ResourceResponse&) final { }
+
+    void assignIdentifierToInitialRequest(unsigned long, DocumentLoader*, const ResourceRequest&) final { }
+    bool shouldUseCredentialStorage(DocumentLoader*, unsigned long) final { return false; }
+    void dispatchWillSendRequest(DocumentLoader*, unsigned long, ResourceRequest&, const ResourceResponse&) final { }
+    void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long, const AuthenticationChallenge&) final { }
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+    bool canAuthenticateAgainstProtectionSpace(DocumentLoader*, unsigned long, const ProtectionSpace&) final { return false; }
+#endif
+
+#if PLATFORM(IOS)
+    RetainPtr<CFDictionaryRef> connectionProperties(DocumentLoader*, unsigned long) final { return nullptr; }
+#endif
+
+    void dispatchDidReceiveResponse(DocumentLoader*, unsigned long, const ResourceResponse&) final { }
+    void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long, int) final { }
+    void dispatchDidFinishLoading(DocumentLoader*, unsigned long) final { }
+#if ENABLE(DATA_DETECTION)
+    void dispatchDidFinishDataDetection(NSArray *) final { }
+#endif
+    void dispatchDidFailLoading(DocumentLoader*, unsigned long, const ResourceError&) final { }
+    bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int) final { return false; }
+
+    void dispatchDidDispatchOnloadEvents() final { }
+    void dispatchDidReceiveServerRedirectForProvisionalLoad() final { }
+    void dispatchDidCancelClientRedirect() final { }
+    void dispatchWillPerformClientRedirect(const URL&, double, double) final { }
+    void dispatchDidChangeLocationWithinPage() final { }
+    void dispatchDidPushStateWithinPage() final { }
+    void dispatchDidReplaceStateWithinPage() final { }
+    void dispatchDidPopStateWithinPage() final { }
+    void dispatchWillClose() final { }
+    void dispatchDidStartProvisionalLoad() final { }
+    void dispatchDidReceiveTitle(const StringWithDirection&) final { }
+    void dispatchDidCommitLoad(std::optional<HasInsecureContent>) final { }
+    void dispatchDidFailProvisionalLoad(const ResourceError&) final { }
+    void dispatchDidFailLoad(const ResourceError&) final { }
+    void dispatchDidFinishDocumentLoad() final { }
+    void dispatchDidFinishLoad() final { }
+    void dispatchDidReachLayoutMilestone(LayoutMilestones) final { }
+
+    Frame* dispatchCreatePage(const NavigationAction&) final { return nullptr; }
+    void dispatchShow() final { }
+
+    void dispatchDecidePolicyForResponse(const ResourceResponse&, const ResourceRequest&, FramePolicyFunction&&) final { }
+    void dispatchDecidePolicyForNewWindowAction(const NavigationAction&, const ResourceRequest&, FormState*, const String&, FramePolicyFunction&&) final;
+    void dispatchDecidePolicyForNavigationAction(const NavigationAction&, const ResourceRequest&, bool didReceiveRedirectResponse, FormState*, FramePolicyFunction&&) final;
+    void cancelPolicyCheck() final { }
+
+    void dispatchUnableToImplementPolicy(const ResourceError&) final { }
+
+    void dispatchWillSendSubmitEvent(Ref<FormState>&&) final;
+    void dispatchWillSubmitForm(FormState&, WTF::Function<void(void)>&&) final;
+
+    void revertToProvisionalState(DocumentLoader*) final { }
+    void setMainDocumentError(DocumentLoader*, const ResourceError&) final { }
+
+    void setMainFrameDocumentReady(bool) final { }
+
+    void startDownload(const ResourceRequest&, const String&) final { }
+
+    void willChangeTitle(DocumentLoader*) final { }
+    void didChangeTitle(DocumentLoader*) final { }
+
+    void willReplaceMultipartContent() final { }
+    void didReplaceMultipartContent() final { }
+
+    void committedLoad(DocumentLoader*, const char*, int) final { }
+    void finishedLoading(DocumentLoader*) final { }
+
+    ResourceError cancelledError(const ResourceRequest&) final { return { ResourceError::Type::Cancellation }; }
+    ResourceError blockedError(const ResourceRequest&) final { return { }; }
+    ResourceError blockedByContentBlockerError(const ResourceRequest&) final { return { }; }
+    ResourceError cannotShowURLError(const ResourceRequest&) final { return { }; }
+    ResourceError interruptedForPolicyChangeError(const ResourceRequest&) final { return { }; }
+#if ENABLE(CONTENT_FILTERING)
+    ResourceError blockedByContentFilterError(const ResourceRequest&) final { return { }; }
+#endif
+
+    ResourceError cannotShowMIMETypeError(const ResourceResponse&) final { return { }; }
+    ResourceError fileDoesNotExistError(const ResourceResponse&) final { return { }; }
+    ResourceError pluginWillHandleLoadError(const ResourceResponse&) final { return { }; }
+
+    bool shouldFallBack(const ResourceError&) final { return false; }
+
+    bool canHandleRequest(const ResourceRequest&) const final { return false; }
+    bool canShowMIMEType(const String&) const final { return false; }
+    bool canShowMIMETypeAsHTML(const String&) const final { return false; }
+    bool representationExistsForURLScheme(const String&) const final { return false; }
+    String generatedMIMETypeForURLScheme(const String&) const final { return emptyString(); }
+
+    void frameLoadCompleted() final { }
+    void restoreViewState() final { }
+    void provisionalLoadStarted() final { }
+    void didFinishLoad() final { }
+    void prepareForDataSourceReplacement() final { }
+
+    void updateCachedDocumentLoader(DocumentLoader&) final { }
+    void setTitle(const StringWithDirection&, const URL&) final { }
+
+    String userAgent(const URL&) final { return emptyString(); }
+
+    void savePlatformDataToCachedFrame(CachedFrame*) final { }
+    void transitionToCommittedFromCachedFrame(CachedFrame*) final { }
+#if PLATFORM(IOS)
+    void didRestoreFrameHierarchyForCachedFrame() final { }
+#endif
+    void transitionToCommittedForNewPage() final { }
+
+    void didSaveToPageCache() final { }
+    void didRestoreFromPageCache() final { }
+
+    void dispatchDidBecomeFrameset(bool) final { }
+
+    void updateGlobalHistory() final { }
+    void updateGlobalHistoryRedirectLinks() final { }
+    bool shouldGoToHistoryItem(HistoryItem*) const final { return false; }
+    void updateGlobalHistoryItemForPage() final { }
+    void saveViewStateToItem(HistoryItem&) final { }
+    bool canCachePage() const final { return false; }
+    void didDisplayInsecureContent() final { }
+    void didRunInsecureContent(SecurityOrigin&, const URL&) final { }
+    void didDetectXSS(const URL&, bool) final { }
+    RefPtr<Frame> createFrame(const URL&, const String&, HTMLFrameOwnerElement&, const String&, bool, int, int) final;
+    RefPtr<Widget> createPlugin(const IntSize&, HTMLPlugInElement&, const URL&, const Vector<String>&, const Vector<String>&, const String&, bool) final;
+    void recreatePlugin(Widget*) final;
+    RefPtr<Widget> createJavaAppletWidget(const IntSize&, HTMLAppletElement&, const URL&, const Vector<String>&, const Vector<String>&) final;
+
+    ObjectContentType objectContentType(const URL&, const String&) final { return ObjectContentType::None; }
+    String overrideMediaType() const final { return { }; }
+
+    void redirectDataToPlugin(Widget&) final { }
+    void dispatchDidClearWindowObjectInWorld(DOMWrapperWorld&) final { }
+
+#if PLATFORM(COCOA)
+    RemoteAXObjectRef accessibilityRemoteObject() final { return nullptr; }
+    NSCachedURLResponse *willCacheResponse(DocumentLoader*, unsigned long, NSCachedURLResponse *response) const final { return response; }
+#endif
+
+#if PLATFORM(WIN) && USE(CFURLCONNECTION)
+    bool shouldCacheResponse(DocumentLoader*, unsigned long, const ResourceResponse&, const unsigned char*, unsigned long long) final { return true; }
+#endif
+
+    Ref<FrameNetworkingContext> createNetworkingContext() final;
+
+    bool isEmptyFrameLoaderClient() final { return true; }
+    void prefetchDNS(const String&) final { }
+
+#if USE(QUICK_LOOK)
+    RefPtr<PreviewLoaderClient> createPreviewLoaderClient(const String&, const String&) final { return nullptr; }
+#endif
+};
+
+}