NetworkDataTaskReplay.cpp [plain text]
#include "config.h"
#include "NetworkDataTaskReplay.h"
#if ENABLE(NETWORK_CAPTURE)
#include "NetworkCaptureEvent.h"
#include "NetworkCaptureLogging.h"
#include "NetworkCaptureResource.h"
#include "NetworkLoadParameters.h"
#include "NetworkSession.h"
#include <WebCore/ResourceError.h>
#include <WebCore/ResourceRequest.h>
#include <WebCore/ResourceResponse.h>
#include <wtf/RunLoop.h>
#define DEBUG_CLASS NetworkDataTaskReplay
namespace WebKit {
namespace NetworkCapture {
static const char* const webKitRelayDomain = "WebKitReplay";
NetworkDataTaskReplay::NetworkDataTaskReplay(NetworkSession& session, NetworkDataTaskClient& client, const NetworkLoadParameters& parameters, Resource* resource)
: NetworkDataTask(session, client, parameters.request, parameters.allowStoredCredentials, parameters.shouldClearReferrerOnHTTPSToHTTPRedirect)
, m_currentRequest(m_firstRequest)
, m_resource(resource)
{
DEBUG_LOG("request URL = " STRING_SPECIFIER, DEBUG_STR(m_firstRequest.url().string()));
DEBUG_LOG("cached URL = " STRING_SPECIFIER, resource ? DEBUG_STR(resource->url().string()) : "<not found>");
m_session->registerNetworkDataTask(*this);
if (resource)
m_eventStream = resource->eventStream();
}
NetworkDataTaskReplay::~NetworkDataTaskReplay()
{
DEBUG_LOG("URL = " STRING_SPECIFIER, DEBUG_STR(m_firstRequest.url().string()));
m_session->unregisterNetworkDataTask(*this);
}
void NetworkDataTaskReplay::resume()
{
DEBUG_LOG("URL = " STRING_SPECIFIER, DEBUG_STR(m_firstRequest.url().string()));
if (m_state == State::Canceling || m_state == State::Completed)
return;
m_state = State::Running;
if (m_scheduledFailureType != NoFailure) {
ASSERT(m_failureTimer.isActive());
return;
}
enqueueEventHandler();
}
void NetworkDataTaskReplay::suspend()
{
DEBUG_LOG("URL = " STRING_SPECIFIER, DEBUG_STR(m_firstRequest.url().string()));
if (m_state == State::Canceling || m_state == State::Completed)
return;
m_state = State::Suspended;
}
void NetworkDataTaskReplay::cancel()
{
DEBUG_LOG("");
if (m_state == State::Canceling || m_state == State::Completed)
return;
m_state = State::Canceling;
}
void NetworkDataTaskReplay::complete()
{
DEBUG_LOG("URL = " STRING_SPECIFIER, DEBUG_STR(m_firstRequest.url().string()));
if (m_state == State::Completed)
return;
m_state = State::Completed;
m_resource = nullptr;
}
void NetworkDataTaskReplay::invalidateAndCancel()
{
DEBUG_LOG("URL = " STRING_SPECIFIER, DEBUG_STR(m_firstRequest.url().string()));
cancel();
complete();
}
void NetworkDataTaskReplay::enqueueEventHandler()
{
DEBUG_LOG("URL = " STRING_SPECIFIER, DEBUG_STR(m_firstRequest.url().string()));
RunLoop::main().dispatch([this, protectedThis = makeRef(*this)] {
DEBUG_LOG("enqueueEventHandler callback");
if (m_state == State::Suspended)
return;
if (m_state == State::Canceling || m_state == State::Completed || !m_client) {
complete();
return;
}
if (!m_resource) {
DEBUG_LOG_ERROR("Error loading resource: could not find cached resource, URL = " STRING_SPECIFIER, DEBUG_STR(m_currentRequest.url().string()));
didFinish(Error::NotFoundError); return;
}
if (!equalLettersIgnoringASCIICase(m_currentRequest.httpMethod(), "get")) {
DEBUG_LOG_ERROR("Error loading resource: unsupported method (" STRING_SPECIFIER "), URL = " STRING_SPECIFIER, DEBUG_STR(m_currentRequest.httpMethod()), DEBUG_STR(m_currentRequest.url().string()));
didFinish(Error::MethodNotAllowed);
return;
}
auto event = m_eventStream.nextEvent();
if (!event) {
DEBUG_LOG_ERROR("Error loading resource: nextEvent return null, URL = " STRING_SPECIFIER, DEBUG_STR(m_currentRequest.url().string()));
didFinish(Error::NotFoundError); return;
}
const auto visitor = WTF::makeVisitor(
[this](const RequestSentEvent& event) {
replayRequestSent(event);
},
[this](const ResponseReceivedEvent& event) {
replayResponseReceived(event);
},
[this](const RedirectReceivedEvent& event) {
replayRedirectReceived(event);
},
[this](const RedirectSentEvent& event) {
replayRedirectSent(event);
},
[this](const DataReceivedEvent& event) {
replayDataReceived(event);
},
[this](const FinishedEvent& event) {
replayFinished(event);
});
WTF::visit(visitor, *event);
});
}
void NetworkDataTaskReplay::replayRequestSent(const RequestSentEvent& event)
{
DEBUG_LOG("URL = " STRING_SPECIFIER, DEBUG_STR(m_firstRequest.url().string()));
enqueueEventHandler();
}
void NetworkDataTaskReplay::replayResponseReceived(const ResponseReceivedEvent& event)
{
DEBUG_LOG("URL = " STRING_SPECIFIER, DEBUG_STR(m_firstRequest.url().string()));
WebCore::ResourceResponse response(event.response);
didReceiveResponse(WTFMove(response));
}
void NetworkDataTaskReplay::replayRedirectReceived(const RedirectReceivedEvent& event)
{
DEBUG_LOG("URL = " STRING_SPECIFIER, DEBUG_STR(m_firstRequest.url().string()));
WebCore::ResourceResponse receivedResponse = event.response;
WebCore::ResourceRequest receivedRequest = event.request;
ASSERT(m_client);
m_client->willPerformHTTPRedirection(WTFMove(receivedResponse), WTFMove(receivedRequest), [this, protectedThis = makeRef(*this)] (const WebCore::ResourceRequest& updatedRequest) {
DEBUG_LOG("replayRedirectReceived callback: URL = " STRING_SPECIFIER, DEBUG_STR(m_firstRequest.url().string()));
m_currentRequest = updatedRequest;
enqueueEventHandler();
});
}
void NetworkDataTaskReplay::replayRedirectSent(const RedirectSentEvent& event)
{
DEBUG_LOG("URL = " STRING_SPECIFIER, DEBUG_STR(m_firstRequest.url().string()));
enqueueEventHandler();
}
void NetworkDataTaskReplay::replayDataReceived(const DataReceivedEvent& event)
{
DEBUG_LOG("URL = " STRING_SPECIFIER, DEBUG_STR(m_firstRequest.url().string()));
ASSERT(m_client);
m_client->didReceiveData(event.data.copyRef());
enqueueEventHandler();
}
void NetworkDataTaskReplay::replayFinished(const FinishedEvent& event)
{
DEBUG_LOG("URL = " STRING_SPECIFIER, DEBUG_STR(m_firstRequest.url().string()));
didFinish(event.error);
}
void NetworkDataTaskReplay::didReceiveResponse(WebCore::ResourceResponse&& response)
{
DEBUG_LOG("URL = " STRING_SPECIFIER, DEBUG_STR(m_firstRequest.url().string()));
ASSERT(m_client);
m_client->didReceiveResponseNetworkSession(WTFMove(response), [this, protectedThis = makeRef(*this)](WebCore::PolicyAction policyAction) {
DEBUG_LOG("didReceiveResponse callback (%u)", static_cast<unsigned>(policyAction));
if (m_state == State::Canceling || m_state == State::Completed) {
complete();
return;
}
switch (policyAction) {
case WebCore::PolicyAction::PolicyUse:
enqueueEventHandler();
break;
case WebCore::PolicyAction::PolicyIgnore:
complete();
break;
case WebCore::PolicyAction::PolicyDownload:
DEBUG_LOG_ERROR("WebCore::PolicyAction::PolicyDownload");
break;
}
});
}
void NetworkDataTaskReplay::didFinish()
{
didFinish({ });
}
void NetworkDataTaskReplay::didFinish(Error errorCode)
{
didFinish(WebCore::ResourceError(webKitRelayDomain, static_cast<int>(errorCode), m_firstRequest.url(), String()));
}
void NetworkDataTaskReplay::didFinish(const WebCore::ResourceError& error)
{
DEBUG_LOG("(%d)", error.errorCode());
complete();
ASSERT(m_client);
m_client->didCompleteWithError(error);
}
} }
#endif // ENABLE(NETWORK_CAPTURE)