Skip to content

Commit

Permalink
Track when link decoration filtering was applied to a request's url
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=265531
rdar://118940125

Reviewed by Wenson Hsieh.

Link decoration filtering (LDF) isn't always applied to requests. This patch
provides a way for later stages of the resource loading process to know if LDF
was previously applied, but this patch does not make any changes to the current
behavior.

* Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml:
* Source/WebCore/loader/FrameLoader.cpp:
(WebCore::FrameLoader::updateRequestAndAddExtraFields):
* Source/WebCore/page/ChromeClient.h:
(WebCore::ChromeClient::applyLinkDecorationFilteringWithResult const):
(WebCore::ChromeClient::applyLinkDecorationFiltering const):
* Source/WebCore/platform/network/ResourceRequestBase.cpp:
(WebCore::ResourceRequestBase::setAsIsolatedCopy):
(WebCore::ResourceRequestBase::setURL):
(WebCore::ResourceRequestBase::setDidFilterLinkDecoration):
* Source/WebCore/platform/network/ResourceRequestBase.h:
(WebCore::ResourceRequestBase::RequestData::RequestData):
(WebCore::ResourceRequestBase::didFilterLinkDecoration const):
* Source/WebCore/platform/network/cf/ResourceRequest.h:
* Source/WebCore/platform/network/cocoa/ResourceRequestCocoa.mm:
(WebCore::ResourceRequest::ResourceRequest):
(WebCore::ResourceRequest::getResourceRequestPlatformData const):
* Source/WebKit/Shared/Cocoa/WebCoreArgumentCodersCocoa.serialization.in:
* Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in:
* Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::applyLinkDecorationFilteringWithResult const):
(WebKit::WebChromeClient::applyLinkDecorationFiltering const): Deleted.
* Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h:
* Source/WebKit/WebProcess/WebPage/Cocoa/WebPageCocoa.mm:
(WebKit::WebPage::applyLinkDecorationFilteringWithResult):
(WebKit::WebPage::applyLinkDecorationFiltering): Deleted.
* Source/WebKit/WebProcess/WebPage/WebPage.h:
(WebKit::WebPage::applyLinkDecorationFiltering):
(WebKit::WebPage::applyLinkDecorationFilteringWithResult):

Canonical link: https://commits.webkit.org/271712@main
  • Loading branch information
sysrqb authored and Matthew Finkel committed Dec 8, 2023
1 parent 55786dc commit 6f19e5c
Show file tree
Hide file tree
Showing 13 changed files with 61 additions and 23 deletions.
14 changes: 14 additions & 0 deletions Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2647,6 +2647,20 @@ FileSystemAccessEnabled:
"PLATFORM(COCOA)" : true
default: false

FilterLinkDecorationByDefaultEnabled:
type: bool
status: testable
category: networking
humanReadableName: "Filter Link Decoration"
humanReadableDescription: "Enable Filtering Link Decoration"
defaultValue:
WebKitLegacy:
default: false
WebKit:
default: false
WebCore:
default: false

FixedFontFamily:
type: String
status: embedder
Expand Down
6 changes: 4 additions & 2 deletions Source/WebCore/loader/FrameLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3156,8 +3156,10 @@ void FrameLoader::updateRequestAndAddExtraFields(ResourceRequest& request, IsMai
if (shouldUpdate == ShouldUpdateAppInitiatedValue::Yes && localFrame->loader().documentLoader())
request.setIsAppInitiated(localFrame->loader().documentLoader()->lastNavigationWasAppInitiated());

if (page && isMainResource)
request.setURL(page->chrome().client().applyLinkDecorationFiltering(request.url(), LinkDecorationFilteringTrigger::Navigation));
if (page && isMainResource) {
auto [filteredURL, didFilter] = page->chrome().client().applyLinkDecorationFilteringWithResult(request.url(), LinkDecorationFilteringTrigger::Navigation);
request.setURL(filteredURL, didFilter == DidFilterLinkDecoration::Yes);
}
}

void FrameLoader::scheduleRefreshIfNeeded(Document& document, const String& content, IsMetaRefresh isMetaRefresh)
Expand Down
5 changes: 4 additions & 1 deletion Source/WebCore/page/ChromeClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ enum class ModalContainerControlType : uint8_t;
enum class ModalContainerDecision : uint8_t;
enum class RouteSharingPolicy : uint8_t;

enum class DidFilterLinkDecoration : bool { No, Yes };

class ChromeClient {
public:
virtual void chromeDestroyed() = 0;
Expand Down Expand Up @@ -558,7 +560,8 @@ class ChromeClient {
virtual void handlePDFServiceClick(const IntPoint&, HTMLAttachmentElement&) { }
#endif

virtual URL applyLinkDecorationFiltering(const URL& url, LinkDecorationFilteringTrigger) const { return url; }
virtual std::pair<URL, DidFilterLinkDecoration> applyLinkDecorationFilteringWithResult(const URL& url, LinkDecorationFilteringTrigger) const { return { url, DidFilterLinkDecoration::No }; };
URL applyLinkDecorationFiltering(const URL& url, LinkDecorationFilteringTrigger trigger) const { return applyLinkDecorationFilteringWithResult(url, trigger).first; }
virtual URL allowedQueryParametersForAdvancedPrivacyProtections(const URL& url) const { return url; }

virtual bool shouldDispatchFakeMouseMoveEvents() const { return true; }
Expand Down
11 changes: 10 additions & 1 deletion Source/WebCore/platform/network/ResourceRequestBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ void ResourceRequestBase::setAsIsolatedCopy(const ResourceRequest& other)
setIsAppInitiated(other.isAppInitiated());
setPrivacyProxyFailClosedForUnreachableNonMainHosts(other.privacyProxyFailClosedForUnreachableNonMainHosts());
setUseAdvancedPrivacyProtections(other.useAdvancedPrivacyProtections());
setDidFilterLinkDecoration(other.didFilterLinkDecoration());
}

bool ResourceRequestBase::isEmpty() const
Expand All @@ -122,11 +123,12 @@ const URL& ResourceRequestBase::url() const
return m_requestData.m_url;
}

void ResourceRequestBase::setURL(const URL& url)
void ResourceRequestBase::setURL(const URL& url, bool didFilterLinkDecoration)
{
updateResourceRequest();

m_requestData.m_url = url;
m_requestData.m_didFilterLinkDecoration = didFilterLinkDecoration;

m_platformRequestUpdated = false;
}
Expand Down Expand Up @@ -663,6 +665,13 @@ void ResourceRequestBase::setUseAdvancedPrivacyProtections(bool useAdvancedPriva
m_platformRequestUpdated = false;
}

void ResourceRequestBase::setDidFilterLinkDecoration(bool didFilterLinkDecoration)
{
if (m_requestData.m_didFilterLinkDecoration == didFilterLinkDecoration)
return;
m_requestData.m_didFilterLinkDecoration = didFilterLinkDecoration;
}

bool equalIgnoringHeaderFields(const ResourceRequestBase& a, const ResourceRequestBase& b)
{
if (a.url() != b.url())
Expand Down
9 changes: 7 additions & 2 deletions Source/WebCore/platform/network/ResourceRequestBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class ResourceRequestBase {
struct RequestData {
RequestData() { }

RequestData(const URL& url, const URL& firstPartyForCookies, double timeoutInterval, const String& httpMethod, const HTTPHeaderMap& httpHeaderFields, const Vector<String>& responseContentDispositionEncodingFallbackArray, const ResourceRequestCachePolicy& cachePolicy, const SameSiteDisposition& sameSiteDisposition, const ResourceLoadPriority& priority, const ResourceRequestRequester& requester, bool allowCookies, bool isTopSite, bool isAppInitiated = true, bool privacyProxyFailClosedForUnreachableNonMainHosts = false, bool useAdvancedPrivacyProtections = false)
RequestData(const URL& url, const URL& firstPartyForCookies, double timeoutInterval, const String& httpMethod, const HTTPHeaderMap& httpHeaderFields, const Vector<String>& responseContentDispositionEncodingFallbackArray, const ResourceRequestCachePolicy& cachePolicy, const SameSiteDisposition& sameSiteDisposition, const ResourceLoadPriority& priority, const ResourceRequestRequester& requester, bool allowCookies, bool isTopSite, bool isAppInitiated = true, bool privacyProxyFailClosedForUnreachableNonMainHosts = false, bool useAdvancedPrivacyProtections = false, bool didFilterLinkDecoration = false)
: m_url(url)
, m_firstPartyForCookies(firstPartyForCookies)
, m_timeoutInterval(timeoutInterval)
Expand All @@ -82,6 +82,7 @@ class ResourceRequestBase {
, m_isAppInitiated(isAppInitiated)
, m_privacyProxyFailClosedForUnreachableNonMainHosts(privacyProxyFailClosedForUnreachableNonMainHosts)
, m_useAdvancedPrivacyProtections(useAdvancedPrivacyProtections)
, m_didFilterLinkDecoration(didFilterLinkDecoration)
{
}

Expand All @@ -106,6 +107,7 @@ class ResourceRequestBase {
bool m_isAppInitiated : 1 { true };
bool m_privacyProxyFailClosedForUnreachableNonMainHosts : 1 { false };
bool m_useAdvancedPrivacyProtections : 1 { false };
bool m_didFilterLinkDecoration : 1 { false };
};

ResourceRequestBase(RequestData&& requestData)
Expand All @@ -125,7 +127,7 @@ class ResourceRequestBase {
WEBCORE_EXPORT bool isEmpty() const;

WEBCORE_EXPORT const URL& url() const;
WEBCORE_EXPORT void setURL(const URL& url);
WEBCORE_EXPORT void setURL(const URL&, bool didFilterLinkDecoration = false);

void redirectAsGETIfNeeded(const ResourceRequestBase &, const ResourceResponse&);

Expand Down Expand Up @@ -266,6 +268,9 @@ class ResourceRequestBase {
bool useAdvancedPrivacyProtections() const { return m_requestData.m_useAdvancedPrivacyProtections; }
WEBCORE_EXPORT void setUseAdvancedPrivacyProtections(bool);

bool didFilterLinkDecoration() const { return m_requestData.m_didFilterLinkDecoration; }
WEBCORE_EXPORT void setDidFilterLinkDecoration(bool);

protected:
// Used when ResourceRequest is initialized from a platform representation of the request
ResourceRequestBase()
Expand Down
1 change: 1 addition & 0 deletions Source/WebCore/platform/network/cf/ResourceRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ struct ResourceRequestPlatformData {
std::optional<ResourceRequestRequester> m_requester;
bool m_privacyProxyFailClosedForUnreachableNonMainHosts { false };
bool m_useAdvancedPrivacyProtections { false };
bool m_didFilterLinkDecoration { false };
};

using ResourceRequestData = std::variant<ResourceRequestBase::RequestData, ResourceRequestPlatformData>;
Expand Down
2 changes: 2 additions & 0 deletions Source/WebCore/platform/network/cocoa/ResourceRequestCocoa.mm
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
setIsAppInitiated(*platformData.m_isAppInitiated);
setPrivacyProxyFailClosedForUnreachableNonMainHosts(platformData.m_privacyProxyFailClosedForUnreachableNonMainHosts);
setUseAdvancedPrivacyProtections(platformData.m_useAdvancedPrivacyProtections);
setDidFilterLinkDecoration(platformData.m_didFilterLinkDecoration);
}

setCachePartition(cachePartition);
Expand Down Expand Up @@ -125,6 +126,7 @@
requester(),
privacyProxyFailClosedForUnreachableNonMainHosts(),
useAdvancedPrivacyProtections(),
didFilterLinkDecoration(),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ header: <WebCore/ResourceRequest.h>
std::optional<WebCore::ResourceRequestRequester> m_requester;
bool m_privacyProxyFailClosedForUnreachableNonMainHosts;
bool m_useAdvancedPrivacyProtections;
bool m_didFilterLinkDecoration;
};

[Nested] struct WebCore::AttributedString::ParagraphStyleWithTableAndListIDs {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1868,6 +1868,7 @@ header: <WebCore/ResourceRequest.h>
[BitField] bool m_isAppInitiated;
[BitField] bool m_privacyProxyFailClosedForUnreachableNonMainHosts;
[BitField] bool m_useAdvancedPrivacyProtections;
[BitField] bool m_didFilterLinkDecoration;
};

#if USE(SOUP)
Expand Down
4 changes: 2 additions & 2 deletions Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1701,9 +1701,9 @@ void WebChromeClient::requestTextRecognition(Element& element, TextRecognitionOp

#endif

URL WebChromeClient::applyLinkDecorationFiltering(const URL& url, LinkDecorationFilteringTrigger trigger) const
std::pair<URL, DidFilterLinkDecoration> WebChromeClient::applyLinkDecorationFilteringWithResult(const URL& url, LinkDecorationFilteringTrigger trigger) const
{
return protectedPage()->applyLinkDecorationFiltering(url, trigger);
return protectedPage()->applyLinkDecorationFilteringWithResult(url, trigger);
}

URL WebChromeClient::allowedQueryParametersForAdvancedPrivacyProtections(const URL& url) const
Expand Down
3 changes: 2 additions & 1 deletion Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace WebCore {
class HTMLImageElement;
class RegistrableDomain;
enum class CookieConsentDecisionResult : uint8_t;
enum class DidFilterLinkDecoration : bool;
enum class StorageAccessPromptWasShown : bool;
enum class StorageAccessWasGranted : bool;
struct TextRecognitionOptions;
Expand Down Expand Up @@ -465,7 +466,7 @@ class WebChromeClient final : public WebCore::ChromeClient {
void textAutosizingUsesIdempotentModeChanged() final;
#endif

URL applyLinkDecorationFiltering(const URL&, WebCore::LinkDecorationFilteringTrigger) const final;
std::pair<URL, WebCore::DidFilterLinkDecoration> applyLinkDecorationFilteringWithResult(const URL&, WebCore::LinkDecorationFilteringTrigger) const final;
URL allowedQueryParametersForAdvancedPrivacyProtections(const URL&) const final;

#if ENABLE(MEDIA_CONTROLS_CONTEXT_MENUS) && USE(UICONTEXTMENU)
Expand Down
21 changes: 9 additions & 12 deletions Source/WebKit/WebProcess/WebPage/Cocoa/WebPageCocoa.mm
Original file line number Diff line number Diff line change
Expand Up @@ -735,40 +735,37 @@
completionHandler(true);
}

URL WebPage::applyLinkDecorationFiltering(const URL& url, LinkDecorationFilteringTrigger trigger)
std::pair<URL, DidFilterLinkDecoration> WebPage::applyLinkDecorationFilteringWithResult(const URL& url, LinkDecorationFilteringTrigger trigger)
{
#if ENABLE(ADVANCED_PRIVACY_PROTECTIONS)
if (m_linkDecorationFilteringData.isEmpty() && m_domainScopedLinkDecorationFilteringData.isEmpty()) {
RELEASE_LOG_ERROR(ResourceLoadStatistics, "Unable to filter tracking query parameters (missing data)");
return url;
return { url, DidFilterLinkDecoration::No };
}

RefPtr mainFrame = m_mainFrame->coreLocalFrame();
if (!mainFrame)
return url;
return { url, DidFilterLinkDecoration::No };

auto isLinkDecorationFilteringEnabled = [&](const DocumentLoader* loader) {
if (!loader)
return false;
auto effectivePolicies = trigger == LinkDecorationFilteringTrigger::Navigation ? loader->originatorAdvancedPrivacyProtections() : loader->advancedPrivacyProtections();
return effectivePolicies.contains(AdvancedPrivacyProtections::LinkDecorationFiltering);
return effectivePolicies.contains(AdvancedPrivacyProtections::LinkDecorationFiltering) || m_page->settings().filterLinkDecorationByDefaultEnabled();
};

bool shouldApplyLinkDecorationFiltering = [&] {
if (isLinkDecorationFilteringEnabled(RefPtr { mainFrame->loader().documentLoader() }.get()))
return true;

if (isLinkDecorationFilteringEnabled(RefPtr { mainFrame->loader().provisionalDocumentLoader() }.get()))
if (isLinkDecorationFilteringEnabled(RefPtr { mainFrame->loader().activeDocumentLoader() }.get()))
return true;

return isLinkDecorationFilteringEnabled(RefPtr { mainFrame->loader().policyDocumentLoader() }.get());
}();

if (!shouldApplyLinkDecorationFiltering)
return url;
return { url, DidFilterLinkDecoration::No };

if (!url.hasQuery())
return url;
return { url, DidFilterLinkDecoration::No };

auto sanitizedURL = url;

Expand All @@ -784,9 +781,9 @@
WEBPAGE_RELEASE_LOG(ResourceLoadStatistics, "Blocked known tracking query parameters: %s", removedParametersString.utf8().data());
}

return sanitizedURL;
return { sanitizedURL, DidFilterLinkDecoration::Yes };
#else
return url;
return { url, DidFilterLinkDecoration::No };
#endif
}

Expand Down
6 changes: 4 additions & 2 deletions Source/WebKit/WebProcess/WebPage/WebPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include "WebsitePoliciesData.h"
#include <JavaScriptCore/InspectorFrontendChannel.h>
#include <WebCore/AppHighlight.h>
#include <WebCore/ChromeClient.h>
#include <WebCore/DiagnosticLoggingClient.h>
#include <WebCore/DictationContext.h>
#include <WebCore/DictionaryPopupInfo.h>
Expand Down Expand Up @@ -1540,7 +1541,8 @@ class WebPage : public API::ObjectImpl<API::Object::Type::BundlePage>, public IP

void isPlayingMediaDidChange(WebCore::MediaProducerMediaStateFlags);

URL applyLinkDecorationFiltering(const URL&, WebCore::LinkDecorationFilteringTrigger);
std::pair<URL, WebCore::DidFilterLinkDecoration> applyLinkDecorationFilteringWithResult(const URL&, WebCore::LinkDecorationFilteringTrigger);
URL applyLinkDecorationFiltering(const URL& url, WebCore::LinkDecorationFilteringTrigger trigger) { return applyLinkDecorationFilteringWithResult(url, trigger).first; }
URL allowedQueryParametersForAdvancedPrivacyProtections(const URL&);

#if ENABLE(IMAGE_ANALYSIS)
Expand Down Expand Up @@ -2675,7 +2677,7 @@ inline bool WebPage::shouldAvoidComputingPostLayoutDataForEditorState() const {
#endif

#if !PLATFORM(COCOA)
inline URL WebPage::applyLinkDecorationFiltering(const URL& url, WebCore::LinkDecorationFilteringTrigger) { return url; }
inline std::pair<URL, WebCore::DidFilterLinkDecoration> WebPage::applyLinkDecorationFilteringWithResult(const URL& url, WebCore::LinkDecorationFilteringTrigger) { return { url, WebCore::DidFilterLinkDecoration::No }; }
inline URL WebPage::allowedQueryParametersForAdvancedPrivacyProtections(const URL& url) { return url; }
#endif

Expand Down

0 comments on commit 6f19e5c

Please sign in to comment.