Diff
Modified: trunk/LayoutTests/ChangeLog (244822 => 244823)
--- trunk/LayoutTests/ChangeLog 2019-05-01 15:55:10 UTC (rev 244822)
+++ trunk/LayoutTests/ChangeLog 2019-05-01 15:56:34 UTC (rev 244823)
@@ -1,3 +1,20 @@
+2019-05-01 Eric Carlson <eric.carl...@apple.com>
+
+ XMLHttpRequest should propagate user gestures for media playback
+ https://bugs.webkit.org/show_bug.cgi?id=197428
+ <rdar://problem/46677392>
+
+ Reviewed by Jer Noble.
+
+ * fast/events/popup-blocking-timers5-expected.txt:
+ * fast/events/popup-blocking-timers5.html: Decrease the timer interval from 1000 to 900
+ because the user gesture is invalidated based on wall clock time.
+ * fast/events/popup-blocking-timers6-expected.txt:
+ * fast/events/popup-blocking-timers6.html: Increase the timer interval from 1001 to 1100
+ because the user gesture is invalidated based on wall clock time.
+ * http/tests/media/user-gesture-preserved-across-xmlhttprequest-expected.txt: Added.
+ * http/tests/media/user-gesture-preserved-across-xmlhttprequest.html: Added.
+
2019-04-29 Darin Adler <da...@apple.com>
WebKit has too much of its own UTF-8 code and should rely more on ICU's UTF-8 support
Modified: trunk/LayoutTests/fast/events/popup-blocking-timers5-expected.txt (244822 => 244823)
--- trunk/LayoutTests/fast/events/popup-blocking-timers5-expected.txt 2019-05-01 15:55:10 UTC (rev 244822)
+++ trunk/LayoutTests/fast/events/popup-blocking-timers5-expected.txt 2019-05-01 15:56:34 UTC (rev 244823)
@@ -1,4 +1,4 @@
Click Here
-Test calling window.open() with a 1000 ms delay. A popup should be allowed.
+Test calling window.open() with a 900 ms delay. A popup should be allowed.
PASS newWindow is non-null.
Modified: trunk/LayoutTests/fast/events/popup-blocking-timers5.html (244822 => 244823)
--- trunk/LayoutTests/fast/events/popup-blocking-timers5.html 2019-05-01 15:55:10 UTC (rev 244822)
+++ trunk/LayoutTests/fast/events/popup-blocking-timers5.html 2019-05-01 15:56:34 UTC (rev 244823)
@@ -15,14 +15,14 @@
setTimeout(function() {
newWindow = window.open("about:blank");
self.focus();
- debug("Test calling window.open() with a 1000 ms delay. A popup should be allowed.")
+ debug("Test calling window.open() with a 900 ms delay. A popup should be allowed.")
shouldBeNonNull("newWindow");
if (window.testRunner)
testRunner.notifyDone();
- }, 1000);
+ }, 900);
if (window.eventSender)
- eventSender.leapForward(1000);
+ eventSender.leapForward(900);
}
function clickButton() {
Modified: trunk/LayoutTests/fast/events/popup-blocking-timers6-expected.txt (244822 => 244823)
--- trunk/LayoutTests/fast/events/popup-blocking-timers6-expected.txt 2019-05-01 15:55:10 UTC (rev 244822)
+++ trunk/LayoutTests/fast/events/popup-blocking-timers6-expected.txt 2019-05-01 15:56:34 UTC (rev 244823)
@@ -1,4 +1,4 @@
Click Here
-Test calling window.open() with a 1001 ms delay. A popup should not be allowed.
+Test calling window.open() with a 1100 ms delay. A popup should not be allowed.
PASS newWindow is null
Modified: trunk/LayoutTests/fast/events/popup-blocking-timers6.html (244822 => 244823)
--- trunk/LayoutTests/fast/events/popup-blocking-timers6.html 2019-05-01 15:55:10 UTC (rev 244822)
+++ trunk/LayoutTests/fast/events/popup-blocking-timers6.html 2019-05-01 15:56:34 UTC (rev 244823)
@@ -15,14 +15,14 @@
setTimeout(function() {
newWindow = window.open("about:blank");
self.focus();
- debug("Test calling window.open() with a 1001 ms delay. A popup should not be allowed.")
+ debug("Test calling window.open() with a 1100 ms delay. A popup should not be allowed.")
shouldBeNull("newWindow");
if (window.testRunner)
testRunner.notifyDone();
- }, 1001);
+ }, 1100);
if (window.eventSender)
- eventSender.leapForward(1001);
+ eventSender.leapForward(1100);
}
function clickButton() {
Added: trunk/LayoutTests/http/tests/media/user-gesture-preserved-across-xmlhttprequest-expected.txt (0 => 244823)
--- trunk/LayoutTests/http/tests/media/user-gesture-preserved-across-xmlhttprequest-expected.txt (rev 0)
+++ trunk/LayoutTests/http/tests/media/user-gesture-preserved-across-xmlhttprequest-expected.txt 2019-05-01 15:56:34 UTC (rev 244823)
@@ -0,0 +1,56 @@
+Test that a user gesture is preserved across XHR and setTimeout.
+
+
+Run!
+
+** gesture -> XHR -> timeout -> XHR -> window.open: should fail because XHR only propagates user gesture for media
+sending XHR, delay = 100
+EVENT(load): readyState = 4
+setting timeout, delay = 100
+sending XHR, delay = 100
+EVENT(load): readyState = 4
+EXPECTED (window.open("about:blank") == 'null') OK
+
+** gesture -> timeout -> XHR -> timeout -> window.open: should succeed
+setting timeout, delay = 100
+sending XHR, delay = 100
+EVENT(load): readyState = 4
+setting timeout, delay = 100
+EXPECTED (window.open("about:blank") != 'null') OK
+
+** gesture -> timeout -> XHR -> timeout -> video playback: should succeed
+EVENT(canplaythrough)
+setting timeout, delay = 100
+sending XHR, delay = 100
+EVENT(load): readyState = 4
+setting timeout, delay = 100
+RUN(shouldResolve(mediaElement.play()).then(testComplete, testComplete))
+Promise resolved OK
+
+** gesture -> XHR -> timeout -> XHR -> video playback: should succeed
+EVENT(canplaythrough)
+sending XHR, delay = 100
+EVENT(load): readyState = 4
+setting timeout, delay = 100
+sending XHR, delay = 100
+EVENT(load): readyState = 4
+RUN(shouldResolve(mediaElement.play()).then(testComplete, testComplete))
+Promise resolved OK
+
+** NO gesture -> XHR -> timeout -> video playback: should fail
+EVENT(canplaythrough)
+sending XHR, delay = 100
+EVENT(load): readyState = 4
+setting timeout, delay = 100
+RUN(shouldReject(mediaElement.play()).then(testComplete, testComplete))
+Promise rejected correctly OK
+
+** gesture -> "long" XHR -> video playback: should fail
+EVENT(canplaythrough)
+sending XHR, delay = 300
+EVENT(load): readyState = 4
+RUN(shouldReject(mediaElement.play()).then(testComplete, testComplete))
+Promise rejected correctly OK
+
+END OF TEST
+
Added: trunk/LayoutTests/http/tests/media/user-gesture-preserved-across-xmlhttprequest.html (0 => 244823)
--- trunk/LayoutTests/http/tests/media/user-gesture-preserved-across-xmlhttprequest.html (rev 0)
+++ trunk/LayoutTests/http/tests/media/user-gesture-preserved-across-xmlhttprequest.html 2019-05-01 15:56:34 UTC (rev 244823)
@@ -0,0 +1,166 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset='utf-8'>
+ <title>user-gesture-preserved-across-xmlhttprequest</title>
+ <script src=''></script>
+ <script src=''></script>
+
+ <script>
+ let autoRun = true;
+
+ if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+ testRunner.setCanOpenWindows(true);
+ }
+
+ function doXHR(delay, timeout, completionHandler)
+ {
+ var xhr = new XMLHttpRequest();
+ if (window.internals)
+ window.internals.setXHRMaximumIntervalForUserGestureForwarding(xhr, timeout);
+
+ xhr.open('GET', `/xmlhttprequest/resources/download-with-delay.php?iteration=1&delay=${delay}`, true);
+
+ xhr._onload_ = (evt) => {
+ consoleWrite(`EVENT(load): readyState = ${xhr.readyState}`);
+ if (xhr.readyState === 4) {
+ if (xhr.status === 200) {
+ completionHandler();
+ } else {
+ logResult(Failed, `xhr.onload, status = ${xhr.statusText}`);
+ }
+ }
+ };
+
+ xhr._onerror_ = (err) => {
+ logResult(Failed, `xhr.onerror, status = ${xhr.statusText}`);
+ };
+
+ xhr.send(null);
+ }
+
+ function testComplete()
+ {
+ if (autoRun)
+ nextTest();
+ }
+
+ function runTest(test)
+ {
+ if (!test.sequence.length) {
+ switch (test.action) {
+ case 'play':
+ if (test.success)
+ run("shouldResolve(mediaElement.play()).then(testComplete, testComplete)");
+ else
+ run("shouldReject(mediaElement.play()).then(testComplete, testComplete)");
+ break;
+
+ case 'popup':
+ if (window.internals)
+ internals.settings.setJavaScriptCanOpenWindowsAutomatically(false);
+ testExpected('window.open("about:blank")', null, test.success ? '!=' : '==');
+ testComplete();
+ break;
+ }
+ return;
+ }
+
+ let command = test.sequence.shift().trim().split(' ');
+ let delay = command[0];
+ let method = command[1].toLowerCase();
+
+ switch (method) {
+ case 'xhr':
+ consoleWrite(`sending XHR, delay = ${delay}`);
+ doXHR(delay, test.timeout || 0.6, () => runTest(test));
+ break;
+ case 'timeout':
+ consoleWrite(`setting timeout, delay = ${delay}`);
+ setTimeout(() => { runTest(test); }, delay);
+ break;
+ }
+
+ }
+
+ let tests = [
+ { title : 'gesture -> XHR -> timeout -> XHR -> window.open: should fail because XHR only propagates user gesture for media',
+ action : 'popup', withkey : true, success : false, sequence : ['100 XHR', '100 timeout', '100 xhr'] },
+
+ { title : 'gesture -> timeout -> XHR -> timeout -> window.open: should succeed',
+ action : 'popup', withkey : true, success : true, sequence : ['100 timeout', '100 xhr', '100 timeout'] },
+
+ { title : 'gesture -> timeout -> XHR -> timeout -> video playback: should succeed',
+ action : 'play', withkey : true, success : true, sequence : ['100 timeout', '100 XHR', '100 timeout'] },
+
+ { title : 'gesture -> XHR -> timeout -> XHR -> video playback: should succeed',
+ action : 'play', withkey : true, success : true, sequence : ['100 XHR', '100 timeout', '100 xhr'] },
+
+ { title : 'NO gesture -> XHR -> timeout -> video playback: should fail',
+ 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'] },
+ ];
+
+ function nextTest()
+ {
+ if (!tests.length) {
+ consoleWrite('');
+ endTest()
+ return;
+ }
+
+ let test = tests.shift();
+ let action = "" => { runTest(test) };
+ consoleWrite(`<br>** ${test.title}`);
+ switch (test.action) {
+ case 'play':
+ let container = document.getElementById('parent');
+ if (container.firstChild)
+ container.removeChild(container.firstChild);
+
+ mediaElement = document.createElement('video');
+ if (window.internals)
+ internals.setMediaElementRestrictions(mediaElement, 'RequireUserGestureForAudioRateChange');
+
+ mediaElement.src = "" + findMediaFile("video", "test");
+ mediaElement.controls = 1;
+ container.appendChild(mediaElement);
+ waitForEvent('canplaythrough', event => {
+ if (test.withkey)
+ runWithKeyDown(action);
+ else
+ action();
+ });
+
+ break;
+
+ case 'popup':
+ if (test.withkey)
+ runWithKeyDown(action);
+ else
+ action();
+ break;
+ }
+ }
+
+ function start()
+ {
+ if (autoRun)
+ nextTest();
+ }
+
+ </script>
+</head>
+
+<body _onload_="start()">
+ <p>Test that a user gesture is preserved across XHR and setTimeout.</p>
+ <div id='parent'></div>
+ <button _onclick_="nextTest()">Run!</button><br>
+ <pre id='consoleLog'></pre>
+</body>
+</html>
+
Modified: trunk/Source/WebCore/ChangeLog (244822 => 244823)
--- trunk/Source/WebCore/ChangeLog 2019-05-01 15:55:10 UTC (rev 244822)
+++ trunk/Source/WebCore/ChangeLog 2019-05-01 15:56:34 UTC (rev 244823)
@@ -1,3 +1,50 @@
+2019-05-01 Eric Carlson <eric.carl...@apple.com>
+
+ XMLHttpRequest should propagate user gestures for media playback
+ https://bugs.webkit.org/show_bug.cgi?id=197428
+ <rdar://problem/46677392>
+
+ Reviewed by Jer Noble.
+
+ A user gesture the would allow media state change in effect when XMLHttpRequest.send is
+ called should be active when the event handlers fire after the transaction completes successfully.
+
+ Test: http/tests/media/user-gesture-preserved-across-xmlhttprequest.html
+
+ * dom/UserGestureIndicator.cpp:
+ (WebCore::UserGestureIndicator::UserGestureIndicator): Add a 'scope' parameter to potentially
+ limit the scope of the gesture to just media.
+ (WebCore::UserGestureIndicator::~UserGestureIndicator): Clear the scope.
+ * dom/UserGestureIndicator.h:
+ (WebCore::UserGestureToken::processingUserGesture const):
+ (WebCore::UserGestureToken::setScope):
+ (WebCore::UserGestureToken::resetScope):
+ (WebCore::UserGestureToken::hasExpired const):
+
+ * page/DOMTimer.cpp:
+ (WebCore::DOMTimerFireState::DOMTimerFireState): Don't need to store the nested timer interval,
+ UserGestureIndicator knows when it started.
+ (WebCore::DOMTimer::DOMTimer): Ditto.
+ (WebCore::DOMTimer::fired): Ditto.
+ (WebCore::DOMTimerFireState::nestedTimerInterval const): Deleted.
+ (WebCore::shouldForwardUserGesture): Deleted.
+ (WebCore::userGestureTokenToForward): Deleted.
+ (WebCore::currentNestedTimerInterval): Deleted.
+ * page/DOMTimer.h:
+
+ * testing/Internals.cpp:
+ (WebCore::Internals::setXHRMaximumIntervalForUserGestureForwarding): Override the maximum
+ user gesture interval for testing.
+ * testing/Internals.h:
+ * testing/Internals.idl:
+
+ * xml/XMLHttpRequest.cpp:
+ (WebCore::XMLHttpRequest::XMLHttpRequest):
+ (WebCore::XMLHttpRequest::send): Stash the user gesture token.
+ (WebCore::XMLHttpRequest::dispatchEvent): Clear user gesture token if it has expired. If still
+ valid, activate it.
+ * xml/XMLHttpRequest.h:
+
2019-04-29 Darin Adler <da...@apple.com>
WebKit has too much of its own UTF-8 code and should rely more on ICU's UTF-8 support
Modified: trunk/Source/WebCore/dom/UserGestureIndicator.cpp (244822 => 244823)
--- trunk/Source/WebCore/dom/UserGestureIndicator.cpp 2019-05-01 15:55:10 UTC (rev 244822)
+++ trunk/Source/WebCore/dom/UserGestureIndicator.cpp 2019-05-01 15:56:34 UTC (rev 244823)
@@ -70,7 +70,7 @@
}
}
-UserGestureIndicator::UserGestureIndicator(RefPtr<UserGestureToken> token)
+UserGestureIndicator::UserGestureIndicator(RefPtr<UserGestureToken> token, UserGestureToken::GestureScope scope)
{
// Silently ignore UserGestureIndicators on non main threads.
if (!isMainThread())
@@ -79,8 +79,10 @@
// It is only safe to use currentToken() on the main thread.
m_previousToken = currentToken();
- if (token)
+ if (token) {
+ token->setScope(scope);
currentToken() = token;
+ }
}
UserGestureIndicator::~UserGestureIndicator()
@@ -88,8 +90,10 @@
if (!isMainThread())
return;
- if (auto token = currentToken())
+ if (auto token = currentToken()) {
token->resetDOMPasteAccess();
+ token->resetScope();
+ }
currentToken() = m_previousToken;
}
Modified: trunk/Source/WebCore/dom/UserGestureIndicator.h (244822 => 244823)
--- trunk/Source/WebCore/dom/UserGestureIndicator.h 2019-05-01 15:55:10 UTC (rev 244822)
+++ trunk/Source/WebCore/dom/UserGestureIndicator.h 2019-05-01 15:56:34 UTC (rev 244823)
@@ -27,6 +27,7 @@
#include "DOMPasteAccess.h"
#include <wtf/Function.h>
+#include <wtf/MonotonicTime.h>
#include <wtf/Noncopyable.h>
#include <wtf/RefCounted.h>
#include <wtf/Vector.h>
@@ -53,7 +54,7 @@
WEBCORE_EXPORT ~UserGestureToken();
ProcessingUserGestureState state() const { return m_state; }
- bool processingUserGesture() const { return m_state == ProcessingUserGesture; }
+ bool processingUserGesture() const { return m_scope == GestureScope::All && m_state == ProcessingUserGesture; }
bool processingUserGestureForMedia() const { return m_state == ProcessingUserGesture || m_state == ProcessingPotentialUserGesture; }
UserGestureType gestureType() const { return m_gestureType; }
@@ -78,6 +79,15 @@
}
void resetDOMPasteAccess() { m_domPasteAccessPolicy = DOMPasteAccessPolicy::NotRequestedYet; }
+ enum class GestureScope { All, MediaOnly };
+ void setScope(GestureScope scope) { m_scope = scope; }
+ void resetScope() { m_scope = GestureScope::All; }
+
+ bool hasExpired(Seconds expirationInterval) const
+ {
+ return m_startTime + expirationInterval < MonotonicTime::now();
+ }
+
private:
UserGestureToken(ProcessingUserGestureState state, UserGestureType gestureType)
: m_state(state)
@@ -89,6 +99,8 @@
Vector<WTF::Function<void (UserGestureToken&)>> m_destructionObservers;
UserGestureType m_gestureType;
DOMPasteAccessPolicy m_domPasteAccessPolicy { DOMPasteAccessPolicy::NotRequestedYet };
+ GestureScope m_scope { GestureScope::All };
+ MonotonicTime m_startTime { MonotonicTime::now() };
};
class UserGestureIndicator {
@@ -103,7 +115,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>);
+ WEBCORE_EXPORT explicit UserGestureIndicator(RefPtr<UserGestureToken>, UserGestureToken::GestureScope = UserGestureToken::GestureScope::All);
WEBCORE_EXPORT ~UserGestureIndicator();
private:
Modified: trunk/Source/WebCore/page/DOMTimer.cpp (244822 => 244823)
--- trunk/Source/WebCore/page/DOMTimer.cpp 2019-05-01 15:55:10 UTC (rev 244822)
+++ trunk/Source/WebCore/page/DOMTimer.cpp 2019-05-01 15:56:34 UTC (rev 244823)
@@ -53,9 +53,8 @@
class DOMTimerFireState {
public:
- DOMTimerFireState(ScriptExecutionContext& context, int nestingLevel, const Seconds& nestedTimerInterval)
+ DOMTimerFireState(ScriptExecutionContext& context, int nestingLevel)
: m_context(context)
- , m_nestedTimerInterval(nestedTimerInterval)
, m_contextIsDocument(is<Document>(m_context))
{
// For worker threads, don't update the current DOMTimerFireState.
@@ -78,8 +77,6 @@
Document* contextDocument() const { return m_contextIsDocument ? &downcast<Document>(m_context) : nullptr; }
- const Seconds& nestedTimerInterval() const { return m_nestedTimerInterval; }
-
void setScriptMadeUserObservableChanges() { m_scriptMadeUserObservableChanges = true; }
void setScriptMadeNonUserObservableChanges() { m_scriptMadeNonUserObservableChanges = true; }
@@ -98,7 +95,6 @@
private:
ScriptExecutionContext& m_context;
- Seconds m_nestedTimerInterval;
uint64_t m_initialDOMTreeVersion;
DOMTimerFireState* m_previous;
bool m_contextIsDocument;
@@ -163,27 +159,6 @@
bool NestedTimersMap::isTrackingNestedTimers = false;
-static inline bool shouldForwardUserGesture(Seconds interval)
-{
- return UserGestureIndicator::processingUserGesture()
- && interval <= maxIntervalForUserGestureForwarding;
-}
-
-static inline RefPtr<UserGestureToken> userGestureTokenToForward(Seconds interval)
-{
- if (!shouldForwardUserGesture(interval))
- return nullptr;
-
- return UserGestureIndicator::currentUserGesture();
-}
-
-static inline Seconds currentNestedTimerInterval()
-{
- if (DOMTimerFireState::current)
- return DOMTimerFireState::current->nestedTimerInterval();
- return { };
-}
-
DOMTimer::DOMTimer(ScriptExecutionContext& context, std::unique_ptr<ScheduledAction> action, Seconds interval, bool singleShot)
: SuspendableTimer(context)
, m_nestingLevel(context.timerNestingLevel())
@@ -191,8 +166,7 @@
, m_originalInterval(interval)
, m_throttleState(Undetermined)
, m_currentTimerInterval(intervalClampedToMinimum())
- , m_nestedTimerInterval(currentNestedTimerInterval())
- , m_userGestureTokenToForward(userGestureTokenToForward(m_nestedTimerInterval + m_currentTimerInterval))
+ , m_userGestureTokenToForward(UserGestureIndicator::currentUserGesture())
{
RefPtr<DOMTimer> reference = adoptRef(this);
@@ -310,8 +284,11 @@
ASSERT(scriptExecutionContext());
ScriptExecutionContext& context = *scriptExecutionContext();
- DOMTimerFireState fireState(context, std::min(m_nestingLevel + 1, maxTimerNestingLevel), m_nestedTimerInterval + m_currentTimerInterval);
+ DOMTimerFireState fireState(context, std::min(m_nestingLevel + 1, maxTimerNestingLevel));
+ if (m_userGestureTokenToForward && m_userGestureTokenToForward->hasExpired(maxIntervalForUserGestureForwarding))
+ m_userGestureTokenToForward = nullptr;
+
ASSERT(!isSuspended());
ASSERT(!context.activeDOMObjectsAreSuspended());
UserGestureIndicator gestureIndicator(m_userGestureTokenToForward);
Modified: trunk/Source/WebCore/page/DOMTimer.h (244822 => 244823)
--- trunk/Source/WebCore/page/DOMTimer.h 2019-05-01 15:55:10 UTC (rev 244822)
+++ trunk/Source/WebCore/page/DOMTimer.h 2019-05-01 15:56:34 UTC (rev 244823)
@@ -92,7 +92,6 @@
Seconds m_originalInterval;
TimerThrottleState m_throttleState;
Seconds m_currentTimerInterval;
- Seconds m_nestedTimerInterval;
RefPtr<UserGestureToken> m_userGestureTokenToForward;
};
Modified: trunk/Source/WebCore/testing/Internals.cpp (244822 => 244823)
--- trunk/Source/WebCore/testing/Internals.cpp 2019-05-01 15:55:10 UTC (rev 244822)
+++ trunk/Source/WebCore/testing/Internals.cpp 2019-05-01 15:56:34 UTC (rev 244823)
@@ -5032,4 +5032,9 @@
page->diagnosticLoggingClient().logDiagnosticMessageWithValueDictionary("testMessage"_s, "testDescription"_s, dictionary, ShouldSample::No);
}
+void Internals::setXHRMaximumIntervalForUserGestureForwarding(XMLHttpRequest& request, double interval)
+{
+ request.setMaximumIntervalForUserGestureForwarding(interval);
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/testing/Internals.h (244822 => 244823)
--- trunk/Source/WebCore/testing/Internals.h 2019-05-01 15:55:10 UTC (rev 244822)
+++ trunk/Source/WebCore/testing/Internals.h 2019-05-01 15:56:34 UTC (rev 244823)
@@ -816,7 +816,9 @@
void processDidResume();
void testDictionaryLogging();
-
+
+ void setXHRMaximumIntervalForUserGestureForwarding(XMLHttpRequest&, double);
+
private:
explicit Internals(Document&);
Document* contextDocument() const;
Modified: trunk/Source/WebCore/testing/Internals.idl (244822 => 244823)
--- trunk/Source/WebCore/testing/Internals.idl 2019-05-01 15:55:10 UTC (rev 244822)
+++ trunk/Source/WebCore/testing/Internals.idl 2019-05-01 15:56:34 UTC (rev 244823)
@@ -747,4 +747,6 @@
void processDidResume();
void testDictionaryLogging();
+
+ void setXHRMaximumIntervalForUserGestureForwarding(XMLHttpRequest xhr, double interval);
};
Modified: trunk/Source/WebCore/xml/XMLHttpRequest.cpp (244822 => 244823)
--- trunk/Source/WebCore/xml/XMLHttpRequest.cpp 2019-05-01 15:55:10 UTC (rev 244822)
+++ trunk/Source/WebCore/xml/XMLHttpRequest.cpp 2019-05-01 15:56:34 UTC (rev 244823)
@@ -66,6 +66,8 @@
namespace WebCore {
+static const Seconds maximumIntervalForUserGestureForwarding { 10_s };
+
WTF_MAKE_ISO_ALLOCATED_IMPL(XMLHttpRequest);
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, xmlHttpRequestCounter, ("XMLHttpRequest"));
@@ -121,6 +123,7 @@
, m_resumeTimer(*this, &XMLHttpRequest::resumeTimerFired)
, m_networkErrorTimer(*this, &XMLHttpRequest::networkErrorTimerFired)
, m_timeoutTimer(*this, &XMLHttpRequest::didReachTimeout)
+ , m_maximumIntervalForUserGestureForwarding(maximumIntervalForUserGestureForwarding)
{
#ifndef NDEBUG
xmlHttpRequestCounter.increment();
@@ -436,6 +439,7 @@
ExceptionOr<void> XMLHttpRequest::send(Optional<SendTypes>&& sendType)
{
InspectorInstrumentation::willSendXMLHttpRequest(scriptExecutionContext(), url());
+ m_userGestureToken = UserGestureIndicator::currentUserGesture();
ExceptionOr<void> result;
if (!sendType)
@@ -1089,6 +1093,20 @@
}
}
+void XMLHttpRequest::dispatchEvent(Event& event)
+{
+ if (m_userGestureToken && m_userGestureToken->hasExpired(m_maximumIntervalForUserGestureForwarding))
+ m_userGestureToken = nullptr;
+
+ if (readyState() != DONE || !m_userGestureToken || !m_userGestureToken->processingUserGesture()) {
+ EventTarget::dispatchEvent(event);
+ return;
+ }
+
+ UserGestureIndicator gestureIndicator(m_userGestureToken, UserGestureToken::GestureScope::MediaOnly);
+ EventTarget::dispatchEvent(event);
+}
+
void XMLHttpRequest::dispatchErrorEvents(const AtomicString& type)
{
if (!m_uploadComplete) {
@@ -1188,4 +1206,9 @@
ActiveDOMObject::contextDestroyed();
}
+void XMLHttpRequest::setMaximumIntervalForUserGestureForwarding(double interval)
+{
+ m_maximumIntervalForUserGestureForwarding = Seconds(interval);
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/xml/XMLHttpRequest.h (244822 => 244823)
--- trunk/Source/WebCore/xml/XMLHttpRequest.h 2019-05-01 15:55:10 UTC (rev 244822)
+++ trunk/Source/WebCore/xml/XMLHttpRequest.h 2019-05-01 15:56:34 UTC (rev 244823)
@@ -26,6 +26,7 @@
#include "FormData.h"
#include "ResourceResponse.h"
#include "ThreadableLoaderClient.h"
+#include "UserGestureIndicator.h"
#include <wtf/URL.h>
#include "XMLHttpRequestEventTarget.h"
#include "XMLHttpRequestProgressEventThrottle.h"
@@ -127,6 +128,8 @@
size_t memoryCost() const;
+ WEBCORE_EXPORT void setMaximumIntervalForUserGestureForwarding(double);
+
private:
explicit XMLHttpRequest(ScriptExecutionContext&);
@@ -187,6 +190,9 @@
void dispatchErrorEvents(const AtomicString&);
+ using EventTarget::dispatchEvent;
+ void dispatchEvent(Event&) override;
+
void resumeTimerFired();
Ref<TextResourceDecoder> createDecoder() const;
@@ -243,6 +249,8 @@
MonotonicTime m_sendingTime;
Optional<ExceptionCode> m_exceptionCode;
+ RefPtr<UserGestureToken> m_userGestureToken;
+ Seconds m_maximumIntervalForUserGestureForwarding;
};
inline auto XMLHttpRequest::responseType() const -> ResponseType