Title: [222665] trunk/Source/WebCore
Revision
222665
Author
[email protected]
Date
2017-09-29 14:19:32 -0700 (Fri, 29 Sep 2017)

Log Message

[Curl] Extract a features to manage HTTP communication from ResourceHandle
https://bugs.webkit.org/show_bug.cgi?id=175148

Patch by Basuke Suzuki <[email protected]> on 2017-09-29
Reviewed by Alex Christensen.

* platform/Curl.cmake:
* platform/network/curl/CurlRequest.cpp: Added.
(WebCore::CurlRequest::CurlRequest):
(WebCore::CurlRequest::setUserPass):
(WebCore::CurlRequest::start):
(WebCore::CurlRequest::startWithJobManager):
(WebCore::CurlRequest::cancel):
(WebCore::CurlRequest::suspend):
(WebCore::CurlRequest::resume):
(WebCore::CurlRequest::callDelegate):
(WebCore::CurlRequest::setupTransfer):
(WebCore::CurlRequest::willSetupSslCtx):
(WebCore::CurlRequest::willSendData):
(WebCore::CurlRequest::didReceiveHeader):
(WebCore::CurlRequest::didReceiveData):
(WebCore::CurlRequest::didCompleteTransfer):
(WebCore::CurlRequest::didCancelTransfer):
(WebCore::CurlRequest::resolveBlobReferences):
(WebCore::CurlRequest::setupPUT):
(WebCore::CurlRequest::setupPOST):
(WebCore::CurlRequest::setupFormData):
(WebCore::CurlRequest::invokeDidReceiveResponseForFile):
(WebCore::CurlRequest::invokeDidReceiveResponse):
(WebCore::CurlRequest::setPaused):
(WebCore::CurlRequest::willSetupSslCtxCallback):
(WebCore::CurlRequest::willSendDataCallback):
(WebCore::CurlRequest::didReceiveHeaderCallback):
(WebCore::CurlRequest::didReceiveDataCallback):
* platform/network/curl/CurlRequest.h: Added.
(WebCore::CurlRequest::~CurlRequest):
(WebCore::CurlRequest::setDelegate):
(WebCore::CurlRequest::isSyncRequest):
(WebCore::CurlRequest::getNetworkLoadMetrics):
* platform/network/curl/CurlRequestDelegate.h: Added.
* platform/network/curl/ResourceHandleCurl.cpp:
(WebCore::ResourceHandle::cancel):
(WebCore::ResourceHandle::platformSetDefersLoading):
(WebCore::ResourceHandle::didReceiveAuthenticationChallenge):
(WebCore::ResourceHandle::receivedCredential):
(WebCore::ResourceHandle::receivedRequestToContinueWithoutCredential):
(WebCore::ResourceHandle::receivedCancellation):
* platform/network/curl/ResourceHandleCurlDelegate.cpp:
(WebCore::ResourceHandleCurlDelegate::ResourceHandleCurlDelegate):
(WebCore::ResourceHandleCurlDelegate::~ResourceHandleCurlDelegate):
(WebCore::ResourceHandleCurlDelegate::start):
(WebCore::ResourceHandleCurlDelegate::cancel):
(WebCore::ResourceHandleCurlDelegate::setDefersLoading):
(WebCore::ResourceHandleCurlDelegate::setAuthentication):
(WebCore::ResourceHandleCurlDelegate::dispatchSynchronousJob):
(WebCore::ResourceHandleCurlDelegate::createCurlRequest):
(WebCore::ResourceHandleCurlDelegate::cancelledOrClientless):
(WebCore::ResourceHandleCurlDelegate::curlDidReceiveResponse):
(WebCore::ResourceHandleCurlDelegate::curlDidReceiveBuffer):
(WebCore::ResourceHandleCurlDelegate::curlDidComplete):
(WebCore::ResourceHandleCurlDelegate::curlDidFailWithError):
(WebCore::ResourceHandleCurlDelegate::response):
(WebCore::ResourceHandleCurlDelegate::getCredential):
(WebCore::ResourceHandleCurlDelegate::retain): Deleted.
(WebCore::ResourceHandleCurlDelegate::release): Deleted.
(WebCore::ResourceHandleCurlDelegate::setupTransfer): Deleted.
(WebCore::ResourceHandleCurlDelegate::didCompleteTransfer): Deleted.
(WebCore::ResourceHandleCurlDelegate::didCancelTransfer): Deleted.
(WebCore::ResourceHandleCurlDelegate::setupAuthentication): Deleted.
(WebCore::ResourceHandleCurlDelegate::didReceiveAllHeaders): Deleted.
(WebCore::ResourceHandleCurlDelegate::didReceiveContentData): Deleted.
(WebCore::ResourceHandleCurlDelegate::handleLocalReceiveResponse): Deleted.
(WebCore::ResourceHandleCurlDelegate::prepareSendData): Deleted.
(WebCore::ResourceHandleCurlDelegate::didFinish): Deleted.
(WebCore::ResourceHandleCurlDelegate::didFail): Deleted.
(WebCore::ResourceHandleCurlDelegate::setupPOST): Deleted.
(WebCore::ResourceHandleCurlDelegate::setupPUT): Deleted.
(WebCore::ResourceHandleCurlDelegate::getFormElementsCount): Deleted.
(WebCore::ResourceHandleCurlDelegate::setupFormData): Deleted.
(WebCore::ResourceHandleCurlDelegate::applyAuthentication): Deleted.
(WebCore::ResourceHandleCurlDelegate::getNetworkLoadMetrics): Deleted.
(WebCore::ResourceHandleCurlDelegate::willSetupSslCtx): Deleted.
(WebCore::ResourceHandleCurlDelegate::didReceiveHeader): Deleted.
(WebCore::ResourceHandleCurlDelegate::didReceiveData): Deleted.
(WebCore::ResourceHandleCurlDelegate::willSendData): Deleted.
(WebCore::ResourceHandleCurlDelegate::willSetupSslCtxCallback): Deleted.
(WebCore::ResourceHandleCurlDelegate::didReceiveHeaderCallback): Deleted.
(WebCore::ResourceHandleCurlDelegate::didReceiveDataCallback): Deleted.
(WebCore::ResourceHandleCurlDelegate::willSendDataCallback): Deleted.
* platform/network/curl/ResourceHandleCurlDelegate.h:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (222664 => 222665)


--- trunk/Source/WebCore/ChangeLog	2017-09-29 21:14:09 UTC (rev 222664)
+++ trunk/Source/WebCore/ChangeLog	2017-09-29 21:19:32 UTC (rev 222665)
@@ -1,3 +1,95 @@
+2017-09-29  Basuke Suzuki  <[email protected]>
+
+        [Curl] Extract a features to manage HTTP communication from ResourceHandle
+        https://bugs.webkit.org/show_bug.cgi?id=175148
+
+        Reviewed by Alex Christensen.
+
+        * platform/Curl.cmake:
+        * platform/network/curl/CurlRequest.cpp: Added.
+        (WebCore::CurlRequest::CurlRequest):
+        (WebCore::CurlRequest::setUserPass):
+        (WebCore::CurlRequest::start):
+        (WebCore::CurlRequest::startWithJobManager):
+        (WebCore::CurlRequest::cancel):
+        (WebCore::CurlRequest::suspend):
+        (WebCore::CurlRequest::resume):
+        (WebCore::CurlRequest::callDelegate):
+        (WebCore::CurlRequest::setupTransfer):
+        (WebCore::CurlRequest::willSetupSslCtx):
+        (WebCore::CurlRequest::willSendData):
+        (WebCore::CurlRequest::didReceiveHeader):
+        (WebCore::CurlRequest::didReceiveData):
+        (WebCore::CurlRequest::didCompleteTransfer):
+        (WebCore::CurlRequest::didCancelTransfer):
+        (WebCore::CurlRequest::resolveBlobReferences):
+        (WebCore::CurlRequest::setupPUT):
+        (WebCore::CurlRequest::setupPOST):
+        (WebCore::CurlRequest::setupFormData):
+        (WebCore::CurlRequest::invokeDidReceiveResponseForFile):
+        (WebCore::CurlRequest::invokeDidReceiveResponse):
+        (WebCore::CurlRequest::setPaused):
+        (WebCore::CurlRequest::willSetupSslCtxCallback):
+        (WebCore::CurlRequest::willSendDataCallback):
+        (WebCore::CurlRequest::didReceiveHeaderCallback):
+        (WebCore::CurlRequest::didReceiveDataCallback):
+        * platform/network/curl/CurlRequest.h: Added.
+        (WebCore::CurlRequest::~CurlRequest):
+        (WebCore::CurlRequest::setDelegate):
+        (WebCore::CurlRequest::isSyncRequest):
+        (WebCore::CurlRequest::getNetworkLoadMetrics):
+        * platform/network/curl/CurlRequestDelegate.h: Added.
+        * platform/network/curl/ResourceHandleCurl.cpp:
+        (WebCore::ResourceHandle::cancel):
+        (WebCore::ResourceHandle::platformSetDefersLoading):
+        (WebCore::ResourceHandle::didReceiveAuthenticationChallenge):
+        (WebCore::ResourceHandle::receivedCredential):
+        (WebCore::ResourceHandle::receivedRequestToContinueWithoutCredential):
+        (WebCore::ResourceHandle::receivedCancellation):
+        * platform/network/curl/ResourceHandleCurlDelegate.cpp:
+        (WebCore::ResourceHandleCurlDelegate::ResourceHandleCurlDelegate):
+        (WebCore::ResourceHandleCurlDelegate::~ResourceHandleCurlDelegate):
+        (WebCore::ResourceHandleCurlDelegate::start):
+        (WebCore::ResourceHandleCurlDelegate::cancel):
+        (WebCore::ResourceHandleCurlDelegate::setDefersLoading):
+        (WebCore::ResourceHandleCurlDelegate::setAuthentication):
+        (WebCore::ResourceHandleCurlDelegate::dispatchSynchronousJob):
+        (WebCore::ResourceHandleCurlDelegate::createCurlRequest):
+        (WebCore::ResourceHandleCurlDelegate::cancelledOrClientless):
+        (WebCore::ResourceHandleCurlDelegate::curlDidReceiveResponse):
+        (WebCore::ResourceHandleCurlDelegate::curlDidReceiveBuffer):
+        (WebCore::ResourceHandleCurlDelegate::curlDidComplete):
+        (WebCore::ResourceHandleCurlDelegate::curlDidFailWithError):
+        (WebCore::ResourceHandleCurlDelegate::response):
+        (WebCore::ResourceHandleCurlDelegate::getCredential):
+        (WebCore::ResourceHandleCurlDelegate::retain): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::release): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::setupTransfer): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::didCompleteTransfer): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::didCancelTransfer): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::setupAuthentication): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::didReceiveAllHeaders): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::didReceiveContentData): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::handleLocalReceiveResponse): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::prepareSendData): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::didFinish): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::didFail): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::setupPOST): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::setupPUT): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::getFormElementsCount): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::setupFormData): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::applyAuthentication): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::getNetworkLoadMetrics): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::willSetupSslCtx): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::didReceiveHeader): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::didReceiveData): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::willSendData): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::willSetupSslCtxCallback): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::didReceiveHeaderCallback): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::didReceiveDataCallback): Deleted.
+        (WebCore::ResourceHandleCurlDelegate::willSendDataCallback): Deleted.
+        * platform/network/curl/ResourceHandleCurlDelegate.h:
+
 2017-09-29  Chris Dumez  <[email protected]>
 
         Split some logic out of VisitedLinkStore and make it reusable

Modified: trunk/Source/WebCore/platform/Curl.cmake (222664 => 222665)


--- trunk/Source/WebCore/platform/Curl.cmake	2017-09-29 21:14:09 UTC (rev 222664)
+++ trunk/Source/WebCore/platform/Curl.cmake	2017-09-29 21:19:32 UTC (rev 222665)
@@ -11,6 +11,7 @@
     platform/network/curl/CurlContext.cpp
     platform/network/curl/CurlDownload.cpp
     platform/network/curl/CurlJobManager.cpp
+    platform/network/curl/CurlRequest.cpp
     platform/network/curl/CurlSSLHandle.cpp
     platform/network/curl/CurlSSLVerifier.cpp
     platform/network/curl/DNSCurl.cpp

Added: trunk/Source/WebCore/platform/network/curl/CurlRequest.cpp (0 => 222665)


--- trunk/Source/WebCore/platform/network/curl/CurlRequest.cpp	                        (rev 0)
+++ trunk/Source/WebCore/platform/network/curl/CurlRequest.cpp	2017-09-29 21:19:32 UTC (rev 222665)
@@ -0,0 +1,537 @@
+/*
+ * Copyright (C) 2017 Sony Interactive Entertainment Inc.
+ *
+ * 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 "CurlRequest.h"
+
+#if USE(CURL)
+
+#include "CurlRequestDelegate.h"
+#include "MIMETypeRegistry.h"
+#include "ResourceError.h"
+#include "SharedBuffer.h"
+#include <wtf/MainThread.h>
+
+namespace WebCore {
+
+CurlRequest::CurlRequest(const ResourceRequest&request, CurlRequestDelegate* delegate, bool shouldSuspend)
+    : m_request(request.isolatedCopy())
+    , m_shouldSuspend(shouldSuspend)
+{
+    ASSERT(isMainThread());
+
+    setDelegate(delegate);
+    resolveBlobReferences(m_request);
+}
+
+void CurlRequest::setUserPass(const String& user, const String& password)
+{
+    ASSERT(isMainThread());
+
+    m_user = user.isolatedCopy();
+    m_password = user.isolatedCopy();
+}
+
+void CurlRequest::start(bool isSyncRequest)
+{
+    ASSERT(isMainThread());
+
+    m_isSyncRequest = isSyncRequest;
+
+    auto url = ""
+
+    if (!m_isSyncRequest) {
+        // For asynchronous, use CurlJobManager. Curl processes runs on sub thread.
+        if (url.isLocalFile())
+            invokeDidReceiveResponseForFile(url);
+
+        startWithJobManager();
+    } else {
+        // For synchronous, does not use CurlJobManager. Curl processes runs on main thread.
+        // curl_easy_perform blocks until the transfer is finished.
+        retain();
+        if (url.isLocalFile())
+            invokeDidReceiveResponseForFile(url);
+
+        setupTransfer();
+        CURLcode resultCode = m_curlHandle->perform();
+        didCompleteTransfer(resultCode);
+        release();
+    }
+}
+
+void CurlRequest::startWithJobManager()
+{
+    ASSERT(isMainThread());
+
+    CurlJobManager::singleton().add(this);
+}
+
+void CurlRequest::cancel()
+{
+    ASSERT(isMainThread());
+
+    if (m_cancelled)
+        return;
+
+    m_cancelled = true;
+
+    if (!m_isSyncRequest)
+        CurlJobManager::singleton().cancel(this);
+
+    setPaused(false);
+}
+
+void CurlRequest::suspend()
+{
+    ASSERT(isMainThread());
+
+    setPaused(true);
+}
+
+void CurlRequest::resume()
+{
+    ASSERT(isMainThread());
+
+    setPaused(false);
+}
+
+/* `this` is protected inside this method. */
+void CurlRequest::callDelegate(WTF::Function<void(CurlRequestDelegate*)> task)
+{
+    if (isMainThread()) {
+        if (CurlRequestDelegate* delegate = m_delegate)
+            task(delegate);
+    } else {
+        callOnMainThread([protectedThis = makeRef(*this), task = WTFMove(task)]() mutable {
+            if (CurlRequestDelegate* delegate = protectedThis->m_delegate)
+                task(delegate);
+        });
+    }
+}
+
+CURL* CurlRequest::setupTransfer()
+{
+    auto& sslHandle = CurlContext::singleton().sslHandle();
+
+    m_curlHandle = std::make_unique<CurlHandle>();
+
+    m_curlHandle->initialize();
+    m_curlHandle->setUrl(m_request.url());
+    m_curlHandle->appendRequestHeaders(m_request.httpHeaderFields());
+
+    auto method = m_request.httpMethod();
+    if (method == "GET")
+        m_curlHandle->enableHttpGetRequest();
+    else if (method == "POST")
+        setupPOST(m_request);
+    else if (method == "PUT")
+        setupPUT(m_request);
+    else if (method == "HEAD")
+        m_curlHandle->enableHttpHeadRequest();
+    else {
+        m_curlHandle->setHttpCustomRequest(method);
+        setupPUT(m_request);
+    }
+
+    if (!m_user.isEmpty() || !m_password.isEmpty()) {
+        m_curlHandle->enableHttpAuthentication(CURLAUTH_ANY);
+        m_curlHandle->setHttpAuthUserPass(m_user.latin1().data(), m_password.latin1().data());
+    }
+
+    m_curlHandle->setHeaderCallbackFunction(didReceiveHeaderCallback, this);
+    m_curlHandle->setWriteCallbackFunction(didReceiveDataCallback, this);
+
+    m_curlHandle->enableShareHandle();
+    m_curlHandle->enableAllowedProtocols();
+    m_curlHandle->enableAcceptEncoding();
+    m_curlHandle->enableTimeout();
+
+    m_curlHandle->enableAutoReferer();
+    m_curlHandle->enableFollowLocation();
+    m_curlHandle->enableProxyIfExists();
+    m_curlHandle->enableCookieJarIfExists();
+
+    m_curlHandle->setSslVerifyPeer(CurlHandle::VerifyPeer::Enable);
+    m_curlHandle->setSslVerifyHost(CurlHandle::VerifyHost::StrictNameCheck);
+
+    auto sslClientCertificate = sslHandle.getSSLClientCertificate(m_request.url().host());
+    if (sslClientCertificate) {
+        m_curlHandle->setSslCert(sslClientCertificate->first.utf8().data());
+        m_curlHandle->setSslCertType("P12");
+        m_curlHandle->setSslKeyPassword(sslClientCertificate->second.utf8().data());
+    }
+
+    if (sslHandle.shouldIgnoreSSLErrors())
+        m_curlHandle->setSslVerifyPeer(CurlHandle::VerifyPeer::Disable);
+    else
+        m_curlHandle->setSslCtxCallbackFunction(willSetupSslCtxCallback, this);
+
+    m_curlHandle->setCACertPath(sslHandle.getCACertPath());
+
+    if (m_shouldSuspend)
+        suspend();
+
+#ifndef NDEBUG
+    m_curlHandle->enableVerboseIfUsed();
+    m_curlHandle->enableStdErrIfUsed();
+#endif
+
+    return m_curlHandle->handle();
+}
+
+CURLcode CurlRequest::willSetupSslCtx(void* sslCtx)
+{
+    m_sslVerifier.setCurlHandle(m_curlHandle.get());
+    m_sslVerifier.setHostName(m_request.url().host());
+    m_sslVerifier.setSslCtx(sslCtx);
+
+    return CURLE_OK;
+}
+
+// This is called to obtain HTTP POST or PUT data.
+// Iterate through FormData elements and upload files.
+// Carefully respect the given buffer size and fill the rest of the data at the next calls.
+
+size_t CurlRequest::willSendData(char* ptr, size_t blockSize, size_t numberOfBlocks)
+{
+    if (m_cancelled)
+        return CURL_READFUNC_ABORT;
+
+    if (!blockSize || !numberOfBlocks)
+        return 0;
+
+    if (!m_formDataStream || !m_formDataStream->hasMoreElements())
+        return 0;
+
+    auto sendBytes = m_formDataStream->read(ptr, blockSize, numberOfBlocks);
+    if (!sendBytes) {
+        // Something went wrong so error the job.
+        return CURL_READFUNC_ABORT;
+    }
+
+    return sendBytes;
+}
+
+// This is being called for each HTTP header in the response. This includes '\r\n'
+// for the last line of the header.
+
+size_t CurlRequest::didReceiveHeader(String&& header)
+{
+    static const auto emptyLineCRLF = "\r\n";
+    static const auto emptyLineLF = "\n";
+
+    if (m_cancelled)
+        return 0;
+
+    auto receiveBytes = static_cast<size_t>(header.length());
+
+    // The HTTP standard requires to use \r\n but for compatibility it recommends to accept also \n.
+    if ((header != emptyLineCRLF) && (header != emptyLineLF)) {
+        m_response.headers.append(WTFMove(header));
+        return receiveBytes;
+    }
+
+    long statusCode = 0;
+    if (auto code = m_curlHandle->getResponseCode())
+        statusCode = *code;
+
+    long httpConnectCode = 0;
+    if (auto code = m_curlHandle->getHttpConnectCode())
+        httpConnectCode = *code;
+
+    if ((100 <= statusCode) && (statusCode < 200)) {
+        // Just return when receiving http info, e.g. HTTP/1.1 100 Continue.
+        // If not, the request might be cancelled, because the MIME type will be empty for this response.
+        m_response = CurlResponse { };
+        return receiveBytes;
+    }
+
+    if (!statusCode && (httpConnectCode == 200)) {
+        // Comes here when receiving 200 Connection Established. Just return.
+        m_response = CurlResponse { };
+        return receiveBytes;
+    }
+
+    // If the FOLLOWLOCATION option is enabled for the curl handle then
+    // curl will follow the redirections internally. Thus this header callback
+    // will be called more than one time with the line starting "HTTP" for one job.
+
+    m_response.url = ""
+    m_response.statusCode = statusCode;
+
+    if (auto length = m_curlHandle->getContentLength())
+        m_response.expectedContentLength = *length;
+
+    if (auto port = m_curlHandle->getPrimaryPort())
+        m_response.connectPort = *port;
+
+    if (auto auth = m_curlHandle->getHttpAuthAvail())
+        m_response.availableHttpAuth = *auth;
+
+    if (auto metrics = m_curlHandle->getNetworkLoadMetrics())
+        m_networkLoadMetrics = *metrics;
+
+    invokeDidReceiveResponse();
+
+    return receiveBytes;
+}
+
+// called with data after all headers have been processed via headerCallback
+
+size_t CurlRequest::didReceiveData(Ref<SharedBuffer>&& buffer)
+{
+    if (m_cancelled)
+        return 0;
+
+    auto receiveBytes = buffer->size();
+
+    // this shouldn't be necessary but apparently is. CURL writes the data
+    // of html page even if it is a redirect that was handled internally
+    // can be observed e.g. on gmail.com
+    auto statusCode = m_curlHandle->getResponseCode();
+    if (statusCode && (300 <= *statusCode) && (*statusCode < 400))
+        return receiveBytes;
+
+    if (receiveBytes) {
+        callDelegate([this, buffer = WTFMove(buffer)](CurlRequestDelegate* delegate) mutable {
+            if (delegate)
+                delegate->curlDidReceiveBuffer(WTFMove(buffer));
+        });
+    }
+
+    return receiveBytes;
+}
+
+void CurlRequest::didCompleteTransfer(CURLcode result)
+{
+    if (m_cancelled) {
+        m_curlHandle = nullptr;
+        return;
+    }
+
+    if (result == CURLE_OK) {
+        if (auto metrics = m_curlHandle->getNetworkLoadMetrics())
+            m_networkLoadMetrics = *metrics;
+
+        callDelegate([this](CurlRequestDelegate* delegate) {
+            if (delegate)
+                delegate->curlDidComplete();
+        });
+    } else {
+        auto resourceError = ResourceError::httpError(result, m_request.url());
+        if (m_sslVerifier.sslErrors())
+            resourceError.setSslErrors(m_sslVerifier.sslErrors());
+
+        callDelegate([this, error = resourceError.isolatedCopy()](CurlRequestDelegate* delegate) {
+            if (delegate)
+                delegate->curlDidFailWithError(error);
+        });
+    }
+
+    m_formDataStream = nullptr;
+    m_curlHandle = nullptr;
+}
+
+void CurlRequest::didCancelTransfer()
+{
+    m_formDataStream = nullptr;
+    m_curlHandle = nullptr;
+}
+
+void CurlRequest::resolveBlobReferences(ResourceRequest& request)
+{
+    ASSERT(isMainThread());
+
+    RefPtr<FormData> formData = request.httpBody();
+    if (!formData)
+        return;
+
+    // Resolve the blob elements so the formData can correctly report it's size.
+    formData = formData->resolveBlobReferences();
+    request.setHTTPBody(WTFMove(formData));
+}
+
+void CurlRequest::setupPUT(ResourceRequest& request)
+{
+    m_curlHandle->enableHttpPutRequest();
+
+    // Disable the Expect: 100 continue header
+    m_curlHandle->removeRequestHeader("Expect");
+
+    auto numElements = request.httpBody()->elements().size();
+    if (!numElements)
+        return;
+
+    setupFormData(request, false);
+}
+
+void CurlRequest::setupPOST(ResourceRequest& request)
+{
+    m_curlHandle->enableHttpPostRequest();
+
+    auto numElements = request.httpBody()->elements().size();
+    if (!numElements)
+        return;
+
+    // Do not stream for simple POST data
+    if (numElements == 1) {
+        m_postBuffer = request.httpBody()->flatten();
+        if (m_postBuffer.size())
+            m_curlHandle->setPostFields(m_postBuffer.data(), m_postBuffer.size());
+    } else
+        setupFormData(request, true);
+}
+
+void CurlRequest::setupFormData(ResourceRequest& request, bool isPostRequest)
+{
+    static auto maxCurlOffT = CurlHandle::maxCurlOffT();
+
+    // Obtain the total size of the form data
+    curl_off_t size = 0;
+    bool chunkedTransfer = false;
+    auto elements = request.httpBody()->elements();
+
+    for (auto element : elements) {
+        if (element.m_type == FormDataElement::Type::EncodedFile) {
+            long long fileSizeResult;
+            if (getFileSize(element.m_filename, fileSizeResult)) {
+                if (fileSizeResult > maxCurlOffT) {
+                    // File size is too big for specifying it to cURL
+                    chunkedTransfer = true;
+                    break;
+                }
+                size += fileSizeResult;
+            } else {
+                chunkedTransfer = true;
+                break;
+            }
+        } else
+            size += element.m_data.size();
+    }
+
+    // cURL guesses that we want chunked encoding as long as we specify the header
+    if (chunkedTransfer)
+        m_curlHandle->appendRequestHeader("Transfer-Encoding: chunked");
+    else {
+        if (isPostRequest)
+            m_curlHandle->setPostFieldLarge(size);
+        else
+            m_curlHandle->setInFileSizeLarge(size);
+    }
+
+    m_formDataStream = std::make_unique<FormDataStream>();
+    m_formDataStream->setHTTPBody(request.httpBody());
+
+    m_curlHandle->setReadCallbackFunction(willSendDataCallback, this);
+}
+
+void CurlRequest::invokeDidReceiveResponseForFile(URL& url)
+{
+    // Since the code in didReceiveHeader() will not have run for local files
+    // the code to set the URL and fire didReceiveResponse is never run,
+    // which means the ResourceLoader's response does not contain the URL.
+    // Run the code here for local files to resolve the issue.
+
+    ASSERT(isMainThread());
+    ASSERT(url.isLocalFile());
+
+    m_response.url = ""
+    m_response.statusCode = 200;
+
+    // Determine the MIME type based on the path.
+    m_response.headers.append(String("Content-Type: " + MIMETypeRegistry::getMIMETypeForPath(m_response.url)));
+
+    if (!m_isSyncRequest) {
+        // DidReceiveResponse must not be called immediately
+        CurlJobManager::singleton().callOnJobThread([protectedThis = makeRef(*this)]() {
+            protectedThis->invokeDidReceiveResponse();
+        });
+    } else
+        invokeDidReceiveResponse();
+}
+
+void CurlRequest::invokeDidReceiveResponse()
+{
+    callDelegate([this, response = m_response.isolatedCopy()](CurlRequestDelegate* delegate) {
+        if (delegate)
+            delegate->curlDidReceiveResponse(response);
+    });
+}
+
+void CurlRequest::setPaused(bool paused)
+{
+    if (m_cancelled)
+        return;
+
+    if (paused == m_isPaused)
+        return;
+
+    m_isPaused = paused;
+
+    if (!m_curlHandle)
+        return;
+
+    if (!m_isSyncRequest && isMainThread()) {
+        CurlJobManager::singleton().callOnJobThread([protectedThis = makeRef(*this), paused = m_isPaused]() {
+            if (protectedThis->m_cancelled)
+                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.
+                protectedThis->cancel();
+            }
+        });
+    } else {
+        auto error = m_curlHandle->pause(m_isPaused ? CURLPAUSE_ALL : CURLPAUSE_CONT);
+        if ((error != CURLE_OK) && !m_isPaused)
+            cancel();
+    }
+}
+
+CURLcode CurlRequest::willSetupSslCtxCallback(CURL*, void* sslCtx, void* userData)
+{
+    return static_cast<CurlRequest*>(userData)->willSetupSslCtx(sslCtx);
+}
+
+size_t CurlRequest::willSendDataCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* userData)
+{
+    return static_cast<CurlRequest*>(userData)->willSendData(ptr, blockSize, numberOfBlocks);
+}
+
+size_t CurlRequest::didReceiveHeaderCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* userData)
+{
+    return static_cast<CurlRequest*>(userData)->didReceiveHeader(String(ptr, blockSize * numberOfBlocks));
+}
+
+size_t CurlRequest::didReceiveDataCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* userData)
+{
+    return static_cast<CurlRequest*>(userData)->didReceiveData(SharedBuffer::create(ptr, blockSize * numberOfBlocks));
+}
+
+}
+
+#endif

Added: trunk/Source/WebCore/platform/network/curl/CurlRequest.h (0 => 222665)


--- trunk/Source/WebCore/platform/network/curl/CurlRequest.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/network/curl/CurlRequest.h	2017-09-29 21:19:32 UTC (rev 222665)
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2017 Sony Interactive Entertainment Inc.
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include "CurlJobManager.h"
+#include "CurlResponse.h"
+#include "CurlSSLVerifier.h"
+#include "FormDataStreamCurl.h"
+#include "NetworkLoadMetrics.h"
+#include "ResourceRequest.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class CurlRequestDelegate;
+class ResourceError;
+class SharedBuffer;
+
+class CurlRequest : public ThreadSafeRefCounted<CurlRequest>, public CurlJobClient {
+    WTF_MAKE_NONCOPYABLE(CurlRequest);
+
+public:
+    CurlRequest(const ResourceRequest&, CurlRequestDelegate* = nullptr, bool shouldSuspend = false);
+    virtual ~CurlRequest() { }
+
+    void setDelegate(CurlRequestDelegate* delegate) { m_delegate = delegate;  }
+    void setUserPass(const String&, const String&);
+
+    void start(bool isSyncRequest = false);
+    void cancel();
+    void suspend();
+    void resume();
+
+    bool isSyncRequest() { return m_isSyncRequest; }
+
+    NetworkLoadMetrics getNetworkLoadMetrics() { return m_networkLoadMetrics.isolatedCopy(); }
+
+private:
+    void retain() override { ref(); }
+    void release() override { deref(); }
+    CURL* handle() override { return m_curlHandle ? m_curlHandle->handle() : nullptr; }
+
+    void startWithJobManager();
+
+    void callDelegate(WTF::Function<void(CurlRequestDelegate*)>);
+
+    // Transfer processing of Request body, Response header/body
+    // Called by worker thread in case of async, main thread in case of sync.
+    CURL* setupTransfer() override;
+    CURLcode willSetupSslCtx(void*);
+    size_t willSendData(char*, size_t, size_t);
+    size_t didReceiveHeader(String&&);
+    size_t didReceiveData(Ref<SharedBuffer>&&);
+    void didCompleteTransfer(CURLcode) override;
+    void didCancelTransfer() override;
+
+    // For POST and PUT method 
+    void resolveBlobReferences(ResourceRequest&);
+    void setupPOST(ResourceRequest&);
+    void setupPUT(ResourceRequest&);
+    void setupFormData(ResourceRequest&, bool);
+
+    // Processing for DidResourceResponse
+    void invokeDidReceiveResponseForFile(URL&);
+    void invokeDidReceiveResponse();
+    void setPaused(bool);
+
+    // Callback functions for curl
+    static CURLcode willSetupSslCtxCallback(CURL*, void*, void*);
+    static size_t willSendDataCallback(char*, size_t, size_t, void*);
+    static size_t didReceiveHeaderCallback(char*, size_t, size_t, void*);
+    static size_t didReceiveDataCallback(char*, size_t, size_t, void*);
+
+
+    std::atomic<CurlRequestDelegate*> m_delegate { };
+    bool m_isSyncRequest { false };
+    bool m_cancelled { false };
+
+    // Used by worker thread in case of async, and main thread in case of sync.
+    ResourceRequest m_request;
+    String m_user;
+    String m_password;
+    bool m_shouldSuspend { false };
+
+    std::unique_ptr<CurlHandle> m_curlHandle;
+    std::unique_ptr<FormDataStream> m_formDataStream;
+    Vector<char> m_postBuffer;
+    CurlSSLVerifier m_sslVerifier;
+    CurlResponse m_response;
+
+    bool m_isPaused { false };
+
+    NetworkLoadMetrics m_networkLoadMetrics;
+};
+
+}

Added: trunk/Source/WebCore/platform/network/curl/CurlRequestDelegate.h (0 => 222665)


--- trunk/Source/WebCore/platform/network/curl/CurlRequestDelegate.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/network/curl/CurlRequestDelegate.h	2017-09-29 21:19:32 UTC (rev 222665)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 Sony Interactive Entertainment Inc.
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <wtf/Ref.h>
+
+namespace WebCore {
+
+class CurlResponse;
+class ResourceError;
+class SharedBuffer;
+
+class CurlRequestDelegate {
+public:
+    virtual void curlDidReceiveResponse(const CurlResponse&) = 0;
+    virtual void curlDidReceiveBuffer(Ref<SharedBuffer>&&) = 0;
+    virtual void curlDidComplete() = 0;
+    virtual void curlDidFailWithError(const ResourceError&) = 0;
+};
+
+}

Modified: trunk/Source/WebCore/platform/network/curl/ResourceHandleCurl.cpp (222664 => 222665)


--- trunk/Source/WebCore/platform/network/curl/ResourceHandleCurl.cpp	2017-09-29 21:14:09 UTC (rev 222664)
+++ trunk/Source/WebCore/platform/network/curl/ResourceHandleCurl.cpp	2017-09-29 21:19:32 UTC (rev 222665)
@@ -32,19 +32,12 @@
 
 #if USE(CURL)
 
-#include "CachedResourceLoader.h"
 #include "CredentialStorage.h"
-#include "CurlCacheManager.h"
 #include "CurlContext.h"
-#include "CurlJobManager.h"
-#include "CurlSSLHandle.h"
 #include "FileSystem.h"
 #include "Logging.h"
-#include "MIMETypeRegistry.h"
-#include "NetworkingContext.h"
 #include "ResourceHandleInternal.h"
 #include "SynchronousLoaderClient.h"
-#include <wtf/text/Base64.h>
 
 namespace WebCore {
 
@@ -78,7 +71,8 @@
 
 void ResourceHandle::cancel()
 {
-    d->m_delegate->cancel();
+    if (d->m_delegate)
+        d->m_delegate->cancel();
 }
 
 #if OS(WINDOWS)
@@ -114,7 +108,8 @@
 {
     ASSERT(isMainThread());
 
-    d->m_delegate->setDefersLoading(defers);
+    if (d->m_delegate)
+        d->m_delegate->setDefersLoading(defers);
 }
 
 bool ResourceHandle::shouldUseCredentialStorage()
@@ -136,7 +131,8 @@
             urlToStore = challenge.failureResponse().url();
         CredentialStorage::defaultCredentialStorage().set(partition, credential, challenge.protectionSpace(), urlToStore);
         
-        d->m_delegate->setAuthentication(credential.user(), credential.password());
+        if (d->m_delegate)
+            d->m_delegate->setAuthentication(credential.user(), credential.password());
 
         d->m_user = String();
         d->m_pass = String();
@@ -161,7 +157,8 @@
                     CredentialStorage::defaultCredentialStorage().set(partition, credential, challenge.protectionSpace(), challenge.failureResponse().url());
                 }
 
-                d->m_delegate->setAuthentication(credential.user(), credential.password());
+                if (d->m_delegate)
+                    d->m_delegate->setAuthentication(credential.user(), credential.password());
                 return;
             }
         }
@@ -168,9 +165,11 @@
     }
 
     d->m_currentWebChallenge = challenge;
-    
-    if (client())
+
+    if (client()) {
+        auto protectedThis = makeRef(*this);
         client()->didReceiveAuthenticationChallenge(this, d->m_currentWebChallenge);
+    }
 }
 
 void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge, const Credential& credential)
@@ -194,7 +193,9 @@
         }
     }
 
-    d->m_delegate->setAuthentication(credential.user(), credential.password());
+    if (d->m_delegate)
+        d->m_delegate->setAuthentication(credential.user(), credential.password());
+
     clearAuthentication();
 }
 
@@ -205,7 +206,9 @@
     if (challenge != d->m_currentWebChallenge)
         return;
 
-    d->m_delegate->setAuthentication("", "");
+    if (d->m_delegate)
+        d->m_delegate->setAuthentication("", "");
+
     clearAuthentication();
 }
 
@@ -216,8 +219,10 @@
     if (challenge != d->m_currentWebChallenge)
         return;
 
-    if (client())
+    if (client()) {
+        auto protectedThis = makeRef(*this);
         client()->receivedCancellation(this, challenge);
+    }
 }
 
 void ResourceHandle::receivedRequestToPerformDefaultHandling(const AuthenticationChallenge&)

Modified: trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.cpp (222664 => 222665)


--- trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.cpp	2017-09-29 21:14:09 UTC (rev 222664)
+++ trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.cpp	2017-09-29 21:19:32 UTC (rev 222665)
@@ -32,17 +32,15 @@
 
 #if USE(CURL)
 
+#include "AuthenticationChallenge.h"
 #include "CredentialStorage.h"
 #include "CurlCacheManager.h"
+#include "CurlRequest.h"
 #include "HTTPParsers.h"
-#include "MIMETypeRegistry.h"
 #include "MultipartHandle.h"
-#include "ResourceHandle.h"
 #include "ResourceHandleInternal.h"
 #include "SharedBuffer.h"
 #include "TextEncoding.h"
-#include "URL.h"
-#include <wtf/MainThread.h>
 #include <wtf/text/Base64.h>
 
 namespace WebCore {
@@ -50,7 +48,7 @@
 ResourceHandleCurlDelegate::ResourceHandleCurlDelegate(ResourceHandle* handle)
     : m_handle(handle)
     , m_firstRequest(handle->firstRequest().isolatedCopy())
-    , m_customHTTPHeaderFields(m_firstRequest.httpHeaderFields().isolatedCopy())
+    , m_currentRequest(handle->firstRequest().isolatedCopy())
     , m_shouldUseCredentialStorage(handle->shouldUseCredentialStorage())
     , m_user(handle->getInternal()->m_user.isolatedCopy())
     , m_pass(handle->getInternal()->m_pass.isolatedCopy())
@@ -57,25 +55,13 @@
     , m_initialCredential(handle->getInternal()->m_initialCredential)
     , m_defersLoading(handle->getInternal()->m_defersLoading)
 {
-    const URL& url = ""
 
-    if (m_customHTTPHeaderFields.size()) {
-        auto& cache = CurlCacheManager::getInstance();
-        bool hasCacheHeaders = m_customHTTPHeaderFields.contains(HTTPHeaderName::IfModifiedSince) || m_customHTTPHeaderFields.contains(HTTPHeaderName::IfNoneMatch);
-        if (!hasCacheHeaders && cache.isCached(url)) {
-            cache.addCacheEntryClient(url, m_handle);
-            // append additional cache information
-            for (auto entry : cache.requestHeaders(url))
-                m_customHTTPHeaderFields.set(entry.key, entry.value);
-            m_addedCacheValidationHeaders = true;
-        }
-    }
-
-    setupAuthentication();
 }
 
 ResourceHandleCurlDelegate::~ResourceHandleCurlDelegate()
 {
+    if (m_curlRequest)
+        m_curlRequest->setDelegate(nullptr);
 }
 
 bool ResourceHandleCurlDelegate::hasHandle() const
@@ -88,76 +74,66 @@
     m_handle = nullptr;
 }
 
-void ResourceHandleCurlDelegate::start(bool isSyncRequest)
+bool ResourceHandleCurlDelegate::start()
 {
-    m_isSyncRequest = isSyncRequest;
+    ASSERT(isMainThread());
 
-    if (!m_isSyncRequest) {
-        // For asynchronous, use CurlJobManager. Curl processes runs on sub thread.
-        CurlJobManager::singleton().add(this);
-    } else {
-        // For synchronous, does not use CurlJobManager. Curl processes runs on main thread.
-        retain();
-        setupTransfer();
+    auto credential = getCredential(m_currentRequest, false);
 
-        // curl_easy_perform blocks until the transfer is finished.
-        CURLcode resultCode = m_curlHandle->perform();
-        didCompleteTransfer(resultCode);
-        release();
-    }
+    m_curlRequest = createCurlRequest(m_currentRequest);
+    m_curlRequest->setUserPass(credential.first, credential.second);
+    m_curlRequest->start();
+
+    return true;
 }
 
 void ResourceHandleCurlDelegate::cancel()
 {
+    ASSERT(isMainThread());
+
     releaseHandle();
 
-    if (!m_isSyncRequest)
-        CurlJobManager::singleton().cancel(this);
+    if (!m_curlRequest)
+        m_curlRequest->cancel();
 }
 
 void ResourceHandleCurlDelegate::setDefersLoading(bool defers)
 {
+    ASSERT(isMainThread());
+
     if (defers == m_defersLoading)
         return;
 
     m_defersLoading = defers;
 
-    auto action = "" = makeRef(*this)]() {
-        if (!protectedThis->m_curlHandle)
-            return;
+    if (!m_curlRequest)
+        return;
 
-        if (protectedThis->m_defersLoading) {
-            CURLcode error = protectedThis->m_curlHandle->pause(CURLPAUSE_ALL);
-            // If we could not defer the handle, so don't do it.
-            if (error != CURLE_OK)
-                return;
-        } else {
-            CURLcode error = protectedThis->m_curlHandle->pause(CURLPAUSE_CONT);
-            if (error != CURLE_OK) {
-                // Restarting the handle has failed so just cancel it.
-                protectedThis->m_handle->cancel();
-            }
-        }
-    };
-
-    CurlJobManager::singleton().callOnJobThread(WTFMove(action));
+    if (m_defersLoading)
+        m_curlRequest->suspend();
+    else
+        m_curlRequest->resume();
 }
 
-void ResourceHandleCurlDelegate::setAuthentication(const String& user, const String& pass)
+void ResourceHandleCurlDelegate::setAuthentication(const String& user, const String& password)
 {
-    auto action = "" = makeRef(*this), user = user.isolatedCopy(), pass = pass.isolatedCopy()]() {
-        protectedThis->m_user = user;
-        protectedThis->m_pass = pass;
-        if (protectedThis->m_curlHandle)
-            protectedThis->m_curlHandle->setHttpAuthUserPass(user, pass);
-    };
+    ASSERT(isMainThread());
 
-    CurlJobManager::singleton().callOnJobThread(WTFMove(action));
+    if (!m_curlRequest)
+        return;
+
+    bool isSyncRequest = m_curlRequest->isSyncRequest();
+    m_curlRequest->cancel();
+    m_curlRequest->setDelegate(nullptr);
+
+    m_curlRequest = createCurlRequest(m_currentRequest);
+    m_curlRequest->setUserPass(user, password);
+    m_curlRequest->start(isSyncRequest);
 }
 
 void ResourceHandleCurlDelegate::dispatchSynchronousJob()
 {
-    if (m_firstRequest.url().protocolIsData()) {
+    if (m_currentRequest.url().protocolIsData()) {
         handleDataURL();
         return;
     }
@@ -167,162 +143,57 @@
     // and we would assert so force defersLoading to be false.
     m_defersLoading = false;
 
-    start(true);
+    m_curlRequest = createCurlRequest(m_currentRequest);
+    m_curlRequest->start(true);
 }
 
-void ResourceHandleCurlDelegate::retain()
+RefPtr<CurlRequest> ResourceHandleCurlDelegate::createCurlRequest(ResourceRequest& request)
 {
-    ref();
-}
+    ASSERT(isMainThread());
 
-void ResourceHandleCurlDelegate::release()
-{
-    deref();
-}
+    // CurlCache : append additional cache information
+    m_addedCacheValidationHeaders = false;
 
-CURL* ResourceHandleCurlDelegate::setupTransfer()
-{
-    m_curlHandle = std::make_unique<CurlHandle>();
-    m_curlHandle->initialize();
+    bool hasCacheHeaders = request.httpHeaderFields().contains(HTTPHeaderName::IfModifiedSince) || request.httpHeaderFields().contains(HTTPHeaderName::IfNoneMatch);
+    if (!hasCacheHeaders) {
+        auto& cache = CurlCacheManager::getInstance();
+        URL cacheUrl = request.url();
+        cacheUrl.removeFragmentIdentifier();
 
-    if (m_defersLoading) {
-        CURLcode error = m_curlHandle->pause(CURLPAUSE_ALL);
-        // If we did not pause the handle, we would ASSERT in the
-        // header callback. So just assert here.
-        ASSERT_UNUSED(error, error == CURLE_OK);
-    }
+        if (cache.isCached(cacheUrl)) {
+            cache.addCacheEntryClient(cacheUrl, m_handle);
 
-#ifndef NDEBUG
-    m_curlHandle->enableVerboseIfUsed();
-    m_curlHandle->enableStdErrIfUsed();
-#endif
+            for (auto entry : cache.requestHeaders(cacheUrl))
+                request.addHTTPHeaderField(entry.key, entry.value);
 
-    auto& sslHandle = CurlContext::singleton().sslHandle();
-
-    m_curlHandle->setSslVerifyPeer(CurlHandle::VerifyPeer::Enable);
-    m_curlHandle->setSslVerifyHost(CurlHandle::VerifyHost::StrictNameCheck);
-    m_curlHandle->setWriteCallbackFunction(didReceiveDataCallback, this);
-    m_curlHandle->setHeaderCallbackFunction(didReceiveHeaderCallback, this);
-    m_curlHandle->enableAutoReferer();
-    m_curlHandle->enableFollowLocation();
-    m_curlHandle->enableHttpAuthentication(CURLAUTH_ANY);
-    m_curlHandle->enableShareHandle();
-    m_curlHandle->enableTimeout();
-    m_curlHandle->enableAllowedProtocols();
-
-    auto sslClientCertificate = sslHandle.getSSLClientCertificate(m_firstRequest.url().host());
-    if (sslClientCertificate) {
-        m_curlHandle->setSslCert(sslClientCertificate->first.utf8().data());
-        m_curlHandle->setSslCertType("P12");
-        m_curlHandle->setSslKeyPassword(sslClientCertificate->second.utf8().data());
-    }
-
-    if (sslHandle.shouldIgnoreSSLErrors())
-        m_curlHandle->setSslVerifyPeer(CurlHandle::VerifyPeer::Disable);
-    else
-        m_curlHandle->setSslCtxCallbackFunction(willSetupSslCtxCallback, this);
-
-    m_curlHandle->setCACertPath(sslHandle.getCACertPath());
-
-    m_curlHandle->enableAcceptEncoding();
-    m_curlHandle->setUrl(m_firstRequest.url());
-    m_curlHandle->enableCookieJarIfExists();
-
-    if (m_customHTTPHeaderFields.size())
-        m_curlHandle->appendRequestHeaders(m_customHTTPHeaderFields);
-
-    String method = m_firstRequest.httpMethod();
-    if ("GET" == method)
-        m_curlHandle->enableHttpGetRequest();
-    else if ("POST" == method)
-        setupPOST();
-    else if ("PUT" == method)
-        setupPUT();
-    else if ("HEAD" == method)
-        m_curlHandle->enableHttpHeadRequest();
-    else {
-        m_curlHandle->setHttpCustomRequest(method);
-        setupPUT();
-    }
-
-    applyAuthentication();
-
-    m_curlHandle->enableProxyIfExists();
-
-    return m_curlHandle->handle();
-}
-
-void ResourceHandleCurlDelegate::didCompleteTransfer(CURLcode result)
-{
-    if (result == CURLE_OK) {
-        NetworkLoadMetrics networkLoadMetrics = getNetworkLoadMetrics();
-
-        if (isMainThread())
-            didFinish(networkLoadMetrics);
-        else {
-            callOnMainThread([protectedThis = makeRef(*this), metrics = networkLoadMetrics.isolatedCopy()] {
-                if (!protectedThis->m_handle)
-                    return;
-                protectedThis->didFinish(metrics);
-            });
+            m_addedCacheValidationHeaders = true;
         }
-    } else {
-        ResourceError resourceError = ResourceError::httpError(result, m_firstRequest.url());
-        if (m_sslVerifier.sslErrors())
-            resourceError.setSslErrors(m_sslVerifier.sslErrors());
-
-        if (isMainThread())
-            didFail(resourceError);
-        else {
-            callOnMainThread([protectedThis = makeRef(*this), error = resourceError.isolatedCopy()] {
-                if (!protectedThis->m_handle)
-                    return;
-                protectedThis->didFail(error);
-            });
-        }
     }
 
-    m_formDataStream = nullptr;
-    m_curlHandle = nullptr;
+    return adoptRef(new CurlRequest(request, this, m_defersLoading));
 }
 
-void ResourceHandleCurlDelegate::didCancelTransfer()
+bool ResourceHandleCurlDelegate::cancelledOrClientless()
 {
-    m_formDataStream = nullptr;
-    m_curlHandle = nullptr;
-}
+    if (!m_handle)
+        return true;
 
-ResourceResponse& ResourceHandleCurlDelegate::response()
-{
-    return m_handle->getInternal()->m_response;
+    return !m_handle->client();
 }
 
-void ResourceHandleCurlDelegate::setupAuthentication()
+void ResourceHandleCurlDelegate::curlDidReceiveResponse(const CurlResponse& receivedResponse)
 {
-    // m_user/m_pass are credentials given manually, for instance, by the arguments passed to XMLHttpRequest.open().
-    String partition = m_firstRequest.cachePartition();
+    ASSERT(isMainThread());
+    ASSERT(!m_defersLoading);
 
-    if (m_shouldUseCredentialStorage) {
-        if (m_user.isEmpty() && m_pass.isEmpty()) {
-            // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication, 
-            // try and reuse the credential preemptively, as allowed by RFC 2617.
-            m_initialCredential = CredentialStorage::defaultCredentialStorage().get(partition, m_firstRequest.url());
-        } else {
-            // If there is already a protection space known for the URL, update stored credentials
-            // before sending a request. This makes it possible to implement logout by sending an
-            // XMLHttpRequest with known incorrect credentials, and aborting it immediately (so that
-            // an authentication dialog doesn't pop up).
-            CredentialStorage::defaultCredentialStorage().set(partition, Credential(m_user, m_pass, CredentialPersistenceNone), m_firstRequest.url());
-        }
-    }
-}
+    if (cancelledOrClientless())
+        return;
 
-void ResourceHandleCurlDelegate::didReceiveAllHeaders(const CurlResponse& receivedResponse)
-{
-    ASSERT(isMainThread());
-
     m_handle->getInternal()->m_response = ResourceResponse(receivedResponse);
 
+    if (m_curlRequest)
+        m_handle->getInternal()->m_response.setDeprecatedNetworkLoadMetrics(m_curlRequest->getNetworkLoadMetrics());
+
     if (response().isMultipart()) {
         String boundary;
         bool parsed = MultipartHandle::extractBoundary(response().httpHeaderField(HTTPHeaderName::ContentType), boundary);
@@ -346,7 +217,9 @@
 
             return;
         }
-    } else if (response().isUnauthorized()) {
+    }
+
+    if (response().isUnauthorized()) {
         AuthenticationChallenge challenge(receivedResponse, m_authFailureCount, response(), m_handle);
         m_handle->didReceiveAuthenticationChallenge(challenge);
         m_authFailureCount++;
@@ -353,12 +226,12 @@
         return;
     }
 
-    m_didNotifyResponse = true;
-
     if (m_handle->client()) {
         if (response().isNotModified()) {
-            const String& url = ""
-            if (CurlCacheManager::getInstance().getCachedResponse(url, response())) {
+            URL cacheUrl = m_currentRequest.url();
+            cacheUrl.removeFragmentIdentifier();
+
+            if (CurlCacheManager::getInstance().getCachedResponse(cacheUrl, response())) {
                 if (m_addedCacheValidationHeaders) {
                     response().setHTTPStatusCode(200);
                     response().setHTTPStatusText("OK");
@@ -365,17 +238,18 @@
                 }
             }
         }
+
         CurlCacheManager::getInstance().didReceiveResponse(*m_handle, response());
         m_handle->client()->didReceiveResponse(m_handle, ResourceResponse(response()));
     }
 }
 
-void ResourceHandleCurlDelegate::didReceiveContentData(Ref<SharedBuffer>&& buffer)
+void ResourceHandleCurlDelegate::curlDidReceiveBuffer(Ref<SharedBuffer>&& buffer)
 {
     ASSERT(isMainThread());
 
-    if (!m_didNotifyResponse)
-        handleLocalReceiveResponse();
+    if (cancelledOrClientless())
+        return;
 
     if (m_multipartHandle)
         m_multipartHandle->contentReceived(buffer->data(), buffer->size());
@@ -385,65 +259,16 @@
     }
 }
 
-void ResourceHandleCurlDelegate::handleLocalReceiveResponse()
+void ResourceHandleCurlDelegate::curlDidComplete()
 {
     ASSERT(isMainThread());
 
-    // since the code in headerCallback will not have run for local files
-    // the code to set the URL and fire didReceiveResponse is never run,
-    // which means the ResourceLoader's response does not contain the URL.
-    // Run the code here for local files to resolve the issue.
-    // TODO: See if there is a better approach for handling this.
-    URL url = ""
-    ASSERT(url.isValid());
-    response().setURL(url);
-
-    // Determine the MIME type based on the path.
-    response().setMimeType(MIMETypeRegistry::getMIMETypeForPath(url));
-
-    m_didNotifyResponse = true;
-
-    if (m_handle->client())
-        m_handle->client()->didReceiveResponse(m_handle, ResourceResponse(response()));
-}
-
-void ResourceHandleCurlDelegate::prepareSendData(char* buffer, size_t blockSize, size_t numberOfBlocks)
-{
-    ASSERT(isMainThread());
-    ASSERT(!m_sendBytes);
-
-    std::unique_lock<Lock> lock(m_workerThreadMutex);
-
-    if (!m_formDataStream || !m_formDataStream->hasMoreElements()) {
-        m_workerThreadConditionVariable.notifyOne();
+    if (cancelledOrClientless())
         return;
-    }
 
-    size_t size = m_formDataStream->read(buffer, blockSize, numberOfBlocks);
-    if (!size) {
-        // Something went wrong so cancel the job.
-        m_handle->cancel();
-        m_workerThreadConditionVariable.notifyOne();
-        return;
-    }
+    if (m_curlRequest)
+        m_handle->getInternal()->m_response.setDeprecatedNetworkLoadMetrics(m_curlRequest->getNetworkLoadMetrics());
 
-    m_sendBytes = size;
-    m_workerThreadConditionVariable.notifyOne();
-}
-
-void ResourceHandleCurlDelegate::didFinish(NetworkLoadMetrics networkLoadMetrics)
-{
-    response().setDeprecatedNetworkLoadMetrics(networkLoadMetrics);
-
-    if (!m_handle)
-        return;
-
-    if (!m_didNotifyResponse) {
-        handleLocalReceiveResponse();
-        if (!m_handle)
-            return;
-    }
-
     if (m_multipartHandle)
         m_multipartHandle->contentEnded();
 
@@ -453,17 +278,22 @@
     }
 }
 
-void ResourceHandleCurlDelegate::didFail(const ResourceError& resourceError)
+void ResourceHandleCurlDelegate::curlDidFailWithError(const ResourceError& resourceError)
 {
-    if (!m_handle)
+    ASSERT(isMainThread());
+
+    if (cancelledOrClientless())
         return;
 
-    if (m_handle->client()) {
-        CurlCacheManager::getInstance().didFail(*m_handle);
-        m_handle->client()->didFail(m_handle, resourceError);
-    }
+    CurlCacheManager::getInstance().didFail(*m_handle);
+    m_handle->client()->didFail(m_handle, resourceError);
 }
 
+ResourceResponse& ResourceHandleCurlDelegate::response()
+{
+    return m_handle->getInternal()->m_response;
+}
+
 void ResourceHandleCurlDelegate::handleDataURL()
 {
     ASSERT(m_firstRequest.url().protocolIsData());
@@ -526,99 +356,25 @@
         m_handle->client()->didFinishLoading(m_handle);
 }
 
-void ResourceHandleCurlDelegate::setupPOST()
+std::pair<String, String> ResourceHandleCurlDelegate::getCredential(ResourceRequest& request, bool redirect)
 {
-    m_curlHandle->enableHttpPostRequest();
+    // m_user/m_pass are credentials given manually, for instance, by the arguments passed to XMLHttpRequest.open().
+    String partition = request.cachePartition();
 
-    size_t numElements = getFormElementsCount();
-    if (!numElements)
-        return;
-
-    // Do not stream for simple POST data
-    if (numElements == 1) {
-        m_postBytes = m_firstRequest.httpBody()->flatten();
-        if (m_postBytes.size())
-            m_curlHandle->setPostFields(m_postBytes.data(), m_postBytes.size());
-        return;
+    if (m_shouldUseCredentialStorage) {
+        if (m_user.isEmpty() && m_pass.isEmpty()) {
+            // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication, 
+            // try and reuse the credential preemptively, as allowed by RFC 2617.
+            m_initialCredential = CredentialStorage::defaultCredentialStorage().get(partition, request.url());
+        } else if (!redirect) {
+            // If there is already a protection space known for the URL, update stored credentials
+            // before sending a request. This makes it possible to implement logout by sending an
+            // XMLHttpRequest with known incorrect credentials, and aborting it immediately (so that
+            // an authentication dialog doesn't pop up).
+            CredentialStorage::defaultCredentialStorage().set(partition, Credential(m_user, m_pass, CredentialPersistenceNone), request.url());
+        }
     }
 
-    setupFormData(true);
-}
-
-void ResourceHandleCurlDelegate::setupPUT()
-{
-    m_curlHandle->enableHttpPutRequest();
-
-    // Disable the Expect: 100 continue header
-    m_curlHandle->removeRequestHeader("Expect");
-
-    size_t numElements = getFormElementsCount();
-    if (!numElements)
-        return;
-
-    setupFormData(false);
-}
-
-size_t ResourceHandleCurlDelegate::getFormElementsCount()
-{
-    RefPtr<FormData> formData = m_firstRequest.httpBody();
-    if (!formData)
-        return 0;
-
-    // Resolve the blob elements so the formData can correctly report it's size.
-    formData = formData->resolveBlobReferences();
-    size_t size = formData->elements().size();
-    m_firstRequest.setHTTPBody(WTFMove(formData));
-    return size;
-}
-
-void ResourceHandleCurlDelegate::setupFormData(bool isPostRequest)
-{
-    Vector<FormDataElement> elements = m_firstRequest.httpBody()->elements();
-    size_t numElements = elements.size();
-
-    static const long long maxCurlOffT = m_curlHandle->maxCurlOffT();
-
-    // Obtain the total size of the form data
-    curl_off_t size = 0;
-    bool chunkedTransfer = false;
-    for (size_t i = 0; i < numElements; i++) {
-        FormDataElement element = elements[i];
-        if (element.m_type == FormDataElement::Type::EncodedFile) {
-            long long fileSizeResult;
-            if (getFileSize(element.m_filename, fileSizeResult)) {
-                if (fileSizeResult > maxCurlOffT) {
-                    // File size is too big for specifying it to cURL
-                    chunkedTransfer = true;
-                    break;
-                }
-                size += fileSizeResult;
-            } else {
-                chunkedTransfer = true;
-                break;
-            }
-        } else
-            size += elements[i].m_data.size();
-    }
-
-    // cURL guesses that we want chunked encoding as long as we specify the header
-    if (chunkedTransfer)
-        m_curlHandle->appendRequestHeader("Transfer-Encoding: chunked");
-    else {
-        if (isPostRequest)
-            m_curlHandle->setPostFieldLarge(size);
-        else
-            m_curlHandle->setInFileSizeLarge(size);
-    }
-
-    m_formDataStream = std::make_unique<FormDataStream>();
-    m_formDataStream->setHTTPBody(m_firstRequest.httpBody());
-
-    m_curlHandle->setReadCallbackFunction(willSendDataCallback, this);
-}
-
-void ResourceHandleCurlDelegate::applyAuthentication()
-{
     String user = m_user;
     String password = m_pass;
 
@@ -625,208 +381,14 @@
     if (!m_initialCredential.isEmpty()) {
         user = m_initialCredential.user();
         password = m_initialCredential.password();
-        m_curlHandle->enableHttpAuthentication(CURLAUTH_BASIC);
     }
 
-    // It seems we need to set CURLOPT_USERPWD even if username and password is empty.
-    // Otherwise cURL will not automatically continue with a new request after a 401 response.
+    if (user.isEmpty() && password.isEmpty())
+        return std::pair<String, String>("", "");
 
-    // curl CURLOPT_USERPWD expects username:password
-    m_curlHandle->setHttpAuthUserPass(user, password);
+    return std::pair<String, String>(user, password);
 }
 
-NetworkLoadMetrics ResourceHandleCurlDelegate::getNetworkLoadMetrics()
-{
-    NetworkLoadMetrics networkLoadMetrics;
-    if (auto metrics = m_curlHandle->getNetworkLoadMetrics())
-        networkLoadMetrics = *metrics;
-
-    return networkLoadMetrics;
-}
-
-CURLcode ResourceHandleCurlDelegate::willSetupSslCtx(void* sslCtx)
-{
-    m_sslVerifier.setCurlHandle(m_curlHandle.get());
-    m_sslVerifier.setHostName(m_firstRequest.url().host());
-    m_sslVerifier.setSslCtx(sslCtx);
-
-    return CURLE_OK;
-}
-
-/*
-* This is being called for each HTTP header in the response. This includes '\r\n'
-* for the last line of the header.
-*
-* We will add each HTTP Header to the ResourceResponse and on the termination
-* of the header (\r\n) we will parse Content-Type and Content-Disposition and
-* update the ResourceResponse and then send it away.
-*
-*/
-size_t ResourceHandleCurlDelegate::didReceiveHeader(String&& header)
-{
-    static const auto emptyLineCRLF = "\r\n";
-    static const auto emptyLineLF = "\n";
-
-    if (!m_handle)
-        return 0;
-
-    if (m_defersLoading)
-        return 0;
-
-    size_t receiveBytes = header.length();
-
-    // The HTTP standard requires to use \r\n but for compatibility it recommends to accept also \n.
-    // We will add the current header to the CurlResponse.headers
-    if ((header != emptyLineCRLF) && (header != emptyLineLF)) {
-        m_response.headers.append(WTFMove(header));
-        return receiveBytes;
-    }
-
-    // We can finish and send the ResourceResponse
-    long statusCode = 0;
-    if (auto code = m_curlHandle->getResponseCode())
-        statusCode = *code;
-
-    long httpConnectCode = 0;
-    if (auto code = m_curlHandle->getHttpConnectCode())
-        httpConnectCode = *code;
-
-    if ((100 <= statusCode) && (statusCode < 200)) {
-        // Just return when receiving http info, e.g. HTTP/1.1 100 Continue.
-        // If not, the request might be cancelled, because the MIME type will be empty for this response.
-        m_response = CurlResponse();
-        return receiveBytes;
-    }
-
-    if (!statusCode && (httpConnectCode == 200)) {
-        // Comes here when receiving 200 Connection Established. Just return.
-        m_response = CurlResponse();
-        return receiveBytes;
-    }
-
-    // If the FOLLOWLOCATION option is enabled for the curl handle then
-    // curl will follow the redirections internally. Thus this header callback
-    // will be called more than one time with the line starting "HTTP" for one job.
-
-    m_response.url = ""
-    m_response.statusCode = statusCode;
-
-    if (auto length = m_curlHandle->getContentLength())
-        m_response.expectedContentLength = *length;
-
-    if (auto port = m_curlHandle->getPrimaryPort())
-        m_response.connectPort = *port;
-
-    if (auto auth = m_curlHandle->getHttpAuthAvail())
-        m_response.availableHttpAuth = *auth;
-
-    if (isMainThread())
-        didReceiveAllHeaders(m_response);
-    else {
-        callOnMainThread([protectedThis = makeRef(*this), response = m_response.isolatedCopy()] {
-            if (!protectedThis->m_handle)
-                return;
-            protectedThis->didReceiveAllHeaders(response);
-        });
-    }
-
-    return receiveBytes;
-}
-
-// called with data after all headers have been processed via headerCallback
-size_t ResourceHandleCurlDelegate::didReceiveData(Ref<SharedBuffer>&& buffer)
-{
-    if (!m_handle)
-        return 0;
-
-    if (m_defersLoading)
-        return 0;
-
-    size_t receiveBytes = buffer->size();
-
-    // this shouldn't be necessary but apparently is. CURL writes the data
-    // of html page even if it is a redirect that was handled internally
-    // can be observed e.g. on gmail.com
-    if (auto httpCode = m_curlHandle->getResponseCode()) {
-        if (*httpCode >= 300 && *httpCode < 400)
-            return receiveBytes;
-    }
-
-    if (receiveBytes) {
-        if (isMainThread())
-            didReceiveContentData(WTFMove(buffer));
-        else {
-            callOnMainThread([protectedThis = makeRef(*this), buf = WTFMove(buffer)]() mutable {
-                if (!protectedThis->m_handle)
-                    return;
-                protectedThis->didReceiveContentData(WTFMove(buf));
-            });
-        }
-    }
-
-    return receiveBytes;
-}
-
-/* This is called to obtain HTTP POST or PUT data.
-Iterate through FormData elements and upload files.
-Carefully respect the given buffer blockSize and fill the rest of the data at the next calls.
-*/
-size_t ResourceHandleCurlDelegate::willSendData(char* buffer, size_t blockSize, size_t numberOfBlocks)
-{
-    ASSERT(!isMainThread());
-
-    if (!m_handle)
-        return 0;
-
-    if (m_defersLoading)
-        return 0;
-
-    if (!blockSize || !numberOfBlocks)
-        return 0;
-
-    {
-        std::unique_lock<Lock> lock(m_workerThreadMutex);
-
-        m_sendBytes = 0;
-
-        if (isMainThread())
-            prepareSendData(buffer, blockSize, numberOfBlocks);
-        else {
-            callOnMainThread([protectedThis = makeRef(*this), buffer, blockSize, numberOfBlocks] {
-                if (!protectedThis->m_handle)
-                    return;
-                protectedThis->prepareSendData(buffer, blockSize, numberOfBlocks);
-            });
-
-            m_workerThreadConditionVariable.wait(lock, [this] {
-                return m_sendBytes;
-            });
-        }
-    }
-
-    return m_sendBytes;
-}
-
-CURLcode ResourceHandleCurlDelegate::willSetupSslCtxCallback(CURL*, void* sslCtx, void* userData)
-{
-    return static_cast<ResourceHandleCurlDelegate*>(userData)->willSetupSslCtx(sslCtx);
-}
-
-size_t ResourceHandleCurlDelegate::didReceiveHeaderCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* data)
-{
-    return static_cast<ResourceHandleCurlDelegate*>(const_cast<void*>(data))->didReceiveHeader(String(static_cast<const char*>(ptr), blockSize * numberOfBlocks));
-}
-
-size_t ResourceHandleCurlDelegate::didReceiveDataCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* data)
-{
-    return static_cast<ResourceHandleCurlDelegate*>(const_cast<void*>(data))->didReceiveData(SharedBuffer::create(ptr, blockSize * numberOfBlocks));
-}
-
-size_t ResourceHandleCurlDelegate::willSendDataCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* data)
-{
-    return static_cast<ResourceHandleCurlDelegate*>(const_cast<void*>(data))->willSendData(ptr, blockSize, numberOfBlocks);
-}
-
 } // namespace WebCore
 
 #endif

Modified: trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.h (222664 => 222665)


--- trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.h	2017-09-29 21:14:09 UTC (rev 222664)
+++ trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.h	2017-09-29 21:19:32 UTC (rev 222665)
@@ -29,24 +29,17 @@
 #if USE(CURL)
 
 #include "Credential.h"
-#include "CurlJobManager.h"
-#include "CurlResponse.h"
-#include "CurlSSLVerifier.h"
-#include "FormDataStreamCurl.h"
+#include "CurlRequestDelegate.h"
 #include "ResourceRequest.h"
-#include "ResourceResponse.h"
-#include <wtf/Condition.h>
-#include <wtf/ThreadSafeRefCounted.h>
 
 namespace WebCore {
 
+class CurlRequest;
 class MultipartHandle;
-class ProtectionSpace;
-class ResourceError;
 class ResourceHandle;
-class SharedBuffer;
+class ResourceResponse;
 
-class ResourceHandleCurlDelegate final : public ThreadSafeRefCounted<ResourceHandleCurlDelegate>, public CurlJobClient {
+class ResourceHandleCurlDelegate final : public ThreadSafeRefCounted<ResourceHandleCurlDelegate>, public CurlRequestDelegate {
 public:
     ResourceHandleCurlDelegate(ResourceHandle*);
     ~ResourceHandleCurlDelegate();
@@ -54,7 +47,7 @@
     bool hasHandle() const;
     void releaseHandle();
 
-    bool start() { start(false); return true; }
+    bool start();
     void cancel();
 
     void setDefersLoading(bool);
@@ -63,57 +56,28 @@
     void dispatchSynchronousJob();
 
 private:
-    void retain() override;
-    void release() override;
-
-    CURL* handle() override { return m_curlHandle ? m_curlHandle->handle() : nullptr; }
-    CURL* setupTransfer() override;
-    void didCompleteTransfer(CURLcode) override;
-    void didCancelTransfer() override;
-
     // Called from main thread.
     ResourceResponse& response();
 
-    void start(bool isSyncRequest);
+    std::pair<String, String> getCredential(ResourceRequest&, bool);
 
-    void setupAuthentication();
+    bool cancelledOrClientless();
 
-    void didReceiveAllHeaders(const CurlResponse&);
-    void didReceiveContentData(Ref<SharedBuffer>&&);
-    void handleLocalReceiveResponse();
-    void prepareSendData(char*, size_t blockSize, size_t numberOfBlocks);
+    RefPtr<CurlRequest> createCurlRequest(ResourceRequest&);
+    void curlDidReceiveResponse(const CurlResponse&) override;
+    void curlDidReceiveBuffer(Ref<SharedBuffer>&&) override;
+    void curlDidComplete() override;
+    void curlDidFailWithError(const ResourceError&) override;
 
-    void didFinish(NetworkLoadMetrics);
-    void didFail(const ResourceError&);
-
     void handleDataURL();
 
-    // Called from worker thread.
-    void setupPOST();
-    void setupPUT();
-    size_t getFormElementsCount();
-    void setupFormData(bool);
-    void applyAuthentication();
-    NetworkLoadMetrics getNetworkLoadMetrics();
-
-    CURLcode willSetupSslCtx(void*);
-    size_t didReceiveHeader(String&&);
-    size_t didReceiveData(Ref<SharedBuffer>&&);
-    size_t willSendData(char*, size_t blockSize, size_t numberOfBlocks);
-
-    static CURLcode willSetupSslCtxCallback(CURL*, void*, void*);
-    static size_t didReceiveHeaderCallback(char*, size_t blockSize, size_t numberOfBlocks, void*);
-    static size_t didReceiveDataCallback(char*, size_t blockSize, size_t numberOfBlocks, void*);
-    static size_t willSendDataCallback(char*, size_t blockSize, size_t numberOfBlocks, void*);
-
     // Used by main thread.
     ResourceHandle* m_handle;
-    std::unique_ptr<FormDataStream> m_formDataStream;
     std::unique_ptr<MultipartHandle> m_multipartHandle;
-    unsigned short m_authFailureCount { 0 };
+    unsigned m_authFailureCount { 0 };
     // Used by worker thread.
     ResourceRequest m_firstRequest;
-    HTTPHeaderMap m_customHTTPHeaderFields;
+    ResourceRequest m_currentRequest;
     bool m_shouldUseCredentialStorage;
     String m_user;
     String m_pass;
@@ -120,16 +84,7 @@
     Credential m_initialCredential;
     bool m_defersLoading;
     bool m_addedCacheValidationHeaders { false };
-    Vector<char> m_postBytes;
-    std::unique_ptr<CurlHandle> m_curlHandle;
-    CurlSSLVerifier m_sslVerifier;
-    CurlResponse m_response;
-    bool m_didNotifyResponse { false };
-    // Used by both threads.
-    bool m_isSyncRequest { false };
-    Condition m_workerThreadConditionVariable;
-    Lock m_workerThreadMutex;
-    size_t m_sendBytes { 0 };
+    RefPtr<CurlRequest> m_curlRequest;
 };
 
 } // namespace WebCore
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to