Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add support for Clear-Site-Data: "executionContext"
https://bugs.webkit.org/show_bug.cgi?id=251821

Reviewed by Geoffrey Garen.

Add support for `Clear-Site-Data: "executionContext"`:
- https://w3c.github.io/webappsec-clear-site-data/#grammardef-executioncontexts

* LayoutTests/TestExpectations:
Unskip WPT test that is now passing.

* LayoutTests/imported/w3c/web-platform-tests/clear-site-data/executionContexts.sub-expected.txt:
Rebaseline WPT test that is now passing.

* LayoutTests/imported/w3c/web-platform-tests/clear-site-data/executionContexts.sub.html:
Fix WPT test to work with the WebKit test infrastructure (will make an upstream PR).

* Source/WebCore/page/FrameTree.cpp:
(WebCore::FrameTree::traverseNextSkippingChildren const):
(WebCore::FrameTree::nextAncestorSibling const):
* Source/WebCore/page/FrameTree.h:
* Source/WebCore/page/Page.cpp:
(WebCore::Page::reloadExecutionContextsForOrigin const):
* Source/WebCore/page/Page.h:
(WebCore::Page::overrideViewportArguments const):
* Source/WebCore/platform/network/HTTPParsers.cpp:
(WebCore::parseClearSiteDataHeader):
* Source/WebCore/platform/network/HTTPParsers.h:
* Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp:
(WebKit::NetworkResourceLoader::processClearSiteDataHeader):
* Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp:
(WebKit::NetworkProcessProxy::reloadExecutionContextsForOrigin):
* Source/WebKit/UIProcess/Network/NetworkProcessProxy.h:
* Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in:
* Source/WebKit/WebProcess/WebProcess.cpp:
(WebKit::WebProcess::reloadExecutionContextsForOrigin):
* Source/WebKit/WebProcess/WebProcess.h:
* Source/WebKit/WebProcess/WebProcess.messages.in:

Canonical link: https://commits.webkit.org/259940@main
  • Loading branch information
cdumez committed Feb 7, 2023
1 parent 3bced5e commit 35591d2
Show file tree
Hide file tree
Showing 16 changed files with 98 additions and 14 deletions.
3 changes: 0 additions & 3 deletions LayoutTests/TestExpectations
Expand Up @@ -430,9 +430,6 @@ imported/w3c/web-platform-tests/server-timing/test_server_timing.https.html [ Sk
imported/w3c/web-platform-tests/server-timing/navigation_timing_idl.html [ Skip ]
imported/w3c/web-platform-tests/server-timing/navigation_timing_idl.https.html [ Skip ]

# No support for Clear-Site-Data: "executionContexts".
imported/w3c/web-platform-tests/clear-site-data/executionContexts.sub.html [ Skip ]

# Console log lines may appear in a different order so we silence them.
http/tests/security/cookie-module.html [ DumpJSConsoleLogInStdErr ]
http/tests/security/cookie-module-import-propagate.html [ DumpJSConsoleLogInStdErr ]
Expand Down
@@ -1,8 +1,5 @@
Blocked access to external URL https://www2.localhost:9443/clear-site-data/support/iframe_executionContexts.html


Harness Error (TIMEOUT), message = null

TIMEOUT executionContexts triggers the reload of contexts Test timed out
NOTRUN * triggers the reload of contexts
PASS executionContexts triggers the reload of contexts
PASS * triggers the reload of contexts

Expand Up @@ -3,6 +3,7 @@
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
</head>

<body>
Expand All @@ -16,7 +17,7 @@

let ifr = document.createElement('iframe');
document.body.appendChild(ifr);
ifr.src = "https://{{domains[www2]}}:{{ports[https][0]}}/clear-site-data/support/iframe_executionContexts.html";
ifr.src = get_host_info().HTTPS_REMOTE_ORIGIN + "/clear-site-data/support/iframe_executionContexts.html";
});
}

Expand All @@ -28,7 +29,7 @@
}, { once: true });

let image = new Image();
image.src = "https://{{domains[www2]}}:{{ports[https][0]}}/clear-site-data/support/echo-clear-site-data.py?" + what;
image.src = get_host_info().HTTPS_REMOTE_ORIGIN + "/clear-site-data/support/echo-clear-site-data.py?" + what;
});
}

Expand Down
22 changes: 22 additions & 0 deletions Source/WebCore/page/FrameTree.cpp
Expand Up @@ -348,6 +348,28 @@ AbstractFrame* FrameTree::traverseNext(const AbstractFrame* stayWithin) const
return nullptr;
}

AbstractFrame* FrameTree::traverseNextSkippingChildren(const AbstractFrame* stayWithin) const
{
if (&m_thisFrame == stayWithin)
return nullptr;
if (auto* sibling = nextSibling())
return sibling;
return nextAncestorSibling(stayWithin);
}

AbstractFrame* FrameTree::nextAncestorSibling(const AbstractFrame* stayWithin) const
{
ASSERT(!nextSibling());
ASSERT(&m_thisFrame != stayWithin);
for (auto* ancestor = parent(); ancestor; ancestor = ancestor->tree().parent()) {
if (ancestor == stayWithin)
return nullptr;
if (auto ancestorSibling = ancestor->tree().nextSibling())
return ancestorSibling;
}
return nullptr;
}

AbstractFrame* FrameTree::firstRenderedChild() const
{
auto* child = firstChild();
Expand Down
2 changes: 2 additions & 0 deletions Source/WebCore/page/FrameTree.h
Expand Up @@ -58,6 +58,7 @@ class FrameTree {
WEBCORE_EXPORT bool isDescendantOf(const AbstractFrame* ancestor) const;

WEBCORE_EXPORT AbstractFrame* traverseNext(const AbstractFrame* stayWithin = nullptr) const;
AbstractFrame* traverseNextSkippingChildren(const AbstractFrame* stayWithin = nullptr) const;
// Rendered means being the main frame or having an ownerRenderer. It may not have been parented in the Widget tree yet (see WidgetHierarchyUpdatesSuspensionScope).
WEBCORE_EXPORT AbstractFrame* traverseNextRendered(const AbstractFrame* stayWithin = nullptr) const;
WEBCORE_EXPORT AbstractFrame* traverseNext(CanWrap, DidWrap* = nullptr) const;
Expand Down Expand Up @@ -86,6 +87,7 @@ class FrameTree {
private:
AbstractFrame* deepFirstChild() const;
AbstractFrame* deepLastChild() const;
AbstractFrame* nextAncestorSibling(const AbstractFrame* stayWithin) const;

bool scopedBy(TreeScope*) const;
AbstractFrame* scopedChild(unsigned index, TreeScope*) const;
Expand Down
22 changes: 22 additions & 0 deletions Source/WebCore/page/Page.cpp
Expand Up @@ -96,6 +96,7 @@
#include "MediaCanStartListener.h"
#include "MediaRecorderProvider.h"
#include "ModelPlayerProvider.h"
#include "NavigationScheduler.h"
#include "Navigator.h"
#include "PageColorSampler.h"
#include "PageConfiguration.h"
Expand Down Expand Up @@ -4188,4 +4189,25 @@ void Page::didFinishScrolling()
#endif
}

void Page::reloadExecutionContextsForOrigin(const ClientOrigin& origin, std::optional<FrameIdentifier> triggeringFrame) const
{
if (m_mainFrame->document()->topOrigin().data() != origin.topOrigin)
return;

for (AbstractFrame* frame = &m_mainFrame.get(); frame;) {
auto* localFrame = dynamicDowncast<LocalFrame>(frame);
if (!localFrame || frame->frameID() == triggeringFrame) {
frame = frame->tree().traverseNext();
continue;
}
auto* document = localFrame->document();
if (!document || document->securityOrigin().data() != origin.clientOrigin) {
frame = frame->tree().traverseNext();
continue;
}
localFrame->navigationScheduler().scheduleRefresh(*document);
frame = frame->tree().traverseNextSkippingChildren();
}
}

} // namespace WebCore
2 changes: 2 additions & 0 deletions Source/WebCore/page/Page.h
Expand Up @@ -293,6 +293,8 @@ class Page : public Supplementable<Page>, public CanMakeWeakPtr<Page> {
WEBCORE_EXPORT OptionSet<DisabledAdaptations> disabledAdaptations() const;
WEBCORE_EXPORT ViewportArguments viewportArguments() const;

WEBCORE_EXPORT void reloadExecutionContextsForOrigin(const ClientOrigin&, std::optional<FrameIdentifier> triggeringFrame) const;

const std::optional<ViewportArguments>& overrideViewportArguments() const { return m_overrideViewportArguments; }
WEBCORE_EXPORT void setOverrideViewportArguments(const std::optional<ViewportArguments>&);

Expand Down
4 changes: 3 additions & 1 deletion Source/WebCore/platform/network/HTTPParsers.cpp
Expand Up @@ -600,10 +600,12 @@ OptionSet<ClearSiteDataValue> parseClearSiteDataHeader(const ResourceResponse& r
result.add(ClearSiteDataValue::Cache);
else if (trimmedValue == "\"cookies\""_s)
result.add(ClearSiteDataValue::Cookies);
else if (trimmedValue == "\"executionContexts\""_s)
result.add(ClearSiteDataValue::ExecutionContexts);
else if (trimmedValue == "\"storage\""_s)
result.add(ClearSiteDataValue::Storage);
else if (trimmedValue == "\"*\""_s)
result.add({ ClearSiteDataValue::Cache, ClearSiteDataValue::Cookies, ClearSiteDataValue::Storage });
result.add({ ClearSiteDataValue::Cache, ClearSiteDataValue::Cookies, ClearSiteDataValue::ExecutionContexts, ClearSiteDataValue::Storage });
}
return result;
}
Expand Down
3 changes: 2 additions & 1 deletion Source/WebCore/platform/network/HTTPParsers.h
Expand Up @@ -73,7 +73,8 @@ enum class CrossOriginResourcePolicy : uint8_t {
enum class ClearSiteDataValue : uint8_t {
Cache = 1 << 0,
Cookies = 1 << 1,
Storage = 1 << 2,
ExecutionContexts = 1 << 2,
Storage = 1 << 3,
};

bool isValidReasonPhrase(const String&);
Expand Down
13 changes: 11 additions & 2 deletions Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp
Expand Up @@ -764,7 +764,8 @@ void NetworkResourceLoader::processClearSiteDataHeader(const WebCore::ResourceRe
#endif
}

if (!typesToRemove)
bool shouldReloadExecutionContexts = clearSiteDataValues.contains(ClearSiteDataValue::ExecutionContexts);
if (!typesToRemove && !shouldReloadExecutionContexts)
return completionHandler();

LOADER_RELEASE_LOG("processClearSiteDataHeader: BEGIN");
Expand All @@ -785,10 +786,18 @@ void NetworkResourceLoader::processClearSiteDataHeader(const WebCore::ResourceRe
LOADER_RELEASE_LOG("processClearSiteDataHeader: END");
completionHandler();
});
m_connection->networkProcess().deleteWebsiteDataForOrigin(sessionID(), typesToRemove, clientOrigin, [callbackAggregator] { });
if (typesToRemove)
m_connection->networkProcess().deleteWebsiteDataForOrigin(sessionID(), typesToRemove, clientOrigin, [callbackAggregator] { });

if (WebsiteDataStore::computeWebProcessAccessTypeForDataRemoval(typesToRemove, sessionID().isEphemeral()) != WebsiteDataStore::ProcessAccessType::None)
m_connection->networkProcess().parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::DeleteWebsiteDataInWebProcessesForOrigin(typesToRemove, clientOrigin, sessionID(), m_parameters.webPageProxyID), [callbackAggregator] { });

if (shouldReloadExecutionContexts) {
std::optional<WebCore::FrameIdentifier> triggeringFrame;
if (isMainResource())
triggeringFrame = frameID();
m_connection->networkProcess().parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::ReloadExecutionContextsForOrigin(clientOrigin, sessionID(), triggeringFrame), [callbackAggregator] { });
}
}

static BrowsingContextGroupSwitchDecision toBrowsingContextGroupSwitchDecision(const std::optional<CrossOriginOpenerPolicyEnforcementResult>& currentCoopEnforcementResult)
Expand Down
16 changes: 16 additions & 0 deletions Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp
Expand Up @@ -1904,6 +1904,22 @@ void NetworkProcessProxy::deleteWebsiteDataInWebProcessesForOrigin(OptionSet<Web
}
}

void NetworkProcessProxy::reloadExecutionContextsForOrigin(const WebCore::ClientOrigin& origin, PAL::SessionID sessionID, std::optional<WebCore::FrameIdentifier> triggeringFrame, CompletionHandler<void()>&& completionHandler)
{
RELEASE_LOG(Process, "%p - NetworkProcessProxy::reloadExecutionContextsForOrigin BEGIN", this);
auto callbackAggregator = CallbackAggregator::create([protectedThis = Ref { *this }, completionHandler = WTFMove(completionHandler)]() mutable {
RELEASE_LOG(Process, "%p - NetworkProcessProxy::reloadExecutionContextsForOrigin END", protectedThis.ptr());
completionHandler();
});
RefPtr websiteDataStore = websiteDataStoreFromSessionID(sessionID);
if (!websiteDataStore)
return;
for (auto& process : websiteDataStore->processes()) {
if (process.canSendMessage() && !process.isDummyProcessProxy())
process.sendWithAsyncReply(Messages::WebProcess::ReloadExecutionContextsForOrigin(origin, triggeringFrame), [callbackAggregator] { });
}
}

#if ENABLE(NETWORK_ISSUE_REPORTING)

void NetworkProcessProxy::reportNetworkIssue(WebPageProxyIdentifier pageIdentifier, const URL& requestURL)
Expand Down
1 change: 1 addition & 0 deletions Source/WebKit/UIProcess/Network/NetworkProcessProxy.h
Expand Up @@ -305,6 +305,7 @@ class NetworkProcessProxy final : public AuxiliaryProcessProxy, private ProcessT
void cancelDataTask(DataTaskIdentifier, PAL::SessionID);

void deleteWebsiteDataInWebProcessesForOrigin(OptionSet<WebsiteDataType>, const WebCore::ClientOrigin&, PAL::SessionID, WebPageProxyIdentifier, CompletionHandler<void()>&&);
void reloadExecutionContextsForOrigin(const WebCore::ClientOrigin&, PAL::SessionID, std::optional<WebCore::FrameIdentifier> triggeringFrame, CompletionHandler<void()>&&);

void terminateRemoteWorkerContextConnectionWhenPossible(RemoteWorkerType, PAL::SessionID, const WebCore::RegistrableDomain&, WebCore::ProcessIdentifier);

Expand Down
Expand Up @@ -98,6 +98,7 @@ messages -> NetworkProcessProxy LegacyReceiver {
CookiesDidChange(PAL::SessionID sessionID)

DeleteWebsiteDataInWebProcessesForOrigin(OptionSet<WebKit::WebsiteDataType> websiteDataTypes, struct WebCore::ClientOrigin origin, PAL::SessionID sessionID, WebKit::WebPageProxyIdentifier webPageProxyID) -> ()
ReloadExecutionContextsForOrigin(struct WebCore::ClientOrigin origin, PAL::SessionID sessionID, std::optional<WebCore::FrameIdentifier> triggeringFrame) -> ()

#if ENABLE(NETWORK_ISSUE_REPORTING)
ReportNetworkIssue(WebKit::WebPageProxyIdentifier webPageProxyIdentifier, URL requestURL)
Expand Down
9 changes: 9 additions & 0 deletions Source/WebKit/WebProcess/WebProcess.cpp
Expand Up @@ -1459,6 +1459,15 @@ void WebProcess::deleteWebsiteDataForOrigin(OptionSet<WebsiteDataType> websiteDa
completionHandler();
}

void WebProcess::reloadExecutionContextsForOrigin(const ClientOrigin& origin, std::optional<FrameIdentifier> triggeringFrame, CompletionHandler<void()>&& completionHandler)
{
for (auto& page : m_pageMap.values()) {
if (auto* corePage = page->corePage())
corePage->reloadExecutionContextsForOrigin(origin, triggeringFrame);
}
completionHandler();
}

void WebProcess::deleteWebsiteDataForOrigins(OptionSet<WebsiteDataType> websiteDataTypes, const Vector<WebCore::SecurityOriginData>& originDatas, CompletionHandler<void()>&& completionHandler)
{
if (websiteDataTypes.contains(WebsiteDataType::MemoryCache)) {
Expand Down
1 change: 1 addition & 0 deletions Source/WebKit/WebProcess/WebProcess.h
Expand Up @@ -388,6 +388,7 @@ class WebProcess : public AuxiliaryProcess
bool hadMainFrameMainResourcePrivateRelayed() const { return m_hadMainFrameMainResourcePrivateRelayed; }

void deleteWebsiteDataForOrigin(OptionSet<WebsiteDataType>, const WebCore::ClientOrigin&, CompletionHandler<void()>&&);
void reloadExecutionContextsForOrigin(const WebCore::ClientOrigin&, std::optional<WebCore::FrameIdentifier> triggeringFrame, CompletionHandler<void()>&&);

void setAppBadge(std::optional<WebPageProxyIdentifier>, const WebCore::SecurityOriginData&, std::optional<uint64_t>);
void setClientBadge(WebPageProxyIdentifier, const WebCore::SecurityOriginData&, std::optional<uint64_t>);
Expand Down
1 change: 1 addition & 0 deletions Source/WebKit/WebProcess/WebProcess.messages.in
Expand Up @@ -76,6 +76,7 @@ messages -> WebProcess LegacyReceiver NotRefCounted {
DeleteWebsiteData(OptionSet<WebKit::WebsiteDataType> websiteDataTypes, WallTime modifiedSince) -> ()
DeleteWebsiteDataForOrigins(OptionSet<WebKit::WebsiteDataType> websiteDataTypes, Vector<WebCore::SecurityOriginData> origins) -> ()
DeleteWebsiteDataForOrigin(OptionSet<WebKit::WebsiteDataType> websiteDataTypes, struct WebCore::ClientOrigin origin) -> ()
ReloadExecutionContextsForOrigin(struct WebCore::ClientOrigin origin, std::optional<WebCore::FrameIdentifier> triggeringFrame) -> ()
DeleteAllCookies() -> ()

SetHiddenPageDOMTimerThrottlingIncreaseLimit(int milliseconds)
Expand Down

1 comment on commit 35591d2

@mattbrundage
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

executionContexts is misspelled as executionContext in the commit title, at the top of the commit summary, and in the title of https://bugs.webkit.org/show_bug.cgi?id=251821

Please sign in to comment.