Skip to content

Commit 212247d

Browse files
committed
Navigation Timing: cross-origin redirect opt-in should be based on destination origin.
https://bugs.webkit.org/show_bug.cgi?id=316647 Reviewed by NOBODY (OOPS!). This PR aligns the WebKit implementation with whatwg/fetch#1931 and whatwg/html#12513, and ensures that TAO opt-ins for navigation timing take the destination origin into account. No new tests, but a test progresses. * LayoutTests/imported/w3c/web-platform-tests/navigation-timing/redirect-tao-expected.txt: Progression. * LayoutTests/imported/w3c/web-platform-tests/navigation-timing/response-start-after-coop-bcg-switch.https-expected.txt: Expectation change. * LayoutTests/imported/w3c/web-platform-tests/navigation-timing/unload-event-same-origin-check-expected.txt: Progression. * Source/WebCore/page/Performance.cpp: (WebCore::Performance::addNavigationTiming): A no-referrer navigation that has a referring client should not expose redirect timing. * Source/WebCore/page/PerformanceNavigationTiming.cpp: (WebCore::PerformanceNavigationTiming::PerformanceNavigationTiming): intialize m_clientOrReferrerAllowsRedirectTiming. (WebCore::PerformanceNavigationTiming::shouldExposeRedirectTiming const): (WebCore::PerformanceNavigationTiming::redirectCount const): TAO check. * Source/WebCore/page/PerformanceNavigationTiming.h: * Source/WebCore/page/PerformanceResourceTiming.cpp: (WebCore::PerformanceResourceTiming::shouldExposeRedirectTiming const): (WebCore::PerformanceResourceTiming::redirectStart const): (WebCore::PerformanceResourceTiming::redirectEnd const): * Source/WebCore/page/PerformanceResourceTiming.h: * Source/WebCore/platform/network/NetworkLoadMetrics.cpp: (WebCore::NetworkLoadMetrics::NetworkLoadMetrics): (WebCore::NetworkLoadMetrics::isolatedCopy const): Copy navigationTAOCheckPassed. * Source/WebCore/platform/network/NetworkLoadMetrics.h: * Source/WebCore/platform/network/cocoa/NetworkLoadMetrics.mm: (WebCore::packageTimingData): Copy navigationTAOCheckPassed. (WebCore::copyTimingData): Copy navigationTAOCheckPassed. * Source/WebKit/NetworkProcess/NetworkDataTask.h: (WebKit::NetworkDataTask::setNavigationTAOCheckPassed): Setter. * Source/WebKit/NetworkProcess/NetworkLoad.cpp: (WebKit::NetworkLoad::setNavigationTAOCheckPassed): Setter. * Source/WebKit/NetworkProcess/NetworkLoad.h: * Source/WebKit/NetworkProcess/NetworkLoadChecker.cpp: (WebKit::NetworkLoadChecker::checkRedirection): Append TAO values. (WebKit::NetworkLoadChecker::validateResponse): Set TAO values on the response. (WebKit::NetworkLoadChecker::appendToNavigationTimingAllowValuesList): Accumulate TAO values. (WebKit::NetworkLoadChecker::passesNavigationTAOCheck const): Check if the response passes TAO check. * Source/WebKit/NetworkProcess/NetworkLoadChecker.h: (WebKit::NetworkLoadChecker::navigationTAOCheckPassed const): Getter. * Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp: (WebKit::NetworkResourceLoader::didReceiveResponse): Set navigationTAOCheckPassed. * Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.h: * Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm: (WebKit::NetworkDataTaskCocoa::setNavigationTAOCheckPassed): Setter. * Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp: (WebKit::NetworkDataTaskCurl::updateNetworkLoadMetrics): Set navigationTAOCheckPassed. (WebKit::NetworkDataTaskCurl::setNavigationTAOCheckPassed): Setter. * Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h: * Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp: (WebKit::NetworkDataTaskSoup::setNavigationTAOCheckPassed): Setter. * Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.h: * Source/WebKit/Shared/WebCoreArgumentCodersPlatform.serialization.in:
1 parent 5237eb1 commit 212247d

24 files changed

Lines changed: 125 additions & 18 deletions

LayoutTests/imported/w3c/web-platform-tests/navigation-timing/redirect-tao-expected.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11

22

3-
FAIL Exposed when a cross-origin redirect opts in to the destination origin assert_equals: redirectCount expected 1 but got 0
4-
FAIL Exposed when a cross-origin redirect opts in with a wildcard assert_equals: redirectCount expected 1 but got 0
5-
FAIL Exposed when every redirect in the chain opts in to the destination origin assert_equals: redirectCount expected 2 but got 0
3+
PASS Exposed when a cross-origin redirect opts in to the destination origin
4+
PASS Exposed when a cross-origin redirect opts in with a wildcard
5+
PASS Exposed when every redirect in the chain opts in to the destination origin
66
PASS Hidden when the redirect opts in to a non-destination origin
77
PASS Hidden when only part of the chain opts in to the destination origin
88
PASS Hidden for a no-referrer navigation even when the redirect opts in
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11

2-
FAIL Navigation responseStart is not clamped to zero after a cross-origin COOP browsing context group switch assert_greater_than: responseStart should not be clamped to zero after the COOP browsing context group switch expected a number greater than 0 but got 0
2+
FAIL Navigation responseStart is not clamped to zero after a cross-origin COOP browsing context group switch assert_equals: The cross-origin navigation should not expose the redirect count expected 0 but got 2
33

LayoutTests/imported/w3c/web-platform-tests/navigation-timing/unload-event-same-origin-check-expected.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ This test validates that the values of window.performance.getEntriesByType("navi
55

66

77
PASS Redirect chain with a partial TAO opt-in
8-
FAIL Redirect chain with full TAO opt-in assert_equals: Expected redirectCount to be 1 expected 1 but got 0
8+
PASS Redirect chain with full TAO opt-in
99
PASS Same-cross-same redirect chain with no TAO opt-in
1010
PASS cross-cross-same Redirect chain with no TAO opt-in
1111
PASS Previous document cross origin
@@ -14,6 +14,6 @@ PASS No previous document
1414
PASS Same origin previous document with same origin redirect
1515
PASS No previous document with same origin redirect
1616
PASS No previous document with cross origin redirect
17-
FAIL No previous document with cross origin redirect with partial TAO assert_equals: Expected redirectCount to be 1 expected 1 but got 0
17+
PASS No previous document with cross origin redirect with partial TAO
1818
PASS No previous document with cross origin redirect with TAO
1919

Source/WebCore/page/Performance.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,10 @@ void Performance::enqueueLargestContentfulPaint(Ref<LargestContentfulPaint>&& pa
408408

409409
void Performance::addNavigationTiming(DocumentLoader& documentLoader, Document& document, CachedResource& resource, const DocumentLoadTiming& timing, const NetworkLoadMetrics& metrics)
410410
{
411-
m_navigationTiming = PerformanceNavigationTiming::create(m_timeOrigin, resource, timing, metrics, document.eventTiming(), document.securityOrigin(), documentLoader.triggeringAction().type());
411+
// A no-referrer navigation that has a referring client should not expose redirect timing.
412+
// https://html.spec.whatwg.org/#create-the-navigation-timing-entry
413+
bool clientOrReferrerAllowsRedirectTiming = !documentLoader.triggeringAction().requester() || !documentLoader.request().httpReferrer().isEmpty();
414+
m_navigationTiming = PerformanceNavigationTiming::create(m_timeOrigin, resource, timing, metrics, document.eventTiming(), document.securityOrigin(), documentLoader.triggeringAction().type(), clientOrReferrerAllowsRedirectTiming);
412415
addToEntryBuffer(*m_navigationTiming);
413416
}
414417

Source/WebCore/page/PerformanceNavigationTiming.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,12 @@ static PerformanceNavigationTiming::NavigationType NODELETE toPerformanceNavigat
5050
return PerformanceNavigationTiming::NavigationType::Navigate;
5151
}
5252

53-
PerformanceNavigationTiming::PerformanceNavigationTiming(MonotonicTime timeOrigin, CachedResource& resource, const DocumentLoadTiming& documentLoadTiming, const NetworkLoadMetrics& metrics, const DocumentEventTiming& documentEventTiming, const SecurityOrigin& origin, WebCore::NavigationType navigationType)
53+
PerformanceNavigationTiming::PerformanceNavigationTiming(MonotonicTime timeOrigin, CachedResource& resource, const DocumentLoadTiming& documentLoadTiming, const NetworkLoadMetrics& metrics, const DocumentEventTiming& documentEventTiming, const SecurityOrigin& origin, WebCore::NavigationType navigationType, bool clientOrReferrerAllowsRedirectTiming)
5454
: PerformanceResourceTiming(timeOrigin, ResourceTiming::fromLoad(resource, resource.response().url(), "navigation"_s, documentLoadTiming, metrics, origin))
5555
, m_documentEventTiming(documentEventTiming)
5656
, m_documentLoadTiming(documentLoadTiming)
57-
, m_navigationType(toPerformanceNavigationTimingNavigationType(navigationType)) { }
57+
, m_navigationType(toPerformanceNavigationTimingNavigationType(navigationType))
58+
, m_clientOrReferrerAllowsRedirectTiming(clientOrReferrerAllowsRedirectTiming) { }
5859

5960
PerformanceNavigationTiming::~PerformanceNavigationTiming() = default;
6061

@@ -121,9 +122,17 @@ PerformanceNavigationTiming::NavigationType PerformanceNavigationTiming::type()
121122
return m_navigationType;
122123
}
123124

125+
bool PerformanceNavigationTiming::shouldExposeRedirectTiming() const
126+
{
127+
// A cross-origin redirect chain must not leak its redirect timing unless it opted in.
128+
// https://html.spec.whatwg.org/#create-the-navigation-timing-entry
129+
auto& metrics = m_resourceTiming.networkLoadMetrics();
130+
return !metrics.hasCrossOriginRedirect || (m_clientOrReferrerAllowsRedirectTiming && metrics.navigationTAOCheckPassed);
131+
}
132+
124133
unsigned short PerformanceNavigationTiming::redirectCount() const
125134
{
126-
if (m_resourceTiming.networkLoadMetrics().hasCrossOriginRedirect)
135+
if (!shouldExposeRedirectTiming())
127136
return 0;
128137

129138
return m_resourceTiming.networkLoadMetrics().redirectCount;

Source/WebCore/page/PerformanceNavigationTiming.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,18 @@ class PerformanceNavigationTiming final : public PerformanceResourceTiming {
7373
void documentLoadFinished(const NetworkLoadMetrics&);
7474

7575
private:
76-
PerformanceNavigationTiming(MonotonicTime timeOrigin, CachedResource&, const DocumentLoadTiming&, const NetworkLoadMetrics&, const DocumentEventTiming&, const SecurityOrigin&, WebCore::NavigationType);
76+
PerformanceNavigationTiming(MonotonicTime timeOrigin, CachedResource&, const DocumentLoadTiming&, const NetworkLoadMetrics&, const DocumentEventTiming&, const SecurityOrigin&, WebCore::NavigationType, bool clientOrReferrerAllowsRedirectTiming);
7777

7878
double millisecondsSinceOrigin(MonotonicTime) const;
7979
bool NODELETE sameOriginCheckFails() const;
80+
bool NODELETE shouldExposeRedirectTiming() const final;
8081

8182
DocumentEventTiming m_documentEventTiming;
8283
DocumentLoadTiming m_documentLoadTiming;
8384
NavigationType m_navigationType;
85+
// The client/no-referrer half of the redirect timing gate, which only the web process can tell.
86+
// https://html.spec.whatwg.org/#create-the-navigation-timing-entry
87+
bool m_clientOrReferrerAllowsRedirectTiming;
8488
};
8589

8690
} // namespace WebCore

Source/WebCore/page/PerformanceResourceTiming.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,14 @@ double PerformanceResourceTiming::workerStart() const
118118
return networkLoadTimeToDOMHighResTimeStamp(m_timeOrigin, m_resourceTiming.networkLoadMetrics().workerStart);
119119
}
120120

121+
bool PerformanceResourceTiming::shouldExposeRedirectTiming() const
122+
{
123+
return !m_resourceTiming.networkLoadMetrics().failsTAOCheck;
124+
}
125+
121126
double PerformanceResourceTiming::redirectStart() const
122127
{
123-
if (m_resourceTiming.networkLoadMetrics().failsTAOCheck)
128+
if (!shouldExposeRedirectTiming())
124129
return 0.0;
125130

126131
if (m_resourceTiming.isLoadedFromServiceWorker())
@@ -134,7 +139,7 @@ double PerformanceResourceTiming::redirectStart() const
134139

135140
double PerformanceResourceTiming::redirectEnd() const
136141
{
137-
if (m_resourceTiming.networkLoadMetrics().failsTAOCheck)
142+
if (!shouldExposeRedirectTiming())
138143
return 0.0;
139144

140145
if (m_resourceTiming.isLoadedFromServiceWorker())

Source/WebCore/page/PerformanceResourceTiming.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ class PerformanceResourceTiming : public PerformanceEntry {
8484

8585
bool isLoadedFromServiceWorker() const { return m_resourceTiming.isLoadedFromServiceWorker(); }
8686

87+
// Navigation timing exposes redirect timing under a different condition than the TAO check.
88+
virtual bool NODELETE shouldExposeRedirectTiming() const;
89+
8790
MonotonicTime m_timeOrigin;
8891
ResourceTiming m_resourceTiming;
8992
Vector<Ref<PerformanceServerTiming>> m_serverTiming;

Source/WebCore/platform/network/NetworkLoadMetrics.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ namespace WebCore {
3333

3434
NetworkLoadMetrics::NetworkLoadMetrics() = default;
3535

36-
NetworkLoadMetrics::NetworkLoadMetrics(MonotonicTime&& redirectStart, MonotonicTime&& fetchStart, MonotonicTime&& domainLookupStart, MonotonicTime&& domainLookupEnd, MonotonicTime&& connectStart, MonotonicTime&& secureConnectionStart, MonotonicTime&& connectEnd, MonotonicTime&& requestStart, MonotonicTime&& responseStart, MonotonicTime&& responseEnd, MonotonicTime&& workerStart, MonotonicTime&& firstInterimResponseStart, String&& protocol, uint16_t redirectCount, bool complete, bool cellular, bool expensive, bool constrained, bool multipath, bool isReusedConnection, bool failsTAOCheck, bool hasCrossOriginRedirect, bool fromPrefetch, bool fromCache, PrivacyStance privacyStance, uint64_t responseBodyBytesReceived, uint64_t responseBodyDecodedSize, RefPtr<AdditionalNetworkLoadMetricsForWebInspector>&& additionalNetworkLoadMetricsForWebInspector)
36+
NetworkLoadMetrics::NetworkLoadMetrics(MonotonicTime&& redirectStart, MonotonicTime&& fetchStart, MonotonicTime&& domainLookupStart, MonotonicTime&& domainLookupEnd, MonotonicTime&& connectStart, MonotonicTime&& secureConnectionStart, MonotonicTime&& connectEnd, MonotonicTime&& requestStart, MonotonicTime&& responseStart, MonotonicTime&& responseEnd, MonotonicTime&& workerStart, MonotonicTime&& firstInterimResponseStart, String&& protocol, uint16_t redirectCount, bool complete, bool cellular, bool expensive, bool constrained, bool multipath, bool isReusedConnection, bool failsTAOCheck, bool hasCrossOriginRedirect, bool navigationTAOCheckPassed, bool fromPrefetch, bool fromCache, PrivacyStance privacyStance, uint64_t responseBodyBytesReceived, uint64_t responseBodyDecodedSize, RefPtr<AdditionalNetworkLoadMetricsForWebInspector>&& additionalNetworkLoadMetricsForWebInspector)
3737
: redirectStart(WTF::move(redirectStart))
3838
, fetchStart(WTF::move(fetchStart))
3939
, domainLookupStart(WTF::move(domainLookupStart))
@@ -56,6 +56,7 @@ NetworkLoadMetrics::NetworkLoadMetrics(MonotonicTime&& redirectStart, MonotonicT
5656
, isReusedConnection(isReusedConnection)
5757
, failsTAOCheck(failsTAOCheck)
5858
, hasCrossOriginRedirect(hasCrossOriginRedirect)
59+
, navigationTAOCheckPassed(navigationTAOCheckPassed)
5960
, fromPrefetch(fromPrefetch)
6061
, fromCache(fromCache)
6162
, privacyStance(privacyStance)
@@ -183,6 +184,7 @@ NetworkLoadMetrics NetworkLoadMetrics::isolatedCopy() const
183184
copy.isReusedConnection = isReusedConnection;
184185
copy.failsTAOCheck = failsTAOCheck;
185186
copy.hasCrossOriginRedirect = hasCrossOriginRedirect;
187+
copy.navigationTAOCheckPassed = navigationTAOCheckPassed;
186188
copy.fromPrefetch = fromPrefetch;
187189
copy.fromCache = fromCache;
188190

Source/WebCore/platform/network/NetworkLoadMetrics.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class NetworkLoadMetrics {
6565
WTF_DEPRECATED_MAKE_FAST_ALLOCATED(NetworkLoadMetrics);
6666
public:
6767
WEBCORE_EXPORT NetworkLoadMetrics();
68-
WEBCORE_EXPORT NetworkLoadMetrics(MonotonicTime&& redirectStart, MonotonicTime&& fetchStart, MonotonicTime&& domainLookupStart, MonotonicTime&& domainLookupEnd, MonotonicTime&& connectStart, MonotonicTime&& secureConnectionStart, MonotonicTime&& connectEnd, MonotonicTime&& requestStart, MonotonicTime&& responseStart, MonotonicTime&& responseEnd, MonotonicTime&& workerStart, MonotonicTime&& firstInterimResponseStart, String&& protocol, uint16_t redirectCount, bool complete, bool cellular, bool expensive, bool constrained, bool multipath, bool isReusedConnection, bool failsTAOCheck, bool hasCrossOriginRedirect, bool fromPrefetch, bool fromCache, PrivacyStance, uint64_t responseBodyBytesReceived, uint64_t responseBodyDecodedSize, RefPtr<AdditionalNetworkLoadMetricsForWebInspector>&&);
68+
WEBCORE_EXPORT NetworkLoadMetrics(MonotonicTime&& redirectStart, MonotonicTime&& fetchStart, MonotonicTime&& domainLookupStart, MonotonicTime&& domainLookupEnd, MonotonicTime&& connectStart, MonotonicTime&& secureConnectionStart, MonotonicTime&& connectEnd, MonotonicTime&& requestStart, MonotonicTime&& responseStart, MonotonicTime&& responseEnd, MonotonicTime&& workerStart, MonotonicTime&& firstInterimResponseStart, String&& protocol, uint16_t redirectCount, bool complete, bool cellular, bool expensive, bool constrained, bool multipath, bool isReusedConnection, bool failsTAOCheck, bool hasCrossOriginRedirect, bool navigationTAOCheckPassed, bool fromPrefetch, bool fromCache, PrivacyStance, uint64_t responseBodyBytesReceived, uint64_t responseBodyDecodedSize, RefPtr<AdditionalNetworkLoadMetricsForWebInspector>&&);
6969

7070
WEBCORE_EXPORT static const NetworkLoadMetrics& NODELETE emptyMetrics();
7171

@@ -117,6 +117,8 @@ class NetworkLoadMetrics {
117117
bool isReusedConnection : 1 { false };
118118
bool failsTAOCheck : 1 { false };
119119
bool hasCrossOriginRedirect : 1 { false };
120+
// https://fetch.spec.whatwg.org/#navigation-tao-check
121+
bool navigationTAOCheckPassed : 1 { false };
120122
bool fromPrefetch : 1 { false };
121123
bool fromCache : 1 { false };
122124

0 commit comments

Comments
 (0)