Diff
Modified: trunk/LayoutTests/ChangeLog (264852 => 264853)
--- trunk/LayoutTests/ChangeLog 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/LayoutTests/ChangeLog 2020-07-24 20:48:42 UTC (rev 264853)
@@ -1,3 +1,15 @@
+2020-07-24 Jiewen Tan <[email protected]>
+
+ Propagating user gesture through Fetch API
+ https://bugs.webkit.org/show_bug.cgi?id=214444
+ <rdar://problem/65980953>
+
+ Reviewed by Youenn Fablet.
+
+ * http/tests/media/user-gesture-preserved-across-xmlhttprequest-expected.txt:
+ * http/tests/media/user-gesture-preserved-across-xmlhttprequest.html:
+ * http/tests/xmlhttprequest/resources/download-header-with-delay.php: Added.
+
2020-07-24 Karl Rackler <[email protected]>
[ iOS wk2 ] imported/w3c/web-platform-tests/css/css-fonts/crash-font-face-invalid-descriptor.html is a flaky timeout
Modified: trunk/LayoutTests/http/tests/media/user-gesture-preserved-across-xmlhttprequest-expected.txt (264852 => 264853)
--- trunk/LayoutTests/http/tests/media/user-gesture-preserved-across-xmlhttprequest-expected.txt 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/LayoutTests/http/tests/media/user-gesture-preserved-across-xmlhttprequest-expected.txt 2020-07-24 20:48:42 UTC (rev 264853)
@@ -52,5 +52,91 @@
RUN(shouldReject(mediaElement.play()).then(testComplete, testComplete))
Promise rejected correctly OK
+** gesture -> fetch -> window.open: should fail because Fetch only propagates user gesture for media
+fetching, delay = 100
+FETCH(resolved): status = 200
+EXPECTED (window.open("about:blank") == 'null') OK
+
+** gesture -> fetch -> video playback: should succeed
+EVENT(canplaythrough)
+fetching, delay = 100
+FETCH(resolved): status = 200
+RUN(shouldResolve(mediaElement.play()).then(testComplete, testComplete))
+Promise resolved OK
+
+** gesture -> "long" Fetch -> video playback: should fail
+EVENT(canplaythrough)
+fetching, delay = 300
+FETCH(resolved): status = 200
+RUN(shouldReject(mediaElement.play()).then(testComplete, testComplete))
+Promise rejected correctly OK
+
+** no gesture -> fetch -> video playback: should fail
+EVENT(canplaythrough)
+fetching, delay = 100
+FETCH(resolved): status = 200
+RUN(shouldReject(mediaElement.play()).then(testComplete, testComplete))
+Promise rejected correctly OK
+
+** gesture -> fetch -> blob -> window.open: should fail because Fetch only propagates user gesture for media
+fetching blob, delay = 100
+FETCH(resolved): status = 200
+FETCH(response resolved)
+EXPECTED (window.open("about:blank") == 'null') OK
+
+** gesture -> fetch -> blob -> video playback: should succeed
+EVENT(canplaythrough)
+fetching blob, delay = 100
+FETCH(resolved): status = 200
+FETCH(response resolved)
+RUN(shouldResolve(mediaElement.play()).then(testComplete, testComplete))
+Promise resolved OK
+
+** gesture -> fetch -> "long" blob -> video playback: should fail
+EVENT(canplaythrough)
+fetching blob, delay = 300
+FETCH(resolved): status = 200
+FETCH(response resolved)
+RUN(shouldReject(mediaElement.play()).then(testComplete, testComplete))
+Promise rejected correctly OK
+
+** no gesture -> fetch -> blob -> video playback: should fail
+EVENT(canplaythrough)
+fetching blob, delay = 100
+FETCH(resolved): status = 200
+FETCH(response resolved)
+RUN(shouldReject(mediaElement.play()).then(testComplete, testComplete))
+Promise rejected correctly OK
+
+** no gesture -> promise -> video playback: should fail
+EVENT(canplaythrough)
+promise
+PROMISE(resolved)
+RUN(shouldReject(mediaElement.play()).then(testComplete, testComplete))
+Promise rejected correctly OK
+
+** gesture -> promise -> video playback: should fail because promise only propagates user gesture propagated through Fetch
+EVENT(canplaythrough)
+promise
+PROMISE(resolved)
+RUN(shouldReject(mediaElement.play()).then(testComplete, testComplete))
+Promise rejected correctly OK
+
+** gesture -> fetch -> promise -> video playback: should succeed
+EVENT(canplaythrough)
+fetch then promise
+FETCH(resolved): status = 200
+PROMISE(resolved)
+RUN(shouldResolve(mediaElement.play()).then(testComplete, testComplete))
+Promise resolved OK
+
+** gesture -> fetch -> crypto -> video playback: should fail since the user gesture will not be propagated through other API even though it returns promises
+EVENT(canplaythrough)
+fetch then crypto
+FETCH(resolved): status = 200
+CRYPTO(key generated)
+RUN(shouldReject(mediaElement.play()).then(testComplete, testComplete))
+Promise rejected correctly OK
+
END OF TEST
Modified: trunk/LayoutTests/http/tests/media/user-gesture-preserved-across-xmlhttprequest.html (264852 => 264853)
--- trunk/LayoutTests/http/tests/media/user-gesture-preserved-across-xmlhttprequest.html 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/LayoutTests/http/tests/media/user-gesture-preserved-across-xmlhttprequest.html 2020-07-24 20:48:42 UTC (rev 264853)
@@ -19,7 +19,7 @@
{
var xhr = new XMLHttpRequest();
if (window.internals)
- window.internals.setXHRMaximumIntervalForUserGestureForwarding(xhr, timeout);
+ window.internals.setMaximumIntervalForUserGestureForwardingForFetch(timeout);
xhr.open('GET', `/xmlhttprequest/resources/download-with-delay.php?iteration=1&delay=${delay}`, true);
@@ -41,6 +41,70 @@
xhr.send(null);
}
+ function doFetch(delay, timeout, completionHandler)
+ {
+ if (window.internals)
+ window.internals.setMaximumIntervalForUserGestureForwardingForFetch(timeout);
+
+ fetch(`/xmlhttprequest/resources/download-header-with-delay.php?delay=${delay}`, { method: 'GET', cache: "no-cache" }).then(response => {
+ consoleWrite(`FETCH(resolved): status = ${response.status}`);
+ completionHandler();
+ }, error => {
+ consoleWrite(`FETCH(rejected): exception code = ${error.code}`);
+ });
+ }
+
+ function doFetchBlob(delay, timeout, completionHandler)
+ {
+ fetch(`/xmlhttprequest/resources/download-with-delay.php?iteration=1&delay=${delay}`, { method: 'GET', cache: "no-cache" }).then(response => {
+ consoleWrite(`FETCH(resolved): status = ${response.status}`);
+ if (window.internals)
+ window.internals.setMaximumIntervalForUserGestureForwardingForFetch(timeout);
+ return response.blob();
+ }, error => {
+ consoleWrite(`FETCH(rejected): exception code = ${error.code}`);
+ }).then(response => {
+ consoleWrite(`FETCH(response resolved)`);
+ completionHandler();
+ }, error => {
+ consoleWrite(`FETCH(response rejected): exception code = ${error.code}`);
+ });
+ }
+
+ function doPromise(completionHandler)
+ {
+ const promise = new Promise( (resolutionFunc) => {
+ resolutionFunc();
+ });
+
+ promise.then(() => {
+ consoleWrite(`PROMISE(resolved)`);
+ completionHandler()
+ });
+ }
+
+ function doFetchThenPromise(completionHandler)
+ {
+ fetch(`/xmlhttprequest/resources/download-with-delay.php?iteration=1`, { method: 'GET', cache: "no-cache" }).then(response => {
+ consoleWrite(`FETCH(resolved): status = ${response.status}`);
+ return new Promise( (resolutionFunc) => resolutionFunc() );
+ }).then(() => {
+ consoleWrite(`PROMISE(resolved)`);
+ completionHandler()
+ });
+ }
+
+ function doFetchThenCrypto(completionHandler)
+ {
+ fetch(`/xmlhttprequest/resources/download-with-delay.php?iteration=1`, { method: 'GET', cache: "no-cache" }).then(response => {
+ consoleWrite(`FETCH(resolved): status = ${response.status}`);
+ return crypto.subtle.generateKey({name: "RSA-OAEP", modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: "sha-1"}, false, ["decrypt", "encrypt", "wrapKey", "unwrapKey"]);
+ }).then(key => {
+ consoleWrite(`CRYPTO(key generated)`);
+ completionHandler()
+ });
+ }
+
function testComplete()
{
if (autoRun)
@@ -81,8 +145,27 @@
consoleWrite(`setting timeout, delay = ${delay}`);
setTimeout(() => { runTest(test); }, delay);
break;
+ case 'fetch':
+ consoleWrite(`fetching, delay = ${delay}`);
+ doFetch(delay, test.timeout || 0.6, () => runTest(test));
+ break;
+ case 'fetchblob':
+ consoleWrite(`fetching blob, delay = ${delay}`);
+ doFetchBlob(delay, test.timeout || 0.6, () => runTest(test));
+ break;
+ case 'promise':
+ consoleWrite(`promise`);
+ doPromise(() => runTest(test));
+ break;
+ case 'fetchthenpromise':
+ consoleWrite(`fetch then promise`);
+ doFetchThenPromise(() => runTest(test));
+ break;
+ case 'fetchthencrypto':
+ consoleWrite(`fetch then crypto`);
+ doFetchThenCrypto(() => runTest(test));
+ break;
}
-
}
let tests = [
@@ -102,7 +185,44 @@
action : 'play', withkey : false, success : false, sequence : ['100 XHR', '100 timeout'] },
{ title : 'gesture -> "long" XHR -> video playback: should fail',
- action : 'play', withkey : false, success : false, timeout : 0.1, sequence : ['300 XHR'] },
+ action : 'play', withkey : true, success : false, timeout : 0.1, sequence : ['300 XHR'] },
+
+ { title : 'gesture -> fetch -> window.open: should fail because Fetch only propagates user gesture for media',
+ action : 'popup', withkey : true, success : false, sequence : ['100 Fetch'] },
+
+ { title : 'gesture -> fetch -> video playback: should succeed',
+ action : 'play', withkey : true, success : true, sequence : ['100 Fetch'] },
+
+ { title : 'gesture -> "long" Fetch -> video playback: should fail',
+ action : 'play', withkey : true, success : false, timeout : 0.1, sequence : ['300 Fetch'] },
+
+ { title : 'no gesture -> fetch -> video playback: should fail',
+ action : 'play', withkey : false, success : false, sequence : ['100 Fetch'] },
+
+ { title : 'gesture -> fetch -> blob -> window.open: should fail because Fetch only propagates user gesture for media',
+ action : 'popup', withkey : true, success : false, sequence : ['100 FetchBlob'] },
+
+ { title : 'gesture -> fetch -> blob -> video playback: should succeed',
+ action : 'play', withkey : true, success : true, sequence : ['100 FetchBlob'] },
+
+ { title : 'gesture -> fetch -> "long" blob -> video playback: should fail',
+ action : 'play', withkey : true, success : false, timeout : 0.1, sequence : ['300 FetchBlob'] },
+
+ { title : 'no gesture -> fetch -> blob -> video playback: should fail',
+ action : 'play', withkey : false, success : false, sequence : ['100 FetchBlob'] },
+
+ { title : 'no gesture -> promise -> video playback: should fail',
+ action : 'play', withkey : false, success : false, sequence : ['0 promise'] },
+
+ { title : 'gesture -> promise -> video playback: should fail because promise only propagates user gesture propagated through Fetch',
+ action : 'play', withkey : true, success : false, sequence : ['0 promise'] },
+
+ { title : 'gesture -> fetch -> promise -> video playback: should succeed',
+ action : 'play', withkey : true, success : true, sequence : ['0 FetchThenPromise'] },
+
+ { title : 'gesture -> fetch -> crypto -> video playback: should fail since the user gesture will not be propagated through other API even though it returns promises',
+ action : 'play', withkey : true, success : false, sequence : ['0 FetchThenCrypto'] },
+
];
function nextTest()
@@ -109,7 +229,7 @@
{
if (!tests.length) {
consoleWrite('');
- endTest()
+ endTest();
return;
}
Added: trunk/LayoutTests/http/tests/xmlhttprequest/resources/download-header-with-delay.php (0 => 264853)
--- trunk/LayoutTests/http/tests/xmlhttprequest/resources/download-header-with-delay.php (rev 0)
+++ trunk/LayoutTests/http/tests/xmlhttprequest/resources/download-header-with-delay.php 2020-07-24 20:48:42 UTC (rev 264853)
@@ -0,0 +1,14 @@
+<?php
+$delay = $_GET['delay'];
+usleep($delay * 1000);
+
+header("Expires: Thu, 01 Dec 2003 16:00:00 GMT");
+header("Cache-Control: no-cache, no-store, must-revalidate");
+header("Pragma: no-cache");
+header("Content-Type: application/x-no-buffering-please");
+
+echo "$delay\n";
+echo "foobar\n";
+ob_flush();
+flush();
+?>
Modified: trunk/Source/WebCore/ChangeLog (264852 => 264853)
--- trunk/Source/WebCore/ChangeLog 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/Source/WebCore/ChangeLog 2020-07-24 20:48:42 UTC (rev 264853)
@@ -1,3 +1,59 @@
+2020-07-24 Jiewen Tan <[email protected]>
+
+ Propagating user gesture through Fetch API
+ https://bugs.webkit.org/show_bug.cgi?id=214444
+ <rdar://problem/65980953>
+
+ Reviewed by Youenn Fablet.
+
+ This patch propagates media only user gestures through Fetch API, including Fetch and FetchResponse.
+
+ Covered by new test contents.
+
+ * Modules/fetch/DOMWindowFetch.cpp:
+ (WebCore::DOMWindowFetch::fetch):
+ Propagates media only user gestures through Fetch.
+
+ * Modules/fetch/FetchBodyConsumer.cpp:
+ (WebCore::FetchBodyConsumer::clean):
+ (WebCore::FetchBodyConsumer::resolve):
+ (WebCore::FetchBodyConsumer::setConsumePromise):
+ (WebCore::FetchBodyConsumer::resetConsumePromise):
+ (WebCore::FetchBodyConsumer::loadingFailed):
+ (WebCore::FetchBodyConsumer::loadingSucceeded):
+ * Modules/fetch/FetchBodyConsumer.h:
+ (WebCore::FetchBodyConsumer::setMaximumIntervalForUserGestureForwarding):
+ (WebCore::FetchBodyConsumer::FetchBodyConsumer):
+ Propagates media only user gestures through FetchResponse. UserGestureIndicator is only set in the async promise resolving path.
+
+ * WebCore.xcodeproj/project.pbxproj:
+ * bindings/js/JSDOMWindowBase.cpp:
+ (WebCore::JSDOMWindowBase::queueMicrotaskToEventLoop):
+ Propagates media only user gestures that was propagated through Fetch to the related promise executors.
+
+ * dom/UserGestureIndicator.cpp:
+ (WebCore::UserGestureIndicator::UserGestureIndicator):
+ (WebCore::UserGestureIndicator::~UserGestureIndicator):
+ * dom/UserGestureIndicator.h:
+ (WebCore::UserGestureToken::setIsPropagatedFromFetch):
+ (WebCore::UserGestureToken::resetIsPropagatedFromFetch):
+ (WebCore::UserGestureToken::isPropagatedFromFetch const):
+ Adds a flag to indicate the propagation source of a user gesture token. And makes pipelines from testing.
+
+ * page/DOMTimer.cpp:
+ (WebCore::DOMTimer::fired):
+ Gathers some constants.
+
+ * testing/Internals.cpp:
+ (WebCore::Internals::setFetchMaximumIntervalForUserGestureForwarding):
+ * testing/Internals.h:
+ * testing/Internals.idl:
+ Crafts a way to pass the maximum interval from layout tests.
+
+ * xml/XMLHttpRequest.cpp:
+ (WebCore::XMLHttpRequest::XMLHttpRequest):
+ Gathers some constants.
+
2020-07-24 Kenneth Russell <[email protected]>
[WebGL2] Framebuffer and renderbuffer updates
Modified: trunk/Source/WebCore/Modules/fetch/DOMWindowFetch.cpp (264852 => 264853)
--- trunk/Source/WebCore/Modules/fetch/DOMWindowFetch.cpp 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/Source/WebCore/Modules/fetch/DOMWindowFetch.cpp 2020-07-24 20:48:42 UTC (rev 264853)
@@ -35,6 +35,7 @@
#include "FetchResponse.h"
#include "JSDOMPromiseDeferred.h"
#include "JSFetchResponse.h"
+#include "UserGestureIndicator.h"
namespace WebCore {
@@ -56,7 +57,13 @@
return;
}
- FetchResponse::fetch(*document, request.releaseReturnValue().get(), [promise = WTFMove(promise)](ExceptionOr<FetchResponse&>&& result) mutable {
+ FetchResponse::fetch(*document, request.releaseReturnValue(), [promise = WTFMove(promise), userGestureToken = UserGestureIndicator::currentUserGesture()](ExceptionOr<FetchResponse&>&& result) mutable {
+ if (!userGestureToken || userGestureToken->hasExpired(UserGestureToken::maximumIntervalForUserGestureForwardingForFetch()) || !userGestureToken->processingUserGesture()) {
+ promise.settle(WTFMove(result));
+ return;
+ }
+
+ UserGestureIndicator gestureIndicator(userGestureToken, UserGestureToken::GestureScope::MediaOnly, UserGestureToken::IsPropagatedFromFetch::Yes);
promise.settle(WTFMove(result));
});
}
Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp (264852 => 264853)
--- trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp 2020-07-24 20:48:42 UTC (rev 264853)
@@ -68,7 +68,7 @@
void FetchBodyConsumer::clean()
{
m_buffer = nullptr;
- m_consumePromise = nullptr;
+ resetConsumePromise();
if (m_sink) {
m_sink->clearCallback();
return;
@@ -107,7 +107,7 @@
}
if (m_isLoading) {
- m_consumePromise = WTFMove(promise);
+ setConsumePromise(WTFMove(promise));
return;
}
@@ -189,9 +189,16 @@
void FetchBodyConsumer::setConsumePromise(Ref<DeferredPromise>&& promise)
{
ASSERT(!m_consumePromise);
+ m_userGestureToken = UserGestureIndicator::currentUserGesture();
m_consumePromise = WTFMove(promise);
}
+void FetchBodyConsumer::resetConsumePromise()
+{
+ m_consumePromise = nullptr;
+ m_userGestureToken = nullptr;
+}
+
void FetchBodyConsumer::setSource(Ref<FetchBodySource>&& source)
{
m_source = WTFMove(source);
@@ -206,7 +213,7 @@
m_isLoading = false;
if (m_consumePromise) {
m_consumePromise->reject(exception);
- m_consumePromise = nullptr;
+ resetConsumePromise();
}
if (m_source) {
m_source->error(exception);
@@ -218,8 +225,14 @@
{
m_isLoading = false;
- if (m_consumePromise)
- resolve(m_consumePromise.releaseNonNull(), nullptr);
+ if (m_consumePromise) {
+ if (!m_userGestureToken || m_userGestureToken->hasExpired(UserGestureToken::maximumIntervalForUserGestureForwardingForFetch()) || !m_userGestureToken->processingUserGesture())
+ resolve(m_consumePromise.releaseNonNull(), nullptr);
+ else {
+ UserGestureIndicator gestureIndicator(m_userGestureToken, UserGestureToken::GestureScope::MediaOnly, UserGestureToken::IsPropagatedFromFetch::Yes);
+ resolve(m_consumePromise.releaseNonNull(), nullptr);
+ }
+ }
if (m_source) {
m_source->close();
m_source = nullptr;
Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h (264852 => 264853)
--- trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h 2020-07-24 20:48:42 UTC (rev 264853)
@@ -32,6 +32,7 @@
#include "JSDOMPromiseDeferred.h"
#include "ReadableStreamSink.h"
#include "SharedBuffer.h"
+#include "UserGestureIndicator.h"
namespace WebCore {
@@ -43,7 +44,7 @@
public:
enum class Type { None, ArrayBuffer, Blob, JSON, Text };
- FetchBodyConsumer(Type type) : m_type(type) { }
+ explicit FetchBodyConsumer(Type type) : m_type(type) { }
void append(const char* data, unsigned);
void append(const unsigned char* data, unsigned);
@@ -75,6 +76,7 @@
private:
Ref<Blob> takeAsBlob();
+ void resetConsumePromise();
Type m_type;
String m_contentType;
@@ -83,6 +85,7 @@
RefPtr<ReadableStreamToSharedBufferSink> m_sink;
RefPtr<FetchBodySource> m_source;
bool m_isLoading { false };
+ RefPtr<UserGestureToken> m_userGestureToken;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/Modules/fetch/FetchRequest.cpp (264852 => 264853)
--- trunk/Source/WebCore/Modules/fetch/FetchRequest.cpp 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/Source/WebCore/Modules/fetch/FetchRequest.cpp 2020-07-24 20:48:42 UTC (rev 264853)
@@ -334,4 +334,3 @@
}
} // namespace WebCore
-
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (264852 => 264853)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2020-07-24 20:48:42 UTC (rev 264853)
@@ -1762,6 +1762,7 @@
5704405A1E53936200356601 /* JSAesCbcCfbParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 570440591E53936200356601 /* JSAesCbcCfbParams.h */; };
5706A6961DDE5C9500A03B14 /* CryptoAlgorithmRsaOaepParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 5706A6951DDE5C9500A03B14 /* CryptoAlgorithmRsaOaepParams.h */; };
5706A6981DDE5E4600A03B14 /* JSRsaOaepParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 5706A6971DDE5E4600A03B14 /* JSRsaOaepParams.h */; };
+ 57093D1324C97C8F0086C52D /* FetchResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 413015D61C7B570400091C6E /* FetchResponse.h */; settings = {ATTRIBUTES = (Private, ); }; };
571252691E524EB1008FF369 /* CryptoAlgorithmAES_CFB.h in Headers */ = {isa = PBXBuildFile; fileRef = 571252681E524EB1008FF369 /* CryptoAlgorithmAES_CFB.h */; };
57152B5A21CB3E88000C37CA /* ApduCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 57152B5821CB2E3B000C37CA /* ApduCommand.h */; settings = {ATTRIBUTES = (Private, ); }; };
57152B5C21CC1902000C37CA /* ApduResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 57152B5621CB2E3A000C37CA /* ApduResponse.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -1812,6 +1813,7 @@
5750A97E1E6A13EF00705C4A /* CryptoAlgorithmEcKeyParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 5750A97D1E6A13EF00705C4A /* CryptoAlgorithmEcKeyParams.h */; };
5750A9821E6A150800705C4A /* JSEcKeyParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 5750A9801E6A150800705C4A /* JSEcKeyParams.h */; };
5750A9871E6A216800705C4A /* CryptoAlgorithmECDH.h in Headers */ = {isa = PBXBuildFile; fileRef = 5750A9851E6A216800705C4A /* CryptoAlgorithmECDH.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 57533E0824C6C598003EF2D3 /* FetchRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 41F54F881C50C4F600338488 /* FetchRequest.h */; };
5754719F1ECE628300DD63B2 /* JSRsaPssParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 575471991ECE5D2A00DD63B2 /* JSRsaPssParams.h */; };
57585961239F124D00C74572 /* JSAuthenticationExtensionsClientOutputs.h in Headers */ = {isa = PBXBuildFile; fileRef = 5758595E239F117300C74572 /* JSAuthenticationExtensionsClientOutputs.h */; };
5758596C239F321C00C74572 /* AuthenticationExtensionsClientOutputs.h in Headers */ = {isa = PBXBuildFile; fileRef = 57585965239F14CC00C74572 /* AuthenticationExtensionsClientOutputs.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -30808,11 +30810,13 @@
517A53581F5889E800DCDC0A /* FetchLoaderClient.h in Headers */,
41AD753A1CEF6BD100A31486 /* FetchOptions.h in Headers */,
7CE1914D1F2A9AFB00272F78 /* FetchReferrerPolicy.h in Headers */,
+ 57533E0824C6C598003EF2D3 /* FetchRequest.h in Headers */,
7CE1915A1F2A9B3400272F78 /* FetchRequestCache.h in Headers */,
7CE191551F2A9B1D00272F78 /* FetchRequestCredentials.h in Headers */,
7CE1914A1F2A98B900272F78 /* FetchRequestInit.h in Headers */,
7CE191511F2A9B0A00272F78 /* FetchRequestMode.h in Headers */,
7CE191601F2A9B4F00272F78 /* FetchRequestRedirect.h in Headers */,
+ 57093D1324C97C8F0086C52D /* FetchResponse.h in Headers */,
84730D8B1248F0B300D3A9C9 /* FETile.h in Headers */,
84730D8D1248F0B300D3A9C9 /* FETurbulence.h in Headers */,
FD31609512B026F700C1A359 /* FFTConvolver.h in Headers */,
Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp (264852 => 264853)
--- trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp 2020-07-24 20:48:42 UTC (rev 264853)
@@ -215,7 +215,17 @@
auto callback = JSMicrotaskCallback::create(thisObject, WTFMove(task));
auto& eventLoop = thisObject.scriptExecutionContext()->eventLoop();
- eventLoop.queueMicrotask([callback = WTFMove(callback)]() mutable {
+ // Propagating media only user gesture for Fetch API's promise chain.
+ auto userGestureToken = UserGestureIndicator::currentUserGesture();
+ if (userGestureToken && !userGestureToken->isPropagatedFromFetch())
+ userGestureToken = nullptr;
+ eventLoop.queueMicrotask([callback = WTFMove(callback), userGestureToken = WTFMove(userGestureToken)]() mutable {
+ if (!userGestureToken) {
+ callback->call();
+ return;
+ }
+
+ UserGestureIndicator gestureIndicator(userGestureToken, UserGestureToken::GestureScope::MediaOnly, UserGestureToken::IsPropagatedFromFetch::Yes);
callback->call();
});
}
Modified: trunk/Source/WebCore/dom/UserGestureIndicator.cpp (264852 => 264853)
--- trunk/Source/WebCore/dom/UserGestureIndicator.cpp 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/Source/WebCore/dom/UserGestureIndicator.cpp 2020-07-24 20:48:42 UTC (rev 264853)
@@ -49,6 +49,17 @@
observer(*this);
}
+static Seconds maxIntervalForUserGestureForwardingForFetch { 10 };
+const Seconds& UserGestureToken::maximumIntervalForUserGestureForwardingForFetch()
+{
+ return maxIntervalForUserGestureForwardingForFetch;
+}
+
+void UserGestureToken::setMaximumIntervalForUserGestureForwardingForFetchForTesting(Seconds value)
+{
+ maxIntervalForUserGestureForwardingForFetch = WTFMove(value);
+}
+
UserGestureIndicator::UserGestureIndicator(Optional<ProcessingUserGestureState> state, Document* document, UserGestureType gestureType, ProcessInteractionStyle processInteractionStyle)
: m_previousToken { currentToken() }
{
@@ -74,7 +85,7 @@
}
}
-UserGestureIndicator::UserGestureIndicator(RefPtr<UserGestureToken> token, UserGestureToken::GestureScope scope)
+UserGestureIndicator::UserGestureIndicator(RefPtr<UserGestureToken> token, UserGestureToken::GestureScope scope, UserGestureToken::IsPropagatedFromFetch isPropagatedFromFetch)
{
// Silently ignore UserGestureIndicators on non main threads.
if (!isMainThread())
@@ -85,6 +96,7 @@
if (token) {
token->setScope(scope);
+ token->setIsPropagatedFromFetch(isPropagatedFromFetch);
currentToken() = token;
}
}
@@ -97,6 +109,7 @@
if (auto token = currentToken()) {
token->resetDOMPasteAccess();
token->resetScope();
+ token->resetIsPropagatedFromFetch();
}
currentToken() = m_previousToken;
Modified: trunk/Source/WebCore/dom/UserGestureIndicator.h (264852 => 264853)
--- trunk/Source/WebCore/dom/UserGestureIndicator.h 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/Source/WebCore/dom/UserGestureIndicator.h 2020-07-24 20:48:42 UTC (rev 264853)
@@ -47,6 +47,10 @@
class UserGestureToken : public RefCounted<UserGestureToken>, public CanMakeWeakPtr<UserGestureToken> {
public:
+ static constexpr Seconds maximumIntervalForUserGestureForwarding { 1_s }; // One second matches Gecko.
+ static const Seconds& maximumIntervalForUserGestureForwardingForFetch();
+ WEBCORE_EXPORT static void setMaximumIntervalForUserGestureForwardingForFetchForTesting(Seconds);
+
static Ref<UserGestureToken> create(ProcessingUserGestureState state, UserGestureType gestureType)
{
return adoptRef(*new UserGestureToken(state, gestureType));
@@ -84,6 +88,12 @@
void setScope(GestureScope scope) { m_scope = scope; }
void resetScope() { m_scope = GestureScope::All; }
+ // Expand the following methods if more propagation sources are added later.
+ enum class IsPropagatedFromFetch { Yes, No };
+ void setIsPropagatedFromFetch(IsPropagatedFromFetch is) { m_isPropagatedFromFetch = is; }
+ void resetIsPropagatedFromFetch() { m_isPropagatedFromFetch = IsPropagatedFromFetch::No; }
+ bool isPropagatedFromFetch() const { return m_isPropagatedFromFetch == IsPropagatedFromFetch::Yes; }
+
bool hasExpired(Seconds expirationInterval) const
{
return m_startTime + expirationInterval < MonotonicTime::now();
@@ -104,6 +114,7 @@
DOMPasteAccessPolicy m_domPasteAccessPolicy { DOMPasteAccessPolicy::NotRequestedYet };
GestureScope m_scope { GestureScope::All };
MonotonicTime m_startTime { MonotonicTime::now() };
+ IsPropagatedFromFetch m_isPropagatedFromFetch { IsPropagatedFromFetch::No };
};
class UserGestureIndicator {
@@ -118,7 +129,7 @@
// If a document is provided, its last known user gesture timestamp is updated.
enum class ProcessInteractionStyle { Immediate, Delayed };
WEBCORE_EXPORT explicit UserGestureIndicator(Optional<ProcessingUserGestureState>, Document* = nullptr, UserGestureType = UserGestureType::Other, ProcessInteractionStyle = ProcessInteractionStyle::Immediate);
- WEBCORE_EXPORT explicit UserGestureIndicator(RefPtr<UserGestureToken>, UserGestureToken::GestureScope = UserGestureToken::GestureScope::All);
+ WEBCORE_EXPORT explicit UserGestureIndicator(RefPtr<UserGestureToken>, UserGestureToken::GestureScope = UserGestureToken::GestureScope::All, UserGestureToken::IsPropagatedFromFetch = UserGestureToken::IsPropagatedFromFetch::No);
WEBCORE_EXPORT ~UserGestureIndicator();
private:
Modified: trunk/Source/WebCore/page/DOMTimer.cpp (264852 => 264853)
--- trunk/Source/WebCore/page/DOMTimer.cpp 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/Source/WebCore/page/DOMTimer.cpp 2020-07-24 20:48:42 UTC (rev 264853)
@@ -48,7 +48,6 @@
namespace WebCore {
-static const Seconds maxIntervalForUserGestureForwarding { 1_s }; // One second matches Gecko.
static const Seconds minIntervalForNonUserObservableChangeTimers { 1_s }; // Empirically determined to maximize battery life.
static const int maxTimerNestingLevel = 5;
@@ -301,7 +300,7 @@
DOMTimerFireState fireState(context, std::min(m_nestingLevel + 1, maxTimerNestingLevel));
- if (m_userGestureTokenToForward && m_userGestureTokenToForward->hasExpired(maxIntervalForUserGestureForwarding))
+ if (m_userGestureTokenToForward && m_userGestureTokenToForward->hasExpired(UserGestureToken::maximumIntervalForUserGestureForwarding))
m_userGestureTokenToForward = nullptr;
ASSERT(!isSuspended());
Modified: trunk/Source/WebCore/testing/Internals.cpp (264852 => 264853)
--- trunk/Source/WebCore/testing/Internals.cpp 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/Source/WebCore/testing/Internals.cpp 2020-07-24 20:48:42 UTC (rev 264853)
@@ -5672,9 +5672,9 @@
page->diagnosticLoggingClient().logDiagnosticMessageWithValueDictionary("testMessage"_s, "testDescription"_s, dictionary, ShouldSample::No);
}
-void Internals::setXHRMaximumIntervalForUserGestureForwarding(XMLHttpRequest& request, double interval)
+void Internals::setMaximumIntervalForUserGestureForwardingForFetch(double interval)
{
- request.setMaximumIntervalForUserGestureForwarding(interval);
+ UserGestureToken::setMaximumIntervalForUserGestureForwardingForFetchForTesting(Seconds(interval));
}
void Internals::setTransientActivationDuration(double seconds)
Modified: trunk/Source/WebCore/testing/Internals.h (264852 => 264853)
--- trunk/Source/WebCore/testing/Internals.h 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/Source/WebCore/testing/Internals.h 2020-07-24 20:48:42 UTC (rev 264853)
@@ -961,7 +961,7 @@
void testDictionaryLogging();
- void setXHRMaximumIntervalForUserGestureForwarding(XMLHttpRequest&, double);
+ void setMaximumIntervalForUserGestureForwardingForFetch(double);
void setTransientActivationDuration(double seconds);
void setIsPlayingToAutomotiveHeadUnit(bool);
Modified: trunk/Source/WebCore/testing/Internals.idl (264852 => 264853)
--- trunk/Source/WebCore/testing/Internals.idl 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/Source/WebCore/testing/Internals.idl 2020-07-24 20:48:42 UTC (rev 264853)
@@ -907,7 +907,7 @@
void testDictionaryLogging();
- void setXHRMaximumIntervalForUserGestureForwarding(XMLHttpRequest xhr, double interval);
+ void setMaximumIntervalForUserGestureForwardingForFetch(double interval);
void setTransientActivationDuration(double seconds);
void setIsPlayingToAutomotiveHeadUnit(boolean value);
Modified: trunk/Source/WebCore/xml/XMLHttpRequest.cpp (264852 => 264853)
--- trunk/Source/WebCore/xml/XMLHttpRequest.cpp 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/Source/WebCore/xml/XMLHttpRequest.cpp 2020-07-24 20:48:42 UTC (rev 264853)
@@ -67,8 +67,6 @@
namespace WebCore {
-static const Seconds maximumIntervalForUserGestureForwarding { 10_s };
-
WTF_MAKE_ISO_ALLOCATED_IMPL(XMLHttpRequest);
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, xmlHttpRequestCounter, ("XMLHttpRequest"));
@@ -121,7 +119,6 @@
, m_responseType(static_cast<unsigned>(ResponseType::EmptyString))
, m_progressEventThrottle(*this)
, m_timeoutTimer(*this, &XMLHttpRequest::didReachTimeout)
- , m_maximumIntervalForUserGestureForwarding(maximumIntervalForUserGestureForwarding)
{
#ifndef NDEBUG
xmlHttpRequestCounter.increment();
@@ -1081,7 +1078,7 @@
{
RELEASE_ASSERT(!scriptExecutionContext()->activeDOMObjectsAreSuspended());
- if (m_userGestureToken && m_userGestureToken->hasExpired(m_maximumIntervalForUserGestureForwarding))
+ if (m_userGestureToken && m_userGestureToken->hasExpired(UserGestureToken::maximumIntervalForUserGestureForwardingForFetch()))
m_userGestureToken = nullptr;
if (readyState() != DONE || !m_userGestureToken || !m_userGestureToken->processingUserGesture()) {
@@ -1156,11 +1153,6 @@
ActiveDOMObject::contextDestroyed();
}
-void XMLHttpRequest::setMaximumIntervalForUserGestureForwarding(double interval)
-{
- m_maximumIntervalForUserGestureForwarding = Seconds(interval);
-}
-
void XMLHttpRequest::eventListenersDidChange()
{
m_hasRelevantEventListener = hasEventListeners(eventNames().abortEvent)
Modified: trunk/Source/WebCore/xml/XMLHttpRequest.h (264852 => 264853)
--- trunk/Source/WebCore/xml/XMLHttpRequest.h 2020-07-24 19:59:56 UTC (rev 264852)
+++ trunk/Source/WebCore/xml/XMLHttpRequest.h 2020-07-24 20:48:42 UTC (rev 264853)
@@ -128,8 +128,6 @@
size_t memoryCost() const;
- WEBCORE_EXPORT void setMaximumIntervalForUserGestureForwarding(double);
-
using EventTarget::dispatchEvent;
void dispatchEvent(Event&) override;
@@ -247,7 +245,6 @@
Optional<ExceptionCode> m_exceptionCode;
RefPtr<UserGestureToken> m_userGestureToken;
- Seconds m_maximumIntervalForUserGestureForwarding;
bool m_hasRelevantEventListener { false };
};