NetworkCORSPreflightChecker.cpp [plain text]
#include "config.h"
#include "NetworkCORSPreflightChecker.h"
#include "AuthenticationManager.h"
#include "Logging.h"
#include "NetworkLoadParameters.h"
#include "NetworkProcess.h"
#include "SessionTracker.h"
#include <WebCore/CrossOriginAccessControl.h>
#include <WebCore/SecurityOrigin.h>
#define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(m_parameters.sessionID.isAlwaysOnLoggingAllowed(), Network, "%p - NetworkCORSPreflightChecker::" fmt, this, ##__VA_ARGS__)
namespace WebKit {
using namespace WebCore;
NetworkCORSPreflightChecker::NetworkCORSPreflightChecker(Parameters&& parameters, bool shouldCaptureExtraNetworkLoadMetrics, CompletionCallback&& completionCallback)
: m_parameters(WTFMove(parameters))
, m_completionCallback(WTFMove(completionCallback))
, m_shouldCaptureExtraNetworkLoadMetrics(shouldCaptureExtraNetworkLoadMetrics)
{
}
NetworkCORSPreflightChecker::~NetworkCORSPreflightChecker()
{
if (m_task) {
ASSERT(m_task->client() == this);
m_task->clearClient();
m_task->cancel();
}
if (m_completionCallback)
m_completionCallback(ResourceError { ResourceError::Type::Cancellation });
}
void NetworkCORSPreflightChecker::startPreflight()
{
RELEASE_LOG_IF_ALLOWED("startPreflight");
NetworkLoadParameters loadParameters;
loadParameters.sessionID = m_parameters.sessionID;
loadParameters.request = createAccessControlPreflightRequest(m_parameters.originalRequest, m_parameters.sourceOrigin, m_parameters.referrer);
loadParameters.shouldFollowRedirects = false;
if (!m_parameters.userAgent.isNull())
loadParameters.request.setHTTPHeaderField(HTTPHeaderName::UserAgent, m_parameters.userAgent);
if (m_shouldCaptureExtraNetworkLoadMetrics)
m_loadInformation = NetworkTransactionInformation { NetworkTransactionInformation::Type::Preflight, loadParameters.request, { }, { } };
if (auto* networkSession = SessionTracker::networkSession(loadParameters.sessionID)) {
m_task = NetworkDataTask::create(*networkSession, *this, WTFMove(loadParameters));
m_task->resume();
} else
ASSERT_NOT_REACHED();
}
void NetworkCORSPreflightChecker::willPerformHTTPRedirection(WebCore::ResourceResponse&& response, WebCore::ResourceRequest&&, RedirectCompletionHandler&& completionHandler)
{
if (m_shouldCaptureExtraNetworkLoadMetrics)
m_loadInformation.response = WTFMove(response);
RELEASE_LOG_IF_ALLOWED("willPerformHTTPRedirection");
completionHandler({ });
m_completionCallback(ResourceError { errorDomainWebKitInternal, 0, m_parameters.originalRequest.url(), "Preflight response is not successful"_s, ResourceError::Type::AccessControl });
}
void NetworkCORSPreflightChecker::didReceiveChallenge(WebCore::AuthenticationChallenge&& challenge, ChallengeCompletionHandler&& completionHandler)
{
RELEASE_LOG_IF_ALLOWED("didReceiveChallenge, authentication scheme: %u", challenge.protectionSpace().authenticationScheme());
auto scheme = challenge.protectionSpace().authenticationScheme();
bool isTLSHandshake = scheme == ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested
|| scheme == ProtectionSpaceAuthenticationSchemeClientCertificateRequested;
if (!isTLSHandshake) {
completionHandler(AuthenticationChallengeDisposition::UseCredential, { });
return;
}
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
NetworkProcess::singleton().canAuthenticateAgainstProtectionSpace(challenge.protectionSpace(), m_parameters.pageID, m_parameters.frameID, [this, weakThis = makeWeakPtr(this), completionHandler = WTFMove(completionHandler), challenge = WTFMove(challenge)] (bool canAuthenticate) mutable {
if (!canAuthenticate)
return completionHandler(AuthenticationChallengeDisposition::RejectProtectionSpace, { });
NetworkProcess::singleton().authenticationManager().didReceiveAuthenticationChallenge(m_parameters.pageID, m_parameters.frameID, challenge, WTFMove(completionHandler));
});
#else
NetworkProcess::singleton().authenticationManager().didReceiveAuthenticationChallenge(m_parameters.pageID, m_parameters.frameID, challenge, WTFMove(completionHandler));
#endif
}
void NetworkCORSPreflightChecker::didReceiveResponseNetworkSession(WebCore::ResourceResponse&& response, ResponseCompletionHandler&& completionHandler)
{
RELEASE_LOG_IF_ALLOWED("didReceiveResponseNetworkSession");
if (m_shouldCaptureExtraNetworkLoadMetrics)
m_loadInformation.response = response;
m_response = WTFMove(response);
completionHandler(PolicyAction::Use);
}
void NetworkCORSPreflightChecker::didReceiveData(Ref<WebCore::SharedBuffer>&&)
{
RELEASE_LOG_IF_ALLOWED("didReceiveData");
}
void NetworkCORSPreflightChecker::didCompleteWithError(const WebCore::ResourceError& preflightError, const WebCore::NetworkLoadMetrics& metrics)
{
if (m_shouldCaptureExtraNetworkLoadMetrics)
m_loadInformation.metrics = metrics;
if (!preflightError.isNull()) {
RELEASE_LOG_IF_ALLOWED("didCompleteWithError");
auto error = preflightError;
if (error.isNull() || error.isGeneral())
error.setType(ResourceError::Type::AccessControl);
m_completionCallback(WTFMove(error));
return;
}
RELEASE_LOG_IF_ALLOWED("didComplete http_status_code: %d", m_response.httpStatusCode());
String errorDescription;
if (!validatePreflightResponse(m_parameters.originalRequest, m_response, m_parameters.storedCredentialsPolicy, m_parameters.sourceOrigin, errorDescription)) {
RELEASE_LOG_IF_ALLOWED("didComplete, AccessControl error: %s", errorDescription.utf8().data());
m_completionCallback(ResourceError { errorDomainWebKitInternal, 0, m_parameters.originalRequest.url(), errorDescription, ResourceError::Type::AccessControl });
return;
}
m_completionCallback(ResourceError { });
}
void NetworkCORSPreflightChecker::didSendData(uint64_t totalBytesSent, uint64_t totalBytesExpectedToSend)
{
}
void NetworkCORSPreflightChecker::wasBlocked()
{
RELEASE_LOG_IF_ALLOWED("wasBlocked");
m_completionCallback(ResourceError { errorDomainWebKitInternal, 0, m_parameters.originalRequest.url(), "CORS-preflight request was blocked"_s, ResourceError::Type::AccessControl });
}
void NetworkCORSPreflightChecker::cannotShowURL()
{
RELEASE_LOG_IF_ALLOWED("cannotShowURL");
m_completionCallback(ResourceError { errorDomainWebKitInternal, 0, m_parameters.originalRequest.url(), "Preflight response was blocked"_s, ResourceError::Type::AccessControl });
}
NetworkTransactionInformation NetworkCORSPreflightChecker::takeInformation()
{
ASSERT(m_shouldCaptureExtraNetworkLoadMetrics);
return WTFMove(m_loadInformation);
}
}