summaryrefslogtreecommitdiff
path: root/Source/WebKit2/NetworkProcess/capture/NetworkDataTaskReplay.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/NetworkProcess/capture/NetworkDataTaskReplay.cpp')
-rw-r--r--Source/WebKit2/NetworkProcess/capture/NetworkDataTaskReplay.cpp288
1 files changed, 288 insertions, 0 deletions
diff --git a/Source/WebKit2/NetworkProcess/capture/NetworkDataTaskReplay.cpp b/Source/WebKit2/NetworkProcess/capture/NetworkDataTaskReplay.cpp
new file mode 100644
index 000000000..30d730252
--- /dev/null
+++ b/Source/WebKit2/NetworkProcess/capture/NetworkDataTaskReplay.cpp
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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); // TODO: Turn this into a 404?
+ 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); // TODO: Turn this into a 404?
+ 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);
+}
+
+} // namespace NetworkCapture
+} // namespace WebKit
+
+#endif // ENABLE(NETWORK_CAPTURE)