Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Load site-isolated cross-origin iframes in their own process
https://bugs.webkit.org/show_bug.cgi?id=248701
rdar://99665091

Reviewed by Chris Dumez.

This implements the flow needed to load cross-origin iframes in another process
when the off-by-default SiteIsolation experimental feature is turned on.

When a frame begins loading, decidePolicyForNavigationAction is sent to the UI process,
where the UI process finds or makes a new process to load the frame in.  The UI process
tells the process that loading will happen in a new process by responding with
NavigationPolicyDecision::StopAllLoads.  When this happens when navigating the main frame,
we need to stop all loads and we are done in the old process.  When this happens when
navigating an iframe, though, we need to stop the loads but we aren't done; we will be
informed later that the iframe has finished loading, and only thereafter can we consider
the parent frame to have finished loading.

Meanwhile, the UI process has taken the new process and populated it with the necessary
structures to load a frame: a WebPage and a WebFrame, which has been given the FrameIdentifier
from the UI process instead of generating a new one.  We then tell the new process's "main frame"
to load the URL of the iframe.  We use ShouldTreatAsContinuingLoad::YesAfterNavigationPolicyDecision
because we have already called decidePolicyForNavigationAction, so the new process does not need
to ask again.  However, when it receives the response, it does need to call decidePolicyForResponse,
but we haven't even committed the load yet.  We need an object similar to ProvisionalPageProxy
to handle messages before the load is committed, but it has slightly different responsibilities.
So we introduce ProvisionalFrameProxy to handle messages before the load is committed, at which point
the WebFrameProxy now has 2 processes: the process the web content is in, and the process the
WebCore::RemoteFrame is in, which represents an iframe in the DOM of the parent that has its content
in another process, so all it will be able to do is send messages to the other process.

As the load proceeds, it eventually calls WebFrameProxy::didFinishLoad, which needs to send
the new message WebFrame::DidFinishLoadInAnotherProcess to the remote frame's process to tell it
to tell its parent frame to fire the onload event, and finish loading the page.  Only after this
happens should the WKNavigationDelegate be informed that the loading completed.  I modified the
test to wait 0.1 seconds after sending the iframe's response header fields before sending the body
to make sure that the timing of the commit and load finished callbacks does not happen prematurely.

That is what it takes to load an iframe in another process.  There are lots of rough edges and
things to fix and polish later, but this is the minimum change to make it so that there is now
one case where it does the right thing.  Future PRs will make it so that it does the right thing
in all possible cases, but that can and should be broken up into many smaller PRs.  We will also
need to revisit the concept of "main frame", audit all uses of it, and teach the rest of the code
that the topmost Frame in this process might have a parent frame in another process.  We've already
stretched what a WebCore::Page/WebKit::WebPage is when swapping processes on cross-origin navigations,
and this stretches it a little further.  In this case, I'm using a WebPage as the container for the
topmost Frame in the current process.  There are many bugs that need fixing still, but that's ok.

* Source/WebCore/loader/FrameLoader.cpp:
(WebCore::FrameLoader::continueLoadAfterNavigationPolicy):
Don't call checkCompleted() when we receive NavigationPolicyDecision::StopAllLoads when loading
an iframe.  This will be called later by didFinishLoadInAnotherProcess.  We aren't cancelling the
load, so it's not done yet.
* Source/WebCore/page/Frame.cpp:
(WebCore::Frame::Frame):
(WebCore::Frame::create):
Instead of calling FrameIdentifier::generate in the Frame constructor, pass it in as a parameter.
That way, we can add the main frame's identifier to WebPageCreationParameters for making a RemoteFrame's
counterpart Frame as the "main frame" in another process.
(WebCore::Frame::didFinishLoadInAnotherProcess):
* Source/WebCore/page/Frame.h:
* Source/WebCore/page/Page.cpp:
(WebCore::Page::Page):
* Source/WebCore/page/PageConfiguration.h:
* Source/WebKit/Shared/LoadParameters.h:
Prevent uninitialized memory.  I should be initializing all LoadParameters members, but at this
stage of development I'm not yet.
* Source/WebKit/Shared/WebPageCreationParameters.cpp:
(WebKit::WebPageCreationParameters::encode const):
(WebKit::WebPageCreationParameters::decode):
* Source/WebKit/Shared/WebPageCreationParameters.h:
Pass a FrameIdentifier to the main frame when making a page in a new process with the intent of having
its main frame be the remote part of a RemoteFrame in another process.
* Source/WebKit/Sources.txt:
* Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp: Added.
This class owns the process that a RemoteFrame is navigating in between when the navigation is initiated
and when the navigation is committed.  It does some set up and some message handling.
(WebKit::ProvisionalFrameProxy::ProvisionalFrameProxy):
(WebKit::ProvisionalFrameProxy::~ProvisionalFrameProxy):
(WebKit::ProvisionalFrameProxy::didReceiveMessage):
(WebKit::ProvisionalFrameProxy::decidePolicyForResponse):
(WebKit::ProvisionalFrameProxy::didCommitLoadForFrame):
(WebKit::ProvisionalFrameProxy::messageSenderConnection const):
(WebKit::ProvisionalFrameProxy::messageSenderDestinationID const):
* Source/WebKit/UIProcess/ProvisionalFrameProxy.h: Added.
(WebKit::ProvisionalFrameProxy::process):
* Source/WebKit/UIProcess/ProvisionalPageProxy.cpp:
(WebKit::ProvisionalPageProxy::~ProvisionalPageProxy):
Add a check I noticed was necessary in ProvisionalFrameProxy to prevent assertions when destroying
a WebPageProxy between when a navigation is initiated and when it is committed.  Since ProvisionalPageProxy
has a similar design in this aspect, I added the connection existence check there too.
* Source/WebKit/UIProcess/WebFrameProxy.cpp:
(WebKit::WebFrameProxy::~WebFrameProxy):
(WebKit::WebFrameProxy::didFinishLoad):
(WebKit::WebFrameProxy::didFailLoad):
Add some logic to handle the times when a WebFrameProxy has two processes it represents: one with a
Frame and one with a RemoteFrame.  More logic is likely needed, but this is enough to get the 1 unit test
passing without asserting or crashing.
(WebKit::WebFrameProxy::swapToProcess):
This function is called when a cross-origin iframe navigation is initiated.  It just makes a ProvisionalFrameProxy
which handles all the exciting bits.
(WebKit::WebFrameProxy::commitProvisionalFrame):
This function is called when a cross-origin iframe navigation is committed.  It takes the process from the
ProvisionalFrameProxy and destroys the unneeded temporary steward of the process.
* Source/WebKit/UIProcess/WebFrameProxy.h:
* Source/WebKit/UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::continueNavigationInNewProcess):
* Source/WebKit/UIProcess/WebPageProxy.h:
* Source/WebKit/UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::addProvisionalFrameProxy):
(WebKit::WebProcessProxy::removeProvisionalFrameProxy):
Like removeProvisionalPageProxy and addProvisionalPageProxy, we need to be informed about ProvisionalFrameProxies
because canTerminateAuxiliaryProcess needs to return false when we have provisional fames or provisional pages.
Otherwise, processes made for ProvisionalFrameProxy terminate immediately upon creation.
(WebProcessProxy::provisionalFrameCommitted):
(WebProcessProxy::removeFrameWithRemoteFrameProcess):
This is the beginning of what will probably need to become more like WebProcessProxy::addExistingWebPage
and WebProcessProxy::removeWebPage, but we need to have canTerminateAuxiliaryProcess not only return false when
there's a ProvisionalPageProxy using this process, but also if there's a frame with web content running in this
process even if it's not the main frame of a WKWebView.
(WebKit::WebProcessProxy::canTerminateAuxiliaryProcess):
* Source/WebKit/UIProcess/WebProcessProxy.h:
* Source/WebKit/WebKit.xcodeproj/project.pbxproj:
* Source/WebKit/WebProcess/WebPage/WebFrame.cpp:
(WebKit::WebFrame::initWithCoreMainFrame):
(WebKit::WebFrame::createSubframe):
When the UI process gives us a FrameIdentifier to use as the main frame's identifier, don't send
WebPageProxy::DidCreateMainFrame messages, whose only purpose is to inform the UI process of the main frame's
FrameIdentifier.  Otherwise the UI process gets confused.
(WebKit::WebFrame::didCommitLoadInAnotherProcess):
(WebKit::WebFrame::didFinishLoadInAnotherProcess):
* Source/WebKit/WebProcess/WebPage/WebFrame.h:
* Source/WebKit/WebProcess/WebPage/WebFrame.messages.in:
* Source/WebKit/WebProcess/WebPage/WebPage.cpp:
(WebKit::m_appHighlightsVisible):
* Source/WebKitLegacy/mac/WebView/WebFrame.mm:
(+[WebFrame _createFrameWithPage:frameName:frameView:ownerElement:]):
* Source/WebKitLegacy/win/WebFrame.cpp:
(WebFrame::createSubframeWithOwnerElement):
FrameIdentifier generation has been moved to callers of Frame::create to allow UI processes to assign main frames
their FrameIdentifier generated in another process.
* Tools/TestWebKitAPI/Tests/WebKitCocoa/SiteIsolation.mm:
(TestWebKitAPI::TEST):
Expand the test slightly to verify that didFinishNavigation is not called until the iframe is completely loaded.

Canonical link: https://commits.webkit.org/257435@main
  • Loading branch information
Alex Christensen authored and achristensen07 committed Dec 6, 2022
1 parent 036e53a commit 0c677e5
Show file tree
Hide file tree
Showing 26 changed files with 379 additions and 35 deletions.
8 changes: 7 additions & 1 deletion Source/WebCore/loader/FrameLoader.cpp
Expand Up @@ -3605,7 +3605,13 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& reque
}

setPolicyDocumentLoader(nullptr);
checkCompleted();
if (m_frame.isMainFrame() || navigationPolicyDecision != NavigationPolicyDecision::StopAllLoads)
checkCompleted();
else {
// Don't call checkCompleted until Frame::didFinishLoadInAnotherProcess,
// to prevent onload from happening until iframes finish loading in other processes.
ASSERT(m_frame.settings().siteIsolationEnabled());
}

if (navigationPolicyDecision != NavigationPolicyDecision::StopAllLoads)
checkLoadComplete();
Expand Down
13 changes: 9 additions & 4 deletions Source/WebCore/page/Frame.cpp
Expand Up @@ -150,8 +150,8 @@ static inline float parentTextZoomFactor(Frame* frame)
return parent->textZoomFactor();
}

Frame::Frame(Page& page, HTMLFrameOwnerElement* ownerElement, UniqueRef<FrameLoaderClient>&& frameLoaderClient)
: AbstractFrame(page, FrameIdentifier::generate(), ownerElement ? ownerElement->document().frame() : nullptr)
Frame::Frame(Page& page, HTMLFrameOwnerElement* ownerElement, UniqueRef<FrameLoaderClient>&& frameLoaderClient, FrameIdentifier identifier)
: AbstractFrame(page, identifier, ownerElement ? ownerElement->document().frame() : nullptr)
, m_mainFrame(ownerElement ? page.mainFrame() : *this)
, m_settings(&page.settings())
, m_loader(makeUniqueRef<FrameLoader>(*this, WTFMove(frameLoaderClient)))
Expand Down Expand Up @@ -183,10 +183,10 @@ void Frame::init()
m_loader->init();
}

Ref<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, UniqueRef<FrameLoaderClient>&& client)
Ref<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, UniqueRef<FrameLoaderClient>&& client, FrameIdentifier identifier)
{
ASSERT(page);
return adoptRef(*new Frame(*page, ownerElement, WTFMove(client)));
return adoptRef(*new Frame(*page, ownerElement, WTFMove(client), identifier));
}

Frame::~Frame()
Expand Down Expand Up @@ -1111,6 +1111,11 @@ bool Frame::arePluginsEnabled()
return settings().arePluginsEnabled();
}

void Frame::didFinishLoadInAnotherProcess()
{
m_loader->checkCompleted();
}

void Frame::resetScript()
{
resetWindowProxy();
Expand Down
6 changes: 4 additions & 2 deletions Source/WebCore/page/Frame.h
Expand Up @@ -117,7 +117,7 @@ using NodeQualifier = Function<Node* (const HitTestResult&, Node* terminationNod
// FIXME: Rename Frame to LocalFrame and AbstractFrame to Frame.
class Frame final : public AbstractFrame {
public:
WEBCORE_EXPORT static Ref<Frame> create(Page*, HTMLFrameOwnerElement*, UniqueRef<FrameLoaderClient>&&);
WEBCORE_EXPORT static Ref<Frame> create(Page*, HTMLFrameOwnerElement*, UniqueRef<FrameLoaderClient>&&, FrameIdentifier);

WEBCORE_EXPORT void init();
#if PLATFORM(IOS_FAMILY)
Expand Down Expand Up @@ -298,10 +298,12 @@ class Frame final : public AbstractFrame {

WEBCORE_EXPORT bool arePluginsEnabled();

WEBCORE_EXPORT void didFinishLoadInAnotherProcess();

private:
friend class NavigationDisabler;

Frame(Page&, HTMLFrameOwnerElement*, UniqueRef<FrameLoaderClient>&&);
Frame(Page&, HTMLFrameOwnerElement*, UniqueRef<FrameLoaderClient>&&, FrameIdentifier);

void dropChildren();

Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/page/Page.cpp
Expand Up @@ -281,7 +281,7 @@ Page::Page(PageConfiguration&& pageConfiguration)
, m_settings(Settings::create(this))
, m_progress(makeUnique<ProgressTracker>(*this, WTFMove(pageConfiguration.progressTrackerClient)))
, m_backForwardController(makeUnique<BackForwardController>(*this, WTFMove(pageConfiguration.backForwardClient)))
, m_mainFrame(Frame::create(this, nullptr, WTFMove(pageConfiguration.loaderClientForMainFrame)))
, m_mainFrame(Frame::create(this, nullptr, WTFMove(pageConfiguration.loaderClientForMainFrame), pageConfiguration.mainFrameIdentifier ? *pageConfiguration.mainFrameIdentifier : FrameIdentifier::generate()))
, m_editorClient(WTFMove(pageConfiguration.editorClient))
, m_validationMessageClient(WTFMove(pageConfiguration.validationMessageClient))
, m_diagnosticLoggingClient(WTFMove(pageConfiguration.diagnosticLoggingClient))
Expand Down
2 changes: 2 additions & 0 deletions Source/WebCore/page/PageConfiguration.h
Expand Up @@ -26,6 +26,7 @@
#pragma once

#include "ContentSecurityPolicy.h"
#include "FrameIdentifier.h"
#include "ShouldRelaxThirdPartyCookieBlocking.h"
#include <pal/SessionID.h>
#include <wtf/Forward.h>
Expand Down Expand Up @@ -159,6 +160,7 @@ class PageConfiguration {
#endif

ContentSecurityPolicyModeForExtension contentSecurityPolicyModeForExtension { WebCore::ContentSecurityPolicyModeForExtension::None };
std::optional<FrameIdentifier> mainFrameIdentifier;
};

}
2 changes: 1 addition & 1 deletion Source/WebKit/Shared/LoadParameters.h
Expand Up @@ -56,7 +56,7 @@ struct LoadParameters {
void platformEncode(IPC::Encoder&) const;
static WARN_UNUSED_RETURN bool platformDecode(IPC::Decoder&, LoadParameters&);

uint64_t navigationID;
uint64_t navigationID { 0 };

WebCore::ResourceRequest request;
SandboxExtension::Handle sandboxExtensionHandle;
Expand Down
6 changes: 5 additions & 1 deletion Source/WebKit/Shared/WebPageCreationParameters.cpp
Expand Up @@ -198,6 +198,7 @@ void WebPageCreationParameters::encode(IPC::Encoder& encoder) const
#endif

encoder << contentSecurityPolicyModeForExtension;
encoder << mainFrameIdentifier;
}

std::optional<WebPageCreationParameters> WebPageCreationParameters::decode(IPC::Decoder& decoder)
Expand Down Expand Up @@ -628,7 +629,10 @@ std::optional<WebPageCreationParameters> WebPageCreationParameters::decode(IPC::
if (!decoder.decode(parameters.contentSecurityPolicyModeForExtension))
return std::nullopt;

return parameters;
if (!decoder.decode(parameters.mainFrameIdentifier))
return std::nullopt;

return { WTFMove(parameters) };
}

} // namespace WebKit
2 changes: 2 additions & 0 deletions Source/WebKit/Shared/WebPageCreationParameters.h
Expand Up @@ -277,6 +277,8 @@ struct WebPageCreationParameters {
bool hasResizableWindows { false };

WebCore::ContentSecurityPolicyModeForExtension contentSecurityPolicyModeForExtension { WebCore::ContentSecurityPolicyModeForExtension::None };

std::optional<WebCore::FrameIdentifier> mainFrameIdentifier;
};

} // namespace WebKit
1 change: 1 addition & 0 deletions Source/WebKit/Sources.txt
Expand Up @@ -390,6 +390,7 @@ UIProcess/OverrideLanguages.cpp
UIProcess/PageLoadState.cpp
UIProcess/ProcessAssertion.cpp
UIProcess/ProcessThrottler.cpp
UIProcess/ProvisionalFrameProxy.cpp
UIProcess/ProvisionalPageProxy.cpp
UIProcess/ResponsivenessTimer.cpp
UIProcess/SpeechRecognitionRemoteRealtimeMediaSource.cpp
Expand Down
126 changes: 126 additions & 0 deletions Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp
@@ -0,0 +1,126 @@
/*
* Copyright (C) 2022 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. AND ITS CONTRIBUTORS ``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 ITS 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 "config.h"
#include "ProvisionalFrameProxy.h"

#include "APIWebsitePolicies.h"
#include "FrameInfoData.h"
#include "HandleMessage.h"
#include "LoadParameters.h"
#include "WebFrameProxy.h"
#include "WebFrameProxyMessages.h"
#include "WebPageProxyMessages.h"
#include "WebProcessMessages.h"

namespace WebKit {

ProvisionalFrameProxy::ProvisionalFrameProxy(WebFrameProxy& frame, Ref<WebProcessProxy>&& process, const WebCore::ResourceRequest& request)
: m_frame(frame)
, m_process(WTFMove(process))
, m_visitedLinkStore(frame.page()->visitedLinkStore())
, m_pageID(frame.page()->webPageID()) // FIXME: Generate a new one? This can conflict. And we probably want something like ProvisionalPageProxy to respond to messages anyways.
, m_webPageID(frame.page()->identifier())
{
m_process->markProcessAsRecentlyUsed();
m_process->addProvisionalFrameProxy(*this);

m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID, *this);

m_process->addMessageReceiver(Messages::WebFrameProxy::messageReceiverName(), m_frame.frameID().object(), *this);

auto& page = *m_frame.page();
auto parameters = page.creationParameters(m_process, *page.drawingArea());
parameters.isProcessSwap = true; // FIXME: This should be a parameter to creationParameters rather than doctoring up the parameters afterwards.
parameters.mainFrameIdentifier = frame.frameID();
m_process->send(Messages::WebProcess::CreateWebPage(m_pageID, parameters), 0);
m_process->addVisitedLinkStoreUser(page.visitedLinkStore(), page.identifier());

LoadParameters loadParameters;
loadParameters.request = request;
loadParameters.shouldTreatAsContinuingLoad = ShouldTreatAsContinuingLoad::YesAfterNavigationPolicyDecision;
// FIXME: Add more parameters as appropriate.

// FIXME: Do we need a LoadRequestWaitingForProcessLaunch version?
m_process->send(Messages::WebPage::LoadRequest(loadParameters), m_pageID);
}

ProvisionalFrameProxy::~ProvisionalFrameProxy()
{
if (!m_wasCommitted) {
m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID);
m_process->removeMessageReceiver(Messages::WebFrameProxy::messageReceiverName(), m_frame.frameID().object());
if (m_process->hasConnection())
send(Messages::WebPage::Close(), m_pageID);
}
m_process->removeVisitedLinkStoreUser(m_visitedLinkStore.get(), m_webPageID);
m_process->removeProvisionalFrameProxy(*this);
}

void ProvisionalFrameProxy::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
{
ASSERT(decoder.messageReceiverName() == Messages::WebPageProxy::messageReceiverName());

if (decoder.messageName() == Messages::WebPageProxy::DecidePolicyForResponse::name()) {
IPC::handleMessage<Messages::WebPageProxy::DecidePolicyForResponse>(connection, decoder, this, &ProvisionalFrameProxy::decidePolicyForResponse);
return;
}

if (decoder.messageName() == Messages::WebPageProxy::DidCommitLoadForFrame::name()) {
IPC::handleMessage<Messages::WebPageProxy::DidCommitLoadForFrame>(connection, decoder, this, &ProvisionalFrameProxy::didCommitLoadForFrame);
return;
}

if (auto* page = m_frame.page())
page->didReceiveMessage(connection, decoder);
}

void ProvisionalFrameProxy::decidePolicyForResponse(WebCore::FrameIdentifier frameID, FrameInfoData&& frameInfo, WebCore::PolicyCheckIdentifier identifier, uint64_t navigationID, const WebCore::ResourceResponse& response, const WebCore::ResourceRequest& request, bool canShowMIMEType, const String& downloadAttribute, uint64_t listenerID)
{
if (auto* page = m_frame.page())
page->decidePolicyForResponseShared(m_process.copyRef(), m_pageID, frameID, WTFMove(frameInfo), identifier, navigationID, response, request, canShowMIMEType, downloadAttribute, listenerID);
}

void ProvisionalFrameProxy::didCommitLoadForFrame(FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, WebCore::FrameLoadType frameLoadType, const WebCore::CertificateInfo& certificateInfo, bool usedLegacyTLS, bool privateRelayed, bool containsPluginDocument, std::optional<WebCore::HasInsecureContent> forcedHasInsecureContent, WebCore::MouseEventPolicy mouseEventPolicy, const UserData& userData)
{
m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID);
m_process->removeMessageReceiver(Messages::WebFrameProxy::messageReceiverName(), m_frame.frameID().object());
m_wasCommitted = true;

m_frame.commitProvisionalFrame(frameID, WTFMove(frameInfo), WTFMove(request), navigationID, mimeType, frameHasCustomContentProvider, frameLoadType, certificateInfo, usedLegacyTLS, privateRelayed, containsPluginDocument, forcedHasInsecureContent, mouseEventPolicy, userData); // Will delete |this|.
}

IPC::Connection* ProvisionalFrameProxy::messageSenderConnection() const
{
return m_process->connection();
}

uint64_t ProvisionalFrameProxy::messageSenderDestinationID() const
{
// FIXME: This identifier was generated in another process and can collide with identifiers in this frame's process.
return m_frame.frameID().object().toUInt64();
}

}
72 changes: 72 additions & 0 deletions Source/WebKit/UIProcess/ProvisionalFrameProxy.h
@@ -0,0 +1,72 @@
/*
* Copyright (C) 2022 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. AND ITS CONTRIBUTORS ``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 ITS 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.
*/

#pragma once

#include "MessageReceiver.h"
#include "MessageSender.h"
#include "WebPageProxyIdentifier.h"
#include <WebCore/FrameIdentifier.h>
#include <WebCore/FrameLoaderTypes.h>
#include <WebCore/PageIdentifier.h>
#include <wtf/WeakPtr.h>

namespace WebCore {
class ResourceRequest;
class ResourceResponse;
}

namespace WebKit {

class WebFrameProxy;
class WebProcessProxy;
struct FrameInfoData;

class ProvisionalFrameProxy : public IPC::MessageReceiver, public IPC::MessageSender {
WTF_MAKE_FAST_ALLOCATED;
public:
ProvisionalFrameProxy(WebFrameProxy&, Ref<WebProcessProxy>&&, const WebCore::ResourceRequest&);
~ProvisionalFrameProxy();

WebProcessProxy& process() { return m_process.get(); }

private:
void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;

void decidePolicyForResponse(WebCore::FrameIdentifier, FrameInfoData&&, WebCore::PolicyCheckIdentifier, uint64_t navigationID, const WebCore::ResourceResponse&, const WebCore::ResourceRequest&, bool canShowMIMEType, const String& downloadAttribute, uint64_t listenerID);
void didCommitLoadForFrame(WebCore::FrameIdentifier, FrameInfoData&&, WebCore::ResourceRequest&&, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, WebCore::FrameLoadType, const WebCore::CertificateInfo&, bool usedLegacyTLS, bool privateRelayed, bool containsPluginDocument, std::optional<WebCore::HasInsecureContent> forcedHasInsecureContent, WebCore::MouseEventPolicy, const UserData&);

IPC::Connection* messageSenderConnection() const final;
uint64_t messageSenderDestinationID() const final;

WebFrameProxy& m_frame;
Ref<WebProcessProxy> m_process;
Ref<VisitedLinkStore> m_visitedLinkStore;
WebCore::PageIdentifier m_pageID;
WebPageProxyIdentifier m_webPageID;
bool m_wasCommitted { false };
};

} // namespace WebKit
3 changes: 2 additions & 1 deletion Source/WebKit/UIProcess/ProvisionalPageProxy.cpp
Expand Up @@ -119,7 +119,8 @@ ProvisionalPageProxy::~ProvisionalPageProxy()
m_process->processPool().pageEndUsingWebsiteDataStore(m_page.identifier(), *dataStore);

m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_webPageID);
send(Messages::WebPage::Close());
if (m_process->hasConnection())
send(Messages::WebPage::Close());
m_process->removeVisitedLinkStoreUser(m_page.visitedLinkStore(), m_page.identifier());
}

Expand Down

0 comments on commit 0c677e5

Please sign in to comment.