Modified: trunk/LayoutTests/platform/wincairo/TestExpectations (231967 => 231968)
--- trunk/LayoutTests/platform/wincairo/TestExpectations 2018-05-18 18:23:45 UTC (rev 231967)
+++ trunk/LayoutTests/platform/wincairo/TestExpectations 2018-05-18 18:28:37 UTC (rev 231968)
@@ -1561,7 +1561,9 @@
legacy-animation-engine/fast/layers [ Skip ]
legacy-animation-engine/fast/shadow-dom [ Skip ]
legacy-animation-engine/fullscreen [ Skip ]
-loader [ Skip ]
+loader/reload-subresource-when-type-changes.html [ Skip ]
+loader/stateobjects/pushstate-size-iframe.html [ Skip ]
+loader/stateobjects/pushstate-size.html [ Skip ]
mathml [ Skip ]
media [ Skip ]
pageoverlay [ Skip ]
Modified: trunk/Source/WebCore/platform/network/curl/CurlRequest.cpp (231967 => 231968)
--- trunk/Source/WebCore/platform/network/curl/CurlRequest.cpp 2018-05-18 18:23:45 UTC (rev 231967)
+++ trunk/Source/WebCore/platform/network/curl/CurlRequest.cpp 2018-05-18 18:28:37 UTC (rev 231968)
@@ -38,6 +38,8 @@
namespace WebCore {
+static void runOnMainThread(Function<void()>&& task);
+
CurlRequest::CurlRequest(const ResourceRequest&request, CurlRequestClient* client, bool shouldSuspend, bool enableMultipart)
: m_request(request.isolatedCopy())
, m_client(client)
@@ -113,8 +115,8 @@
auto& scheduler = CurlContext::singleton().scheduler();
if (needToInvokeDidCancelTransfer()) {
- scheduler.callOnWorkerThread([protectedThis = makeRef(*this)]() {
- protectedThis->didCancelTransfer();
+ runOnWorkerThreadIfRequired([this, protectedThis = makeRef(*this)]() {
+ didCancelTransfer();
});
} else
scheduler.cancel(this);
@@ -123,8 +125,6 @@
didCancelTransfer();
}
- setRequestPaused(false);
- setCallbackPaused(false);
invalidateClient();
}
@@ -132,6 +132,9 @@
{
ASSERT(isMainThread());
+ if (isCompletedOrCancelled())
+ return;
+
setRequestPaused(true);
}
@@ -139,27 +142,38 @@
{
ASSERT(isMainThread());
+ if (isCompletedOrCancelled())
+ return;
+
setRequestPaused(false);
}
/* `this` is protected inside this method. */
-void CurlRequest::callClient(WTF::Function<void(CurlRequest&, CurlRequestClient&)> task)
+void CurlRequest::callClient(Function<void(CurlRequest&, CurlRequestClient&)>&& task)
{
- if (isMainThread()) {
+ runOnMainThread([this, protectedThis = makeRef(*this), task = WTFMove(task)]() mutable {
if (CurlRequestClient* client = m_client) {
- RefPtr<CurlRequestClient> protectedClient(client);
- task(*this, *client);
+ task(*this, makeRef(*client));
}
- } else {
- callOnMainThread([this, protectedThis = makeRef(*this), task = WTFMove(task)]() mutable {
- if (CurlRequestClient* client = protectedThis->m_client) {
- RefPtr<CurlRequestClient> protectedClient(client);
- task(*this, *client);
- }
- });
- }
+ });
}
+static void runOnMainThread(Function<void()>&& task)
+{
+ if (isMainThread())
+ task();
+ else
+ callOnMainThread(WTFMove(task));
+}
+
+void CurlRequest::runOnWorkerThreadIfRequired(Function<void()>&& task)
+{
+ if (isMainThread() && !m_isSyncRequest)
+ CurlContext::singleton().scheduler().callOnWorkerThread(WTFMove(task));
+ else
+ task();
+}
+
CURL* CurlRequest::setupTransfer()
{
auto& sslHandle = CurlContext::singleton().sslHandle();
@@ -228,7 +242,7 @@
m_curlHandle->setCACertPath(sslHandle.getCACertPath().utf8().data());
if (m_shouldSuspend)
- suspend();
+ setRequestPaused(true);
#ifndef NDEBUG
m_curlHandle->enableVerboseIfUsed();
@@ -358,6 +372,9 @@
// For asynchronous, pause until completeDidReceiveResponse() is called.
setCallbackPaused(true);
invokeDidReceiveResponse(m_response, Action::ReceiveData);
+ // Because libcurl pauses the handle after returning this CURL_WRITEFUNC_PAUSE,
+ // we need to update its state here.
+ updateHandlePauseState(true);
return CURL_WRITEFUNC_PAUSE;
}
@@ -537,8 +554,8 @@
if (!m_isSyncRequest) {
// DidReceiveResponse must not be called immediately
- CurlContext::singleton().scheduler().callOnWorkerThread([protectedThis = makeRef(*this)]() {
- protectedThis->invokeDidReceiveResponse(protectedThis->m_response, Action::StartTransfer);
+ runOnWorkerThreadIfRequired([this, protectedThis = makeRef(*this)]() {
+ invokeDidReceiveResponse(m_response, Action::StartTransfer);
});
} else {
// For synchronous, completeDidReceiveResponse() is called in platformContinueSynchronousDidReceiveResponse().
@@ -580,8 +597,8 @@
startWithJobManager();
} else if (m_actionAfterInvoke == Action::FinishTransfer) {
if (!m_isSyncRequest) {
- CurlContext::singleton().scheduler().callOnWorkerThread([protectedThis = makeRef(*this), finishedResultCode = m_finishedResultCode]() {
- protectedThis->didCompleteTransfer(finishedResultCode);
+ runOnWorkerThreadIfRequired([this, protectedThis = makeRef(*this), finishedResultCode = m_finishedResultCode]() {
+ didCompleteTransfer(finishedResultCode);
});
} else
didCompleteTransfer(m_finishedResultCode);
@@ -590,57 +607,83 @@
void CurlRequest::setRequestPaused(bool paused)
{
- auto wasPaused = isPaused();
+ {
+ LockHolder lock(m_pauseStateMutex);
- m_isPausedOfRequest = paused;
+ auto savedState = shouldBePaused();
+ m_shouldSuspend = m_isPausedOfRequest = paused;
+ if (shouldBePaused() == savedState)
+ return;
+ }
- if (isPaused() == wasPaused)
- return;
-
pausedStatusChanged();
}
void CurlRequest::setCallbackPaused(bool paused)
{
- auto wasPaused = isPaused();
+ {
+ LockHolder lock(m_pauseStateMutex);
- m_isPausedOfCallback = paused;
+ auto savedState = shouldBePaused();
+ m_isPausedOfCallback = paused;
- if (isPaused() == wasPaused)
- return;
+ // If pause is requested, it is called within didReceiveData() which means
+ // actual change happens inside libcurl. No need to update manually here.
+ if (shouldBePaused() == savedState || paused)
+ return;
+ }
- // In this case, PAUSE will be executed within didReceiveData(). Change pause state and return.
- if (paused)
- return;
-
pausedStatusChanged();
}
+void CurlRequest::invokeCancel()
+{
+ // There's no need to extract this method. This is a workaround for MSVC's bug
+ // which happens when using lambda inside other lambda. The compiler loses context
+ // of `this` which prevent makeRef.
+ runOnMainThread([this, protectedThis = makeRef(*this)]() {
+ cancel();
+ });
+}
+
void CurlRequest::pausedStatusChanged()
{
- if (isCompletedOrCancelled())
- return;
+ runOnWorkerThreadIfRequired([this, protectedThis = makeRef(*this)]() {
+ if (isCompletedOrCancelled())
+ return;
- if (!m_isSyncRequest && isMainThread()) {
- CurlContext::singleton().scheduler().callOnWorkerThread([protectedThis = makeRef(*this), paused = isPaused()]() {
- if (protectedThis->isCompletedOrCancelled())
+ bool needCancel { false };
+ {
+ LockHolder lock(m_pauseStateMutex);
+ bool paused = shouldBePaused();
+
+ if (isHandlePaused() == paused)
return;
- auto error = protectedThis->m_curlHandle->pause(paused ? CURLPAUSE_ALL : CURLPAUSE_CONT);
- if ((error != CURLE_OK) && !paused) {
- // Restarting the handle has failed so just cancel it.
- callOnMainThread([protectedThis = makeRef(protectedThis.get())]() {
- protectedThis->cancel();
- });
- }
- });
- } else {
- auto error = m_curlHandle->pause(isPaused() ? CURLPAUSE_ALL : CURLPAUSE_CONT);
- if ((error != CURLE_OK) && !isPaused())
- cancel();
- }
+ auto error = m_curlHandle->pause(paused ? CURLPAUSE_ALL : CURLPAUSE_CONT);
+ if (error == CURLE_OK)
+ updateHandlePauseState(paused);
+
+ needCancel = (error != CURLE_OK && paused);
+ }
+
+ if (needCancel)
+ invokeCancel();
+ });
}
+void CurlRequest::updateHandlePauseState(bool paused)
+{
+ ASSERT(!isMainThread() || m_isSyncRequest);
+ m_isHandlePaused = paused;
+}
+
+bool CurlRequest::isHandlePaused() const
+{
+ ASSERT(!isMainThread() || m_isSyncRequest);
+ return m_isHandlePaused;
+}
+
void CurlRequest::enableDownloadToFile()
{
LockHolder locker(m_downloadMutex);
Modified: trunk/Source/WebCore/platform/network/curl/CurlRequest.h (231967 => 231968)
--- trunk/Source/WebCore/platform/network/curl/CurlRequest.h 2018-05-18 18:23:45 UTC (rev 231967)
+++ trunk/Source/WebCore/platform/network/curl/CurlRequest.h 2018-05-18 18:28:37 UTC (rev 231968)
@@ -105,7 +105,8 @@
void startWithJobManager();
- void callClient(WTF::Function<void(CurlRequest&, CurlRequestClient&)>);
+ void callClient(Function<void(CurlRequest&, CurlRequestClient&)>&&);
+ void runOnWorkerThreadIfRequired(Function<void()>&&);
// Transfer processing of Request body, Response header/body
// Called by worker thread in case of async, main thread in case of sync.
@@ -119,6 +120,7 @@
void didCompleteTransfer(CURLcode) override;
void didCancelTransfer() override;
void finalizeTransfer();
+ void invokeCancel();
// For setup
void appendAcceptLanguageHeader(HTTPHeaderMap&);
@@ -134,7 +136,9 @@
void setRequestPaused(bool);
void setCallbackPaused(bool);
void pausedStatusChanged();
- bool isPaused() const { return m_isPausedOfRequest || m_isPausedOfCallback; };
+ bool shouldBePaused() const { return m_isPausedOfRequest || m_isPausedOfCallback; };
+ void updateHandlePauseState(bool);
+ bool isHandlePaused() const;
// Download
void writeDataToDownloadFileIfEnabled(const SharedBuffer&);
@@ -173,6 +177,16 @@
bool m_isPausedOfRequest { false };
bool m_isPausedOfCallback { false };
+ Lock m_pauseStateMutex;
+ // Following `m_isHandlePaused` is actual paused state of CurlHandle. It's required because pause
+ // request coming from main thread has a time lag until it invokes and receive callback can
+ // change the state by returning a special value. So that is must be managed by this flag.
+ // Unfortunately libcurl doesn't have an interface to check the state.
+ // There's also no need to protect this flag by the mutex because it is and MUST BE accessed only
+ // within worker thread. The access must be using accessor to detect irregular usage.
+ // [TODO] When libcurl is updated to fetch paused state, remove this state variable and
+ // setter/getter above.
+ bool m_isHandlePaused { false };
Lock m_downloadMutex;
bool m_isEnabledDownloadToFile { false };