Title: [219606] trunk/Source/WebCore
Revision
219606
Author
[email protected]
Date
2017-07-18 00:20:34 -0700 (Tue, 18 Jul 2017)

Log Message

[Curl] Unify ResourceHandleManager into CurlJobManager.
https://bugs.webkit.org/show_bug.cgi?id=173991

Use CurlJobManager to make ResourceHandle run in background.
CurlJobManager::start() now accept callback to manage life cycle
of the resource easily in a same context.
Actual management tasks of CurlJobManager is now private class
in CurlJobManager which is better thread safeness.
ResourceHandleManager is deleted at all.

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

* platform/Curl.cmake:
* platform/network/ResourceHandle.h:
* platform/network/curl/CookieJarCurl.cpp:
(WebCore::cookiesForSession):
* platform/network/curl/CurlContext.cpp:
(WebCore::CurlHandle::CurlHandle):
(WebCore::CurlHandle::~CurlHandle):
(WebCore::CurlHandle::errorDescription):
(WebCore::CurlHandle::perform):
(WebCore::CurlHandle::pause):
(WebCore::CurlHandle::appendRequestHeaders):
(WebCore::CurlHandle::appendRequestHeader):
(WebCore::CurlHandle::enableRequestHeaders):
(WebCore::CurlHandle::fetchCookieList):
(WebCore::CurlHandle::getEffectiveURL):
(WebCore::CurlHandle::setPrivateData): Deleted.
(WebCore::CurlHandle::clearRequestHeaders): Deleted.
(WebCore::CurlHandle::getCookieList): Deleted.
(WebCore::CurlHandle::clearCookieList): Deleted.
* platform/network/curl/CurlContext.h:
(WebCore::CurlSList::CurlSList):
(WebCore::CurlSList::~CurlSList):
(WebCore::CurlSList::operator struct curl_slist** ):
(WebCore::CurlSList::head):
(WebCore::CurlSList::isEmpty):
(WebCore::CurlSList::clear):
(WebCore::CurlSList::append):
(WebCore::CurlHandle::errorCode):
(WebCore::CurlHandle::setErrorCode):
(WebCore::CurlHandle::privateData):
(WebCore::CurlHandle::setPrivateData):
* platform/network/curl/CurlDownload.cpp:
(WebCore::CurlDownload::start):
(WebCore::CurlDownload::cancel):
(WebCore::CurlDownload::addHeaders):
(WebCore::CurlDownload::didReceiveData):
(WebCore::CurlDownload::didFail):
(WebCore::CurlDownload::handleCurlMsg): Deleted.
* platform/network/curl/CurlDownload.h:
* platform/network/curl/CurlJobManager.cpp:
(WebCore::CurlJobList::append):
(WebCore::CurlJobList::cancel):
(WebCore::CurlJobList::complete):
(WebCore::CurlJobList::isEmpty):
(WebCore::CurlJobList::withJob):
(WebCore::CurlJobList::withCurlHandle):
(WebCore::CurlJob::invoke):
(WebCore::CurlJobManager::add):
(WebCore::CurlJobManager::cancel):
(WebCore::CurlJobManager::callOnJobThread):
(WebCore::CurlJobManager::startThreadIfNeeded):
(WebCore::CurlJobManager::stopThreadIfNoMoreJobRunning):
(WebCore::CurlJobManager::stopThread):
(WebCore::CurlJobManager::updateJobs):
(WebCore::CurlJobManager::workerThread):
(WebCore::CurlJobManager::CurlJobManager): Deleted.
(WebCore::CurlJobManager::~CurlJobManager): Deleted.
(WebCore::CurlJobManager::remove): Deleted.
(WebCore::CurlJobManager::getActiveCount): Deleted.
(WebCore::CurlJobManager::getPendingCount): Deleted.
(WebCore::CurlJobManager::stopThreadIfIdle): Deleted.
(WebCore::CurlJobManager::updateHandleList): Deleted.
(WebCore::CurlJobManager::addToCurl): Deleted.
(WebCore::CurlJobManager::removeFromCurl): Deleted.
* platform/network/curl/CurlJobManager.h:
(WebCore::CurlJob::CurlJob):
(WebCore::CurlJob::~CurlJob):
(WebCore::CurlJob::operator=):
(WebCore::CurlJob::curlHandle):
(WebCore::CurlJob::ticket):
(WebCore::CurlJob::finished):
(WebCore::CurlJob::error):
(WebCore::CurlJob::cancel):
(WebCore::CurlJobManager::singleton):
(WebCore::CurlJobManager::~CurlJobManager):
(WebCore::CurlJobManager::isActiveJob):
(WebCore::CurlJobManager::runThread): Deleted.
(WebCore::CurlJobManager::setRunThread): Deleted.
* platform/network/curl/ResourceError.h:
(WebCore::ResourceError::ResourceError):
* platform/network/curl/ResourceHandleCurl.cpp:
(WebCore::ResourceHandle::~ResourceHandle):
(WebCore::ResourceHandle::start):
(WebCore::ResourceHandle::cancel):
(WebCore::ResourceHandle::initialize):
(WebCore::ResourceHandle::applyAuthentication):
(WebCore::getFormElementsCount):
(WebCore::ResourceHandle::setupPUT):
(WebCore::ResourceHandle::setupPOST):
(WebCore::ResourceHandle::setupFormData):
(WebCore::ResourceHandle::setHostAllowsAnyHTTPSCertificate):
(WebCore::ResourceHandle::setClientCertificateInfo):
(WebCore::ResourceHandle::platformSetDefersLoading):
(WebCore::ResourceHandle::didFinish):
(WebCore::ResourceHandle::didFail):
(WebCore::ResourceHandle::shouldUseCredentialStorage):
(WebCore::ResourceHandle::didReceiveAuthenticationChallenge):
(WebCore::ResourceHandle::receivedCredential):
(WebCore::ResourceHandle::receivedRequestToContinueWithoutCredential):
(WebCore::ResourceHandle::receivedCancellation):
(WebCore::ResourceHandle::calculateWebTimingInformations):
(WebCore::ResourceHandle::handleLocalReceiveResponse):
(WebCore::ResourceHandle::willPrepareSendData):
(WebCore::ResourceHandle::didReceiveHeaderLine):
(WebCore::ResourceHandle::didReceiveAllHeaders):
(WebCore::ResourceHandle::didReceiveContentData):
(WebCore::ResourceHandle::readCallback):
(WebCore::ResourceHandle::headerCallback):
(WebCore::ResourceHandle::writeCallback):
(WebCore::ResourceHandle::platformLoadResourceSynchronously):
(WebCore::ResourceHandle::dispatchSynchronousJob):
(WebCore::calculateWebTimingInformations): Deleted.
(WebCore::handleLocalReceiveResponse): Deleted.
(WebCore::writeCallback): Deleted.
(WebCore::headerCallback): Deleted.
(WebCore::readCallback): Deleted.
(WebCore::setupFormData): Deleted.
(WebCore::ResourceHandle::handleCurlMsg): Deleted.
* platform/network/curl/ResourceHandleManager.cpp: Removed.
* platform/network/curl/ResourceHandleManager.h: Removed.

Modified Paths

Removed Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (219605 => 219606)


--- trunk/Source/WebCore/ChangeLog	2017-07-18 07:20:33 UTC (rev 219605)
+++ trunk/Source/WebCore/ChangeLog	2017-07-18 07:20:34 UTC (rev 219606)
@@ -1,3 +1,138 @@
+2017-07-18  Basuke Suzuki  <[email protected]>
+
+        [Curl] Unify ResourceHandleManager into CurlJobManager.
+        https://bugs.webkit.org/show_bug.cgi?id=173991
+
+        Use CurlJobManager to make ResourceHandle run in background.
+        CurlJobManager::start() now accept callback to manage life cycle
+        of the resource easily in a same context.
+        Actual management tasks of CurlJobManager is now private class
+        in CurlJobManager which is better thread safeness.
+        ResourceHandleManager is deleted at all.
+
+        Reviewed by Alex Christensen.
+
+        * platform/Curl.cmake:
+        * platform/network/ResourceHandle.h:
+        * platform/network/curl/CookieJarCurl.cpp:
+        (WebCore::cookiesForSession):
+        * platform/network/curl/CurlContext.cpp:
+        (WebCore::CurlHandle::CurlHandle):
+        (WebCore::CurlHandle::~CurlHandle):
+        (WebCore::CurlHandle::errorDescription):
+        (WebCore::CurlHandle::perform):
+        (WebCore::CurlHandle::pause):
+        (WebCore::CurlHandle::appendRequestHeaders):
+        (WebCore::CurlHandle::appendRequestHeader):
+        (WebCore::CurlHandle::enableRequestHeaders):
+        (WebCore::CurlHandle::fetchCookieList):
+        (WebCore::CurlHandle::getEffectiveURL):
+        (WebCore::CurlHandle::setPrivateData): Deleted.
+        (WebCore::CurlHandle::clearRequestHeaders): Deleted.
+        (WebCore::CurlHandle::getCookieList): Deleted.
+        (WebCore::CurlHandle::clearCookieList): Deleted.
+        * platform/network/curl/CurlContext.h:
+        (WebCore::CurlSList::CurlSList):
+        (WebCore::CurlSList::~CurlSList):
+        (WebCore::CurlSList::operator struct curl_slist** ):
+        (WebCore::CurlSList::head):
+        (WebCore::CurlSList::isEmpty):
+        (WebCore::CurlSList::clear):
+        (WebCore::CurlSList::append):
+        (WebCore::CurlHandle::errorCode):
+        (WebCore::CurlHandle::setErrorCode):
+        (WebCore::CurlHandle::privateData):
+        (WebCore::CurlHandle::setPrivateData):
+        * platform/network/curl/CurlDownload.cpp:
+        (WebCore::CurlDownload::start):
+        (WebCore::CurlDownload::cancel):
+        (WebCore::CurlDownload::addHeaders):
+        (WebCore::CurlDownload::didReceiveData):
+        (WebCore::CurlDownload::didFail):
+        (WebCore::CurlDownload::handleCurlMsg): Deleted.
+        * platform/network/curl/CurlDownload.h:
+        * platform/network/curl/CurlJobManager.cpp:
+        (WebCore::CurlJobList::append):
+        (WebCore::CurlJobList::cancel):
+        (WebCore::CurlJobList::complete):
+        (WebCore::CurlJobList::isEmpty):
+        (WebCore::CurlJobList::withJob):
+        (WebCore::CurlJobList::withCurlHandle):
+        (WebCore::CurlJob::invoke):
+        (WebCore::CurlJobManager::add):
+        (WebCore::CurlJobManager::cancel):
+        (WebCore::CurlJobManager::callOnJobThread):
+        (WebCore::CurlJobManager::startThreadIfNeeded):
+        (WebCore::CurlJobManager::stopThreadIfNoMoreJobRunning):
+        (WebCore::CurlJobManager::stopThread):
+        (WebCore::CurlJobManager::updateJobs):
+        (WebCore::CurlJobManager::workerThread):
+        (WebCore::CurlJobManager::CurlJobManager): Deleted.
+        (WebCore::CurlJobManager::~CurlJobManager): Deleted.
+        (WebCore::CurlJobManager::remove): Deleted.
+        (WebCore::CurlJobManager::getActiveCount): Deleted.
+        (WebCore::CurlJobManager::getPendingCount): Deleted.
+        (WebCore::CurlJobManager::stopThreadIfIdle): Deleted.
+        (WebCore::CurlJobManager::updateHandleList): Deleted.
+        (WebCore::CurlJobManager::addToCurl): Deleted.
+        (WebCore::CurlJobManager::removeFromCurl): Deleted.
+        * platform/network/curl/CurlJobManager.h:
+        (WebCore::CurlJob::CurlJob):
+        (WebCore::CurlJob::~CurlJob):
+        (WebCore::CurlJob::operator=):
+        (WebCore::CurlJob::curlHandle):
+        (WebCore::CurlJob::ticket):
+        (WebCore::CurlJob::finished):
+        (WebCore::CurlJob::error):
+        (WebCore::CurlJob::cancel):
+        (WebCore::CurlJobManager::singleton):
+        (WebCore::CurlJobManager::~CurlJobManager):
+        (WebCore::CurlJobManager::isActiveJob):
+        (WebCore::CurlJobManager::runThread): Deleted.
+        (WebCore::CurlJobManager::setRunThread): Deleted.
+        * platform/network/curl/ResourceError.h:
+        (WebCore::ResourceError::ResourceError):
+        * platform/network/curl/ResourceHandleCurl.cpp:
+        (WebCore::ResourceHandle::~ResourceHandle):
+        (WebCore::ResourceHandle::start):
+        (WebCore::ResourceHandle::cancel):
+        (WebCore::ResourceHandle::initialize):
+        (WebCore::ResourceHandle::applyAuthentication):
+        (WebCore::getFormElementsCount):
+        (WebCore::ResourceHandle::setupPUT):
+        (WebCore::ResourceHandle::setupPOST):
+        (WebCore::ResourceHandle::setupFormData):
+        (WebCore::ResourceHandle::setHostAllowsAnyHTTPSCertificate):
+        (WebCore::ResourceHandle::setClientCertificateInfo):
+        (WebCore::ResourceHandle::platformSetDefersLoading):
+        (WebCore::ResourceHandle::didFinish):
+        (WebCore::ResourceHandle::didFail):
+        (WebCore::ResourceHandle::shouldUseCredentialStorage):
+        (WebCore::ResourceHandle::didReceiveAuthenticationChallenge):
+        (WebCore::ResourceHandle::receivedCredential):
+        (WebCore::ResourceHandle::receivedRequestToContinueWithoutCredential):
+        (WebCore::ResourceHandle::receivedCancellation):
+        (WebCore::ResourceHandle::calculateWebTimingInformations):
+        (WebCore::ResourceHandle::handleLocalReceiveResponse):
+        (WebCore::ResourceHandle::willPrepareSendData):
+        (WebCore::ResourceHandle::didReceiveHeaderLine):
+        (WebCore::ResourceHandle::didReceiveAllHeaders):
+        (WebCore::ResourceHandle::didReceiveContentData):
+        (WebCore::ResourceHandle::readCallback):
+        (WebCore::ResourceHandle::headerCallback):
+        (WebCore::ResourceHandle::writeCallback):
+        (WebCore::ResourceHandle::platformLoadResourceSynchronously):
+        (WebCore::ResourceHandle::dispatchSynchronousJob):
+        (WebCore::calculateWebTimingInformations): Deleted.
+        (WebCore::handleLocalReceiveResponse): Deleted.
+        (WebCore::writeCallback): Deleted.
+        (WebCore::headerCallback): Deleted.
+        (WebCore::readCallback): Deleted.
+        (WebCore::setupFormData): Deleted.
+        (WebCore::ResourceHandle::handleCurlMsg): Deleted.
+        * platform/network/curl/ResourceHandleManager.cpp: Removed.
+        * platform/network/curl/ResourceHandleManager.h: Removed.
+
 2017-07-17  Konstantin Tokarev  <[email protected]>
 
         Unreviewed fix to Mac CMake build after r219474.

Modified: trunk/Source/WebCore/platform/Curl.cmake (219605 => 219606)


--- trunk/Source/WebCore/platform/Curl.cmake	2017-07-18 07:20:33 UTC (rev 219605)
+++ trunk/Source/WebCore/platform/Curl.cmake	2017-07-18 07:20:34 UTC (rev 219606)
@@ -15,7 +15,6 @@
     platform/network/curl/MultipartHandle.cpp
     platform/network/curl/ProxyServerCurl.cpp
     platform/network/curl/ResourceHandleCurl.cpp
-    platform/network/curl/ResourceHandleManager.cpp
     platform/network/curl/SSLHandle.cpp
     platform/network/curl/SocketStreamHandleImplCurl.cpp
     platform/network/curl/SynchronousLoaderClientCurl.cpp

Modified: trunk/Source/WebCore/platform/network/ResourceHandle.h (219605 => 219606)


--- trunk/Source/WebCore/platform/network/ResourceHandle.h	2017-07-18 07:20:33 UTC (rev 219605)
+++ trunk/Source/WebCore/platform/network/ResourceHandle.h	2017-07-18 07:20:34 UTC (rev 219606)
@@ -70,6 +70,7 @@
 
 #if USE(CURL)
 #include "CurlJobManager.h"
+#include <wtf/Lock.h>
 #endif
 
 namespace WTF {
@@ -185,12 +186,6 @@
     MonotonicTime m_requestTime;
 #endif
 
-#if USE(CURL)
-    void initialize();
-    void handleDataURL();
-    void handleCurlMsg(CURLMsg*);
-#endif
-
     bool hasAuthenticationChallenge() const;
     void clearAuthentication();
     WEBCORE_EXPORT virtual void cancel();
@@ -293,14 +288,40 @@
 #endif
 
 #if USE(CURL)
-    void dispatchSynchronousJob();
+    CurlJobTicket m_job;
 
+    Vector<char> m_receivedBuffer;
+    Lock m_receivedBufferMutex;
+
+    void initialize();
+    void applyAuthentication();
     void setupPOST();
     void setupPUT();
+    void setupFormData(bool isPostRequest);
 
-    void applyAuthentication();
+    void didFinish();
+    void didFail();
+
+    size_t willPrepareSendData(char* ptr, size_t blockSize, size_t numberOfBlocks);
+    void didReceiveHeaderLine(const String& header);
+    void didReceiveAllHeaders(long httpCode, long long contentLength);
+    void didReceiveContentData();
+
+    void handleLocalReceiveResponse();
+
+    static size_t readCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* data);
+    static size_t headerCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* data);
+    static size_t writeCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* data);
+
+    void dispatchSynchronousJob();
+    void handleDataURL();
+
+#if ENABLE(WEB_TIMING)
+    void calculateWebTimingInformations();
 #endif
 
+#endif
+
     friend class ResourceHandleInternal;
     std::unique_ptr<ResourceHandleInternal> d;
 };

Modified: trunk/Source/WebCore/platform/network/curl/CookieJarCurl.cpp (219605 => 219606)


--- trunk/Source/WebCore/platform/network/curl/CookieJarCurl.cpp	2017-07-18 07:20:33 UTC (rev 219605)
+++ trunk/Source/WebCore/platform/network/curl/CookieJarCurl.cpp	2017-07-18 07:20:34 UTC (rev 219606)
@@ -268,17 +268,18 @@
     CurlHandle curlHandle;
     curlHandle.enableShareHandle();
 
-    struct curl_slist* list = curlHandle.getCookieList();
+    CurlSList cookieList;
+    curlHandle.fetchCookieList(cookieList);
+    const struct curl_slist* list = cookieList.head();
     if (list) {
         String domain = url.host();
         String path = url.path();
         StringBuilder cookiesBuilder;
 
-        struct curl_slist* item = list;
-        while (item) {
-            const char* cookie = item->data;
+        while (list) {
+            const char* cookie = list->data;
             addMatchingCurlCookie(cookie, domain, path, cookiesBuilder, httponly);
-            item = item->next;
+            list = list->next;
         }
 
         cookies = cookiesBuilder.toString();

Modified: trunk/Source/WebCore/platform/network/curl/CurlContext.cpp (219605 => 219606)


--- trunk/Source/WebCore/platform/network/curl/CurlContext.cpp	2017-07-18 07:20:33 UTC (rev 219605)
+++ trunk/Source/WebCore/platform/network/curl/CurlContext.cpp	2017-07-18 07:20:34 UTC (rev 219606)
@@ -28,7 +28,7 @@
 
 #if USE(CURL)
 #include "CurlContext.h"
-
+#include "HTTPHeaderMap.h"
 #include <wtf/MainThread.h>
 #include <wtf/text/CString.h>
 
@@ -101,6 +101,8 @@
 
 // CurlContext -------------------------------------------------------------------
 
+const char* const CurlContext::errorDomain = "CurlErrorDomain";
+
 CurlContext::CurlContext()
 : m_cookieJarFileName { cookieJarPath() }
 , m_certificatePath { certificatePath() }
@@ -285,28 +287,31 @@
 
     m_handle = curl_easy_init();
     curl_easy_setopt(m_handle, CURLOPT_ERRORBUFFER, m_errorBuffer);
+    curl_easy_setopt(m_handle, CURLOPT_PRIVATE, this);
 }
 
 CurlHandle::~CurlHandle()
 {
-    clearCookieList();
     clearUrl();
-    clearRequestHeaders();
 
-    if (m_handle) {
-        curl_easy_cleanup(m_handle);
-        m_handle = nullptr;
-    }
+    curl_easy_cleanup(m_handle);
 }
 
+const String CurlHandle::errorDescription() const
+{
+    return String(curl_easy_strerror(m_errorCode));
+}
+
 CURLcode CurlHandle::perform()
 {
-    return curl_easy_perform(m_handle);
+    m_errorCode = curl_easy_perform(m_handle);
+    return m_errorCode;
 }
 
 CURLcode CurlHandle::pause(int bitmask)
 {
-    return curl_easy_pause(m_handle, CURLPAUSE_ALL);
+    m_errorCode = curl_easy_pause(m_handle, CURLPAUSE_ALL);
+    return m_errorCode;
 }
 
 void CurlHandle::enableShareHandle()
@@ -314,11 +319,6 @@
     curl_easy_setopt(m_handle, CURLOPT_SHARE, CurlContext::singleton().shareHandle().handle());
 }
 
-void CurlHandle::setPrivateData(void* userData)
-{
-    curl_easy_setopt(m_handle, CURLOPT_PRIVATE, userData);
-}
-
 void CurlHandle::setUrl(const String& url)
 {
     clearUrl();
@@ -336,11 +336,15 @@
     }
 }
 
-void CurlHandle::clearRequestHeaders()
+void CurlHandle::appendRequestHeaders(const HTTPHeaderMap& headers)
 {
-    if (m_requestHeaders) {
-        curl_slist_free_all(m_requestHeaders);
-        m_requestHeaders = nullptr;
+    if (headers.size()) {
+        for (auto& entry : headers) {
+            auto& value = entry.value;
+            appendRequestHeader(entry.key, entry.value);
+        }
+
+        enableRequestHeaders();
     }
 }
 
@@ -361,13 +365,15 @@
 
 void CurlHandle::appendRequestHeader(const String& header)
 {
-    m_requestHeaders = curl_slist_append(m_requestHeaders, header.latin1().data());
+    m_requestHeaders.append(header);
 }
 
 void CurlHandle::enableRequestHeaders()
 {
-    if (m_requestHeaders)
-        curl_easy_setopt(m_handle, CURLOPT_HTTPHEADER, m_requestHeaders);
+    if (!m_requestHeaders.isEmpty()) {
+        const struct curl_slist* headers = m_requestHeaders.head();
+        curl_easy_setopt(m_handle, CURLOPT_HTTPHEADER, headers);
+    }
 }
 
 void CurlHandle::enableHttpGetRequest()
@@ -508,21 +514,11 @@
     curl_easy_setopt(m_handle, CURLOPT_COOKIELIST, cookieList);
 }
 
-struct curl_slist* CurlHandle::getCookieList()
+void CurlHandle::fetchCookieList(CurlSList &cookies) const
 {
-    clearCookieList();
-
-    curl_easy_getinfo(m_handle, CURLINFO_COOKIELIST, &m_cookieList);
-
-    return m_cookieList;
+    curl_easy_getinfo(m_handle, CURLINFO_COOKIELIST, static_cast<struct curl_slist**>(cookies));
 }
 
-void CurlHandle::clearCookieList()
-{
-    if (!m_cookieList)
-        curl_slist_free_all(m_cookieList);
-}
-
 void CurlHandle::enableProxyIfExists()
 {
     auto& proxy = CurlContext::singleton().proxyInfo();
@@ -564,7 +560,7 @@
     curl_easy_setopt(m_handle, CURLOPT_SSL_CTX_FUNCTION, callbackFunc);
 }
 
-URL CurlHandle::getEffectiveURL()
+URL CurlHandle::getEffectiveURL() const
 {
     CURLcode errCd = CURLE_FAILED_INIT;
     char* url = ""

Modified: trunk/Source/WebCore/platform/network/curl/CurlContext.h (219605 => 219606)


--- trunk/Source/WebCore/platform/network/curl/CurlContext.h	2017-07-18 07:20:33 UTC (rev 219605)
+++ trunk/Source/WebCore/platform/network/curl/CurlContext.h	2017-07-18 07:20:34 UTC (rev 219606)
@@ -102,6 +102,8 @@
         const String url() const;
     };
 
+    static const char* const errorDomain;
+
     static CurlContext& singleton()
     {
         static CurlContext shared;
@@ -167,10 +169,36 @@
     CURLM* m_multiHandle { nullptr };
 };
 
+// CurlSList -------------------------------------------------
 
+class CurlSList {
+public:
+    CurlSList() { }
+    ~CurlSList() { clear(); }
 
+    operator struct curl_slist** () { return &m_list; }
+
+    const struct curl_slist* head() const { return m_list; }
+    bool isEmpty() const { return m_list; }
+    void clear()
+    {
+        if (m_list) {
+            curl_slist_free_all(m_list);
+            m_list = nullptr;
+        }
+    }
+
+    void append(const char* str) { m_list = curl_slist_append(m_list, str); }
+    void append(const String& str) { append(str.latin1().data()); }
+
+private:
+    struct curl_slist* m_list { nullptr };
+};
+
 // CurlHandle -------------------------------------------------
 
+class HTTPHeaderMap;
+
 class CurlHandle {
     WTF_MAKE_NONCOPYABLE(CurlHandle);
 
@@ -193,13 +221,20 @@
     CURLcode perform();
     CURLcode pause(int);
 
+    CURLcode errorCode() const { return m_errorCode; }
+    void setErrorCode(CURLcode errorCode) { m_errorCode = errorCode; }
+
+    const String errorDescription() const;
+
     void enableShareHandle();
-    void setPrivateData(void* userData);
 
+    void* privateData() const { return m_privateData; }
+    void setPrivateData(void* userData) { m_privateData = userData; }
+
     void setUrl(const String&);
     const char* url() const { return m_url; }
 
-    void clearRequestHeaders();
+    void appendRequestHeaders(const HTTPHeaderMap&);
     void appendRequestHeader(const String&, const String&);
     void appendRequestHeader(const String&);
     void enableRequestHeaders();
@@ -231,7 +266,7 @@
 
     void enableCookieJarIfExists();
     void setCookieList(const char*);
-    struct curl_slist* getCookieList();
+    void fetchCookieList(CurlSList &cookies) const;
 
     void enableProxyIfExists();
 
@@ -244,7 +279,7 @@
     void setSslCtxCallbackFunction(curl_ssl_ctx_callback, void*);
 
     // Status
-    URL getEffectiveURL();
+    URL getEffectiveURL() const;
     CURLcode getPrimaryPort(long&);
     CURLcode getResponseCode(long&);
     CURLcode getContentLenghtDownload(long long&);
@@ -260,16 +295,16 @@
 
 private:
     void clearUrl();
-    void clearCookieList();
 
     static int expectedSizeOfCurlOffT();
 
     CURL* m_handle { nullptr };
     char m_errorBuffer[CURL_ERROR_SIZE] { };
+    CURLcode m_errorCode;
 
     char* m_url { nullptr };
-    struct curl_slist* m_requestHeaders { nullptr };
-    struct curl_slist* m_cookieList { nullptr };
+    void* m_privateData { nullptr };
+    CurlSList m_requestHeaders;
 };
 
 }

Modified: trunk/Source/WebCore/platform/network/curl/CurlDownload.cpp (219605 => 219606)


--- trunk/Source/WebCore/platform/network/curl/CurlDownload.cpp	2017-07-18 07:20:33 UTC (rev 219605)
+++ trunk/Source/WebCore/platform/network/curl/CurlDownload.cpp	2017-07-18 07:20:34 UTC (rev 219606)
@@ -86,13 +86,27 @@
 
 bool CurlDownload::start()
 {
-    ref(); // CurlJobManager will call deref when the download has finished.
-    return CurlJobManager::singleton().add(m_curlHandle.handle());
+    m_job = CurlJobManager::singleton().add(m_curlHandle, [this, protectedThis = makeRef(*this)](CurlJobResult result) mutable {
+        switch (result) {
+        case CurlJobResult::Done:
+            didFinish();
+            break;
+
+        case CurlJobResult::Error:
+            didFail();
+            break;
+
+        case CurlJobResult::Cancelled:
+            break;
+        }
+    });
+    return true;
 }
 
 bool CurlDownload::cancel()
 {
-    return CurlJobManager::singleton().remove(m_curlHandle.handle());
+    CurlJobManager::singleton().cancel(m_job);
+    return true;
 }
 
 String CurlDownload::getTempPath() const
@@ -145,28 +159,7 @@
 void CurlDownload::addHeaders(const ResourceRequest& request)
 {
     LockHolder locker(m_mutex);
-
-    m_curlHandle.clearRequestHeaders();
-
-    if (request.httpHeaderFields().size() > 0) {
-        HTTPHeaderMap customHeaders = request.httpHeaderFields();
-        HTTPHeaderMap::const_iterator end = customHeaders.end();
-        for (HTTPHeaderMap::const_iterator it = customHeaders.begin(); it != end; ++it) {
-            const String& value = it->value;
-            String headerString(it->key);
-            if (value.isEmpty())
-                // Insert the ; to tell curl that this header has an empty value.
-                headerString.append(";");
-            else {
-                headerString.append(": ");
-                headerString.append(value);
-            }
-
-            m_curlHandle.appendRequestHeader(headerString);
-        }
-
-        m_curlHandle.enableRequestHeaders();
-    }
+    m_curlHandle.appendRequestHeaders(request.httpHeaderFields());
 }
 
 void CurlDownload::didReceiveHeader(const String& header)
@@ -201,9 +194,7 @@
 {
     LockHolder locker(m_mutex);
 
-    RefPtr<CurlDownload> protectedThis(this);
-
-    callOnMainThread([this, size, protectedThis] {
+    callOnMainThread([this, size, protectedThis = makeRef(*this)] {
         didReceiveDataOfLength(size);
     });
 
@@ -234,12 +225,13 @@
 void CurlDownload::didFail()
 {
     closeFile();
+    {
+        LockHolder locker(m_mutex);
 
-    LockHolder locker(m_mutex);
+        if (m_deletesFileUponFailure)
+            deleteFile(m_tempPath);
+    }
 
-    if (m_deletesFileUponFailure)
-        deleteFile(m_tempPath);
-
     if (m_listener)
         m_listener->didFail();
 }
@@ -292,29 +284,6 @@
         download->didReceiveResponse();
 }
 
-CurlJobAction CurlDownload::handleCurlMsg(CURLMsg* msg)
-{
-    switch (msg->msg) {
-    case CURLMSG_DONE: {
-        if (msg->data.result == CURLE_OK) {
-            callOnMainThread([this] {
-                didFinish();
-                deref(); // This matches the ref() in CurlDownload::start().
-            });
-        } else {
-            callOnMainThread([this] {
-                didFail();
-                deref(); // This matches the ref() in CurlDownload::start().
-            });
-        }
-        return CurlJobAction::Finished;
-    }
-    default: {
-        return CurlJobAction::None;
-    }
-    }
 }
 
-}
-
 #endif

Modified: trunk/Source/WebCore/platform/network/curl/CurlDownload.h (219605 => 219606)


--- trunk/Source/WebCore/platform/network/curl/CurlDownload.h	2017-07-18 07:20:33 UTC (rev 219605)
+++ trunk/Source/WebCore/platform/network/curl/CurlDownload.h	2017-07-18 07:20:34 UTC (rev 219606)
@@ -50,7 +50,7 @@
     virtual void didFail() { }
 };
 
-class CurlDownload : public ThreadSafeRefCounted<CurlDownload>, public CurlJob {
+class CurlDownload : public ThreadSafeRefCounted<CurlDownload> {
 public:
     CurlDownload();
     ~CurlDownload();
@@ -72,8 +72,6 @@
 
     void setDestination(const String& destination) { m_destination = destination; }
 
-    virtual CurlJobAction handleCurlMsg(CURLMsg*);
-
 private:
     void closeFile();
     void moveFileToDestination();
@@ -100,7 +98,7 @@
     static void receivedResponseCallback(CurlDownload*);
 
     CurlHandle m_curlHandle;
-
+    CurlJobTicket m_job;
     String m_tempPath;
     String m_destination;
     WebCore::PlatformFileHandle m_tempHandle { invalidPlatformFileHandle };

Modified: trunk/Source/WebCore/platform/network/curl/CurlJobManager.cpp (219605 => 219606)


--- trunk/Source/WebCore/platform/network/curl/CurlJobManager.cpp	2017-07-18 07:20:33 UTC (rev 219605)
+++ trunk/Source/WebCore/platform/network/curl/CurlJobManager.cpp	2017-07-18 07:20:34 UTC (rev 219606)
@@ -29,6 +29,7 @@
 #if USE(CURL)
 #include "CurlJobManager.h"
 
+#include <iterator>
 #include <wtf/MainThread.h>
 #include <wtf/text/CString.h>
 
@@ -36,49 +37,117 @@
 
 namespace WebCore {
 
-CurlJobManager::CurlJobManager()
-{
+/*
+ * CurlJobList is used only in background so that no need to manage mutex
+ */
+class CurlJobList : public CurlMultiHandle {
+    using Predicate = WTF::Function<bool(const CurlJob&)>;
+    using Action = ""
+    using JobMap = HashMap<CurlJobTicket, CurlJob>;
 
-}
+public:
+    void append(CurlJob& job)
+    {
+        CurlHandle* curl = job.curlHandle();
 
-CurlJobManager::~CurlJobManager()
+        CURLMcode retval = addHandle(curl->handle());
+            // @FIXME error logging
+        if (retval == CURLM_OK)
+            m_jobs.set(job.ticket(), WTFMove(job));
+    }
+
+    void cancel(CurlJobTicket ticket)
+    {
+        complete(ticket, [](auto&& job) { job.cancel(); });
+    }
+
+    void complete(CurlJobTicket ticket, Action action)
+    {
+        auto found = m_jobs.find(ticket);
+        if (found != m_jobs.end()) {
+            auto job = WTFMove(found->value);
+
+            removeHandle(job.curlHandle()->handle());
+            action(job);
+
+            m_jobs.remove(found);
+        }
+    }
+
+    bool isEmpty() const { return m_jobs.isEmpty(); }
+
+    bool withJob(CurlJobTicket ticket, WTF::Function<void(JobMap::iterator)> callback)
+    {
+        auto found = m_jobs.find(ticket);
+        if (found == m_jobs.end())
+            return false;
+        
+        callback(found);
+        return true;
+    }
+
+    bool withCurlHandle(CurlJobTicket ticket, WTF::Function<void(CurlHandle&)> callback)
+    {
+        return withJob(ticket, [&callback](JobMap::iterator it) {
+            callback(*it->value.curlHandle());
+        });
+    }
+
+private:
+    JobMap m_jobs;
+};
+
+void CurlJob::invoke(CurlJobResult result)
 {
-    stopThread();
+    callOnMainThread([job = WTFMove(m_job), result] {
+        job(result);
+    });
 }
 
-bool CurlJobManager::add(CURL* curlHandle)
+CurlJobTicket CurlJobManager::add(CurlHandle& curl, Callback callback)
 {
     ASSERT(isMainThread());
 
+    CurlJobTicket ticket = static_cast<CurlJobTicket>(curl.handle());
+
     {
         LockHolder locker(m_mutex);
-        m_pendingHandleList.append(curlHandle);
+
+        if (isActiveJob(ticket))
+            return ticket;
+
+
+        m_pendingJobs.append(CurlJob { &curl, WTFMove(callback) });
+        m_activeJobs.add(ticket);
     }
 
     startThreadIfNeeded();
 
-    return true;
+    return ticket;
 }
 
-bool CurlJobManager::remove(CURL* curlHandle)
+bool CurlJobManager::cancel(CurlJobTicket job)
 {
-    LockHolder locker(m_mutex);
+    ASSERT(isMainThread());
 
-    m_removedHandleList.append(curlHandle);
+    if (m_runThread) {
+        LockHolder locker(m_mutex);
 
+        if (!isActiveJob(job))
+            return false;
+        
+        m_cancelledTickets.append(job);
+        m_activeJobs.remove(job);
+    }
+
     return true;
 }
 
-int CurlJobManager::getActiveCount() const
+void CurlJobManager::callOnJobThread(WTF::Function<void()>&& callback)
 {
-    LockHolder locker(m_mutex);
-    return m_activeHandleList.size();
-}
+    LockHolder locker { m_mutex };
 
-int CurlJobManager::getPendingCount() const
-{
-    LockHolder locker(m_mutex);
-    return m_pendingHandleList.size();
+    m_taskQueue.append(std::make_unique<WTF::Function<void()>>(WTFMove(callback)));
 }
 
 void CurlJobManager::startThreadIfNeeded()
@@ -85,10 +154,12 @@
 {
     ASSERT(isMainThread());
 
-    if (!runThread()) {
+    LockHolder locker(m_mutex);
+    if (!m_runThread) {
         if (m_thread)
             m_thread->waitForCompletion();
-        setRunThread(true);
+
+        m_runThread = true;
         m_thread = Thread::create("curlThread", [this] {
             workerThread();
         });
@@ -95,9 +166,19 @@
     }
 }
 
+void CurlJobManager::stopThreadIfNoMoreJobRunning()
+{
+    ASSERT(!isMainThread());
+
+    LockHolder locker(m_mutex);
+
+    if (m_pendingJobs.isEmpty())
+        m_runThread = false;
+}
+
 void CurlJobManager::stopThread()
 {
-    setRunThread(false);
+    m_runThread = false;
 
     if (m_thread) {
         m_thread->waitForCompletion();
@@ -105,54 +186,32 @@
     }
 }
 
-void CurlJobManager::stopThreadIfIdle()
+bool CurlJobManager::updateJobs(CurlJobList& jobs)
 {
-    if (!getActiveCount() && !getPendingCount())
-        setRunThread(false);
-}
+    ASSERT(!isMainThread());
 
-void CurlJobManager::updateHandleList()
-{
-    LockHolder locker(m_mutex);
+    Vector<CurlJob> pendingJobs;
+    Vector<CurlJobTicket> cancelledTickets;
+    {
+        LockHolder locker(m_mutex);
+        if (!m_runThread)
+            return false;
 
-    // Remove curl easy handles from multi list 
-    int size = m_removedHandleList.size();
-    for (int i = 0; i < size; i++) {
-        removeFromCurl(m_removedHandleList[0]);
-        m_removedHandleList.remove(0);
+        pendingJobs = WTFMove(m_pendingJobs);
+        cancelledTickets = WTFMove(m_cancelledTickets);
     }
 
-    // Add pending curl easy handles to multi list 
-    size = m_pendingHandleList.size();
-    for (int i = 0; i < size; i++) {
-        addToCurl(m_pendingHandleList[0]);
-        m_pendingHandleList.remove(0);
-    }
-}
+    for (auto& job : pendingJobs)
+        jobs.append(job);
 
-bool CurlJobManager::addToCurl(CURL* curlHandle)
-{
-    CURLMcode retval = m_curlMultiHandle.addHandle(curlHandle);
-    if (retval == CURLM_OK) {
-        m_activeHandleList.append(curlHandle);
-        return true;
+    for (auto& ticket : cancelledTickets)
+        jobs.cancel(ticket);
+
+    for (auto& callback : m_taskQueue.takeAllMessages()) {
+        (*callback)();
     }
-    return false;
-}
 
-bool CurlJobManager::removeFromCurl(CURL* curlHandle)
-{
-    int handlePos = m_activeHandleList.find(curlHandle);
-
-    if (handlePos < 0)
-        return true;
-
-    CURLMcode retval = m_curlMultiHandle.removeHandle(curlHandle);
-    if (retval == CURLM_OK) {
-        m_activeHandleList.remove(handlePos);
-        return true;
-    }
-    return false;
+    return true;
 }
 
 void CurlJobManager::workerThread()
@@ -159,10 +218,9 @@
 {
     ASSERT(!isMainThread());
 
-    while (runThread()) {
+    CurlJobList jobs;
 
-        updateHandleList();
-
+    while (updateJobs(jobs)) {
         // Retry 'select' if it was interrupted by a process signal.
         int rc = 0;
         do {
@@ -177,7 +235,7 @@
             timeout.tv_sec = 0;
             timeout.tv_usec = selectTimeoutMS * 1000; // select waits microseconds
 
-            m_curlMultiHandle.getFdSet(fdread, fdwrite, fdexcep, maxfd);
+            jobs.getFdSet(fdread, fdwrite, fdexcep, maxfd);
 
             // When the 3 file descriptors are empty, winsock will return -1
             // and bail out, stopping the file download. So make sure we
@@ -186,26 +244,49 @@
                 rc = ::select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);
         } while (rc == -1 && errno == EINTR);
 
-        int runningHandles = 0;
-        while (m_curlMultiHandle.perform(runningHandles) == CURLM_CALL_MULTI_PERFORM) { }
+        int activeCount = 0;
+        while (jobs.perform(activeCount) == CURLM_CALL_MULTI_PERFORM) { }
 
-        int messagesInQueue = 0;
-        CURLMsg* msg = m_curlMultiHandle.readInfo(messagesInQueue);
-        if (!msg)
-            continue;
+        // check the curl messages indicating completed transfers
+        // and free their resources
+        while (true) {
+            int messagesInQueue = 0;
+            CURLMsg* msg = jobs.readInfo(messagesInQueue);
+            if (!msg)
+                break;
 
+            if (msg->msg == CURLMSG_DONE) {
+                auto ticket = static_cast<CurlJobTicket>(msg->easy_handle);
+                CURLcode result = msg->data.result;
 
-        CurlJob* job = nullptr;
-        CURLcode err = curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &job);
-        UNUSED_PARAM(err);
-        ASSERT(job);
+                {
+                    LockHolder locker(m_mutex);
+                    m_activeJobs.remove(ticket);
+                }
 
-        CurlJobAction action = ""
+                jobs.complete(ticket, [result](auto& job) {
+                    job.curlHandle()->setErrorCode(result);
 
-        if (action == CurlJobAction::Finished)
-            removeFromCurl(msg->easy_handle);
+                    bool done = result == CURLE_OK;
+                    if (done)
+                        job.finished();
+                    else {
+                        URL url = ""
+#ifndef NDEBUG
+                        fprintf(stderr, "Curl ERROR for url='', error: '%s'\n", url.string().utf8().data(), job.curlHandle()->errorDescription().utf8().data());
+#endif
+                        job.error();
+                    }
+                });
+            } else
+                ASSERT_NOT_REACHED();
+        }
 
-        stopThreadIfIdle();
+        if (jobs.isEmpty()) {
+            stopThreadIfNoMoreJobRunning();
+            if (!m_runThread)
+                break;
+        }
     }
 }
 

Modified: trunk/Source/WebCore/platform/network/curl/CurlJobManager.h (219605 => 219606)


--- trunk/Source/WebCore/platform/network/curl/CurlJobManager.h	2017-07-18 07:20:33 UTC (rev 219605)
+++ trunk/Source/WebCore/platform/network/curl/CurlJobManager.h	2017-07-18 07:20:34 UTC (rev 219606)
@@ -28,11 +28,16 @@
 
 #include "CurlContext.h"
 
+#include <wtf/Function.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
 #include <wtf/Lock.h>
+#include <wtf/MessageQueue.h>
+#include <wtf/Noncopyable.h>
 #include <wtf/Threading.h>
 #include <wtf/Vector.h>
 
-#if PLATFORM(WIN)
+#if OS(WINDOWS)
 #include <windows.h>
 #include <winsock2.h>
 #endif
@@ -40,59 +45,86 @@
 
 namespace WebCore {
 
-enum class CurlJobAction { None, Finished };
+enum class CurlJobResult { Done, Error, Cancelled };
+using CurlJobTicket = void*;
+using CurlJobCallback = WTF::Function<void(CurlJobResult)>;
+using CurlJobTask = WTF::Function<void(CurlHandle&)>;
 
+class CurlJobList;
+
 class CurlJob {
+    WTF_MAKE_NONCOPYABLE(CurlJob);
 public:
-    virtual CurlJobAction handleCurlMsg(CURLMsg*) = 0;
+    CurlJob() { }
+    CurlJob(CurlHandle* curl, CurlJobCallback job)
+        : m_curl { curl }, m_job { WTFMove(job) } { }
+    CurlJob(CurlJob&& other)
+    {
+        m_curl = other.m_curl;
+        other.m_curl = nullptr;
+        m_job = WTFMove(other.m_job);
+    }
+    ~CurlJob() { }
+
+    CurlJob& operator=(CurlJob&& other)
+    {
+        m_curl = other.m_curl;
+        other.m_curl = nullptr;
+        m_job = WTFMove(other.m_job);
+        return *this;
+    }
+
+    CurlHandle* curlHandle() const { return m_curl; }
+    CurlJobTicket ticket() const { return static_cast<CurlJobTicket>(m_curl->handle()); }
+
+    void finished() { invoke(CurlJobResult::Done); }
+    void error() { invoke(CurlJobResult::Error); }
+    void cancel() { invoke(CurlJobResult::Cancelled); }
+
+private:
+    CurlHandle* m_curl;
+    CurlJobCallback m_job;
+
+    void invoke(CurlJobResult);
 };
 
+
 class CurlJobManager {
+    WTF_MAKE_NONCOPYABLE(CurlJobManager);
+    using Callback = CurlJobCallback;
+
 public:
+
     static CurlJobManager& singleton()
     {
-        // Since it's a static variable, if the class has already been created,
-        // It won't be created again.
-        // And it **is** thread-safe in C++11.
-
         static CurlJobManager shared;
         return shared;
     }
 
-    CurlJobManager();
-    virtual ~CurlJobManager();
+    CurlJobManager() = default;
+    ~CurlJobManager() { stopThread(); }
 
-    bool add(CURL* curlHandle);
-    bool remove(CURL* curlHandle);
+    CurlJobTicket add(CurlHandle&, Callback);
+    bool cancel(CurlJobTicket);
+    void callOnJobThread(WTF::Function<void()>&&);
 
-    int getActiveCount() const;
-    int getPendingCount() const;
-
 private:
     void startThreadIfNeeded();
+    void stopThreadIfNoMoreJobRunning();
     void stopThread();
-    void stopThreadIfIdle();
 
-    void updateHandleList();
+    bool updateJobs(CurlJobList& jobs);
+    bool isActiveJob(CurlJobTicket job) const { return m_activeJobs.contains(job); }
 
-    bool runThread() const { LockHolder locker(m_mutex); return m_runThread; }
-    void setRunThread(bool runThread) { LockHolder locker(m_mutex); m_runThread = runThread; }
-
-    bool addToCurl(CURL* curlHandle);
-    bool removeFromCurl(CURL* curlHandle);
-
     void workerThread();
 
     RefPtr<Thread> m_thread;
-    Vector<CURL*> m_pendingHandleList;
-    Vector<CURL*> m_activeHandleList;
-    Vector<CURL*> m_removedHandleList;
+    Vector<CurlJob> m_pendingJobs;
+    HashSet<CurlJobTicket> m_activeJobs;
+    Vector<CurlJobTicket> m_cancelledTickets;
+    MessageQueue<WTF::Function<void()>> m_taskQueue;
     mutable Lock m_mutex;
-    bool m_runThread { false };
-
-    CurlMultiHandle m_curlMultiHandle;
-
-    friend class CurlJob;
+    bool m_runThread { };
 };
 
 }

Modified: trunk/Source/WebCore/platform/network/curl/ResourceError.h (219605 => 219606)


--- trunk/Source/WebCore/platform/network/curl/ResourceError.h	2017-07-18 07:20:33 UTC (rev 219605)
+++ trunk/Source/WebCore/platform/network/curl/ResourceError.h	2017-07-18 07:20:34 UTC (rev 219606)
@@ -23,9 +23,9 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  */
 
-#ifndef ResourceError_h
-#define ResourceError_h
+#pragma once
 
+#include "CurlContext.h"
 #include "ResourceErrorBase.h"
 
 #if PLATFORM(WIN)
@@ -33,8 +33,6 @@
 #include <winsock2.h>
 #endif
 
-#include <curl/curl.h>
-
 namespace WebCore {
 
 class ResourceError : public ResourceErrorBase
@@ -42,16 +40,20 @@
 public:
     ResourceError(Type type = Type::Null)
         : ResourceErrorBase(type)
-        , m_sslErrors(0)
     {
     }
 
     ResourceError(const String& domain, int errorCode, const URL& failingURL, const String& localizedDescription, Type type = Type::General)
         : ResourceErrorBase(domain, errorCode, failingURL, localizedDescription, type)
-        , m_sslErrors(0)
     {
     }
 
+    ResourceError(const CurlHandle& curl, unsigned sslErrors)
+        : ResourceErrorBase(CurlContext::errorDomain, curl.errorCode(), curl.getEffectiveURL(), curl.errorDescription(), Type::General)
+        , m_sslErrors { sslErrors }
+    {
+    }
+
     unsigned sslErrors() const { return m_sslErrors; }
     void setSSLErrors(unsigned sslVerifyResult) { m_sslErrors = sslVerifyResult; }
     bool hasSSLConnectError() const { return errorCode() == CURLE_SSL_CONNECT_ERROR; }
@@ -60,9 +62,8 @@
     friend class ResourceErrorBase;
     void doPlatformIsolatedCopy(const ResourceError&) { }
 
-    unsigned m_sslErrors;
+    unsigned m_sslErrors { 0 };
 };
 
 }
 
-#endif // ResourceError_h_

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


--- trunk/Source/WebCore/platform/network/curl/ResourceHandleCurl.cpp	2017-07-18 07:20:33 UTC (rev 219605)
+++ trunk/Source/WebCore/platform/network/curl/ResourceHandleCurl.cpp	2017-07-18 07:20:34 UTC (rev 219606)
@@ -35,13 +35,12 @@
 #include "CredentialStorage.h"
 #include "CurlCacheManager.h"
 #include "CurlContext.h"
+#include "CurlJobManager.h"
 #include "FileSystem.h"
 #include "Logging.h"
 #include "MIMETypeRegistry.h"
 #include "NetworkingContext.h"
-#include "NotImplemented.h"
 #include "ResourceHandleInternal.h"
-#include "ResourceHandleManager.h"
 #include "SSLHandle.h"
 #include "SynchronousLoaderClient.h"
 #include <wtf/text/Base64.h>
@@ -55,11 +54,12 @@
 
 ResourceHandle::~ResourceHandle()
 {
-    cancel();
 }
 
 bool ResourceHandle::start()
 {
+    ASSERT(isMainThread());
+
     // The frame could be null if the ResourceHandle is not associated to any
     // Frame, e.g. if we are downloading a file.
     // If the frame is not null but the page is null this must be an attempted
@@ -68,24 +68,274 @@
     if (d->m_context && !d->m_context->isValid())
         return false;
 
-    ResourceHandleManager::sharedInstance()->add(this);
+    initialize();
+
+    m_job = CurlJobManager::singleton().add(d->m_curlHandle, [this, protectedThis = makeRef(*this)](CurlJobResult result) {
+        ASSERT(isMainThread());
+
+        switch (result) {
+        case CurlJobResult::Done:
+            didFinish();
+            break;
+
+        case CurlJobResult::Error:
+            didFail();
+            break;
+
+        case CurlJobResult::Cancelled:
+            break;
+        }
+    });
+    ASSERT(m_job);
+
     return true;
 }
 
 void ResourceHandle::cancel()
 {
-    ResourceHandleManager::sharedInstance()->cancel(this);
+    d->m_cancelled = true;
+    CurlJobManager::singleton().cancel(m_job);
 }
 
+void ResourceHandle::initialize()
+{
+    CurlContext& context = CurlContext::singleton();
+
+    URL url = ""
+
+    // Remove any fragment part, otherwise curl will send it as part of the request.
+    url.removeFragmentIdentifier();
+
+    ResourceHandleInternal* d = getInternal();
+    String urlString = url.string();
+
+    if (url.isLocalFile()) {
+        // Remove any query part sent to a local file.
+        if (!url.query().isEmpty()) {
+            // By setting the query to a null string it'll be removed.
+            url.setQuery(String());
+            urlString = url.string();
+        }
+        // Determine the MIME type based on the path.
+        d->m_response.setMimeType(MIMETypeRegistry::getMIMETypeForPath(url));
+    }
+
+    if (d->m_defersLoading) {
+        CURLcode error = d->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);
+    }
+
+#ifndef NDEBUG
+    d->m_curlHandle.enableVerboseIfUsed();
+    d->m_curlHandle.enableStdErrIfUsed();
+#endif
+
+    d->m_curlHandle.setSslVerifyPeer(CurlHandle::VerifyPeerEnable);
+    d->m_curlHandle.setSslVerifyHost(CurlHandle::VerifyHostStrictNameCheck);
+    d->m_curlHandle.setPrivateData(this);
+    d->m_curlHandle.setWriteCallbackFunction(writeCallback, this);
+    d->m_curlHandle.setHeaderCallbackFunction(headerCallback, this);
+    d->m_curlHandle.enableAutoReferer();
+    d->m_curlHandle.enableFollowLocation();
+    d->m_curlHandle.enableHttpAuthentication(CURLAUTH_ANY);
+    d->m_curlHandle.enableShareHandle();
+    d->m_curlHandle.enableTimeout();
+    d->m_curlHandle.enableAllowedProtocols();
+    setSSLClientCertificate(this);
+
+    if (CurlContext::singleton().shouldIgnoreSSLErrors())
+        d->m_curlHandle.setSslVerifyPeer(CurlHandle::VerifyPeerDisable);
+    else
+        setSSLVerifyOptions(this);
+
+    d->m_curlHandle.enableCAInfoIfExists();
+
+    d->m_curlHandle.enableAcceptEncoding();
+    d->m_curlHandle.setUrl(urlString);
+    d->m_curlHandle.enableCookieJarIfExists();
+
+    if (firstRequest().httpHeaderFields().size()) {
+        auto customHeaders = firstRequest().httpHeaderFields();
+        auto& cache = CurlCacheManager::getInstance();
+
+        bool hasCacheHeaders = customHeaders.contains(HTTPHeaderName::IfModifiedSince) || customHeaders.contains(HTTPHeaderName::IfNoneMatch);
+        if (!hasCacheHeaders && cache.isCached(url)) {
+            cache.addCacheEntryClient(url, this);
+
+            // append additional cache information
+            for (auto entry : cache.requestHeaders(url))
+                customHeaders.set(entry.key, entry.value);
+
+            d->m_addedCacheValidationHeaders = true;
+        }
+
+        d->m_curlHandle.appendRequestHeaders(customHeaders);
+    }
+
+    String method = firstRequest().httpMethod();
+    if ("GET" == method)
+        d->m_curlHandle.enableHttpGetRequest();
+    else if ("POST" == method)
+        setupPOST();
+    else if ("PUT" == method)
+        setupPUT();
+    else if ("HEAD" == method)
+        d->m_curlHandle.enableHttpHeadRequest();
+    else {
+        d->m_curlHandle.setHttpCustomRequest(method);
+        setupPUT();
+    }
+
+    d->m_curlHandle.enableRequestHeaders();
+
+    applyAuthentication();
+
+    d->m_curlHandle.enableProxyIfExists();
+}
+
+void ResourceHandle::applyAuthentication()
+{
+    ResourceRequest& request = firstRequest();
+    // m_user/m_pass are credentials given manually, for instance, by the arguments passed to XMLHttpRequest.open().
+    ResourceHandleInternal* d = getInternal();
+
+    String partition = request.cachePartition();
+
+    if (shouldUseCredentialStorage()) {
+        if (d->m_user.isEmpty() && d->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.
+            d->m_initialCredential = CredentialStorage::defaultCredentialStorage().get(partition, request.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(d->m_user, d->m_pass, CredentialPersistenceNone), request.url());
+        }
+    }
+
+    String user = d->m_user;
+    String password = d->m_pass;
+
+    if (!d->m_initialCredential.isEmpty()) {
+        user = d->m_initialCredential.user();
+        password = d->m_initialCredential.password();
+        d->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.
+
+    // curl CURLOPT_USERPWD expects username:password
+    d->m_curlHandle.setHttpAuthUserPass(user, password);
+}
+
+static inline size_t getFormElementsCount(ResourceHandle* job)
+{
+    RefPtr<FormData> formData = job->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();
+    job->firstRequest().setHTTPBody(WTFMove(formData));
+
+    return size;
+}
+
+void ResourceHandle::setupPUT()
+{
+    d->m_curlHandle.enableHttpPutRequest();
+
+    // Disable the Expect: 100 continue header
+    d->m_curlHandle.appendRequestHeader("Expect:");
+
+    size_t numElements = getFormElementsCount(this);
+    if (!numElements)
+        return;
+
+    setupFormData(false);
+}
+
+void ResourceHandle::setupPOST()
+{
+    d->m_curlHandle.enableHttpPostRequest();
+
+    size_t numElements = getFormElementsCount(this);
+    if (!numElements)
+        return;
+
+    // Do not stream for simple POST data
+    if (numElements == 1) {
+        firstRequest().httpBody()->flatten(d->m_postBytes);
+        if (d->m_postBytes.size())
+            d->m_curlHandle.setPostFields(d->m_postBytes.data(), d->m_postBytes.size());
+        return;
+    }
+
+    setupFormData(true);
+}
+
+void ResourceHandle::setupFormData(bool isPostRequest)
+{
+    Vector<FormDataElement> elements = firstRequest().httpBody()->elements();
+    size_t numElements = elements.size();
+
+    static const long long maxCurlOffT = d->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)
+        d->m_curlHandle.appendRequestHeader("Transfer-Encoding: chunked");
+    else {
+        if (isPostRequest)
+            d->m_curlHandle.setPostFieldLarge(size);
+        else
+            d->m_curlHandle.setInFileSizeLarge(size);
+    }
+
+    d->m_curlHandle.setReadCallbackFunction(readCallback, this);
+}
+
 #if OS(WINDOWS)
 
 void ResourceHandle::setHostAllowsAnyHTTPSCertificate(const String& host)
 {
+    ASSERT(isMainThread());
+
     allowsAnyHTTPSCertificateHosts(host);
 }
 
 void ResourceHandle::setClientCertificateInfo(const String& host, const String& certificate, const String& key)
 {
+    ASSERT(isMainThread());
+
     if (fileExists(certificate))
         addAllowedClientCertificate(host, certificate, key);
     else
@@ -104,41 +354,73 @@
 
 void ResourceHandle::platformSetDefersLoading(bool defers)
 {
-    if (!d->m_curlHandle.handle())
+    ASSERT(isMainThread());
+
+    auto action = "" this, protectedThis = makeRef(*this)]() {
+        if (defers) {
+            CURLcode error = d->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 = d->m_curlHandle.pause(CURLPAUSE_CONT);
+            if (error != CURLE_OK) {
+                // Restarting the handle has failed so just cancel it.
+                cancel();
+            }
+        }
+    };
+
+    if (m_job) {
+        CurlJobManager::singleton().callOnJobThread(WTFMove(action));
+    } else {
+        action();
+    }
+}
+
+void ResourceHandle::didFinish()
+{
+#if ENABLE(WEB_TIMING)
+    calculateWebTimingInformations();
+#endif
+    if (d->m_cancelled)
         return;
 
-    if (defers) {
-        CURLcode error = d->m_curlHandle.pause(CURLPAUSE_ALL);
-        // If we could not defer the handle, so don't do it.
-        if (error != CURLE_OK)
+    if (!d->m_response.responseFired()) {
+        handleLocalReceiveResponse();
+        if (d->m_cancelled)
             return;
-    } else {
-        CURLcode error = d->m_curlHandle.pause(CURLPAUSE_CONT);
-        if (error != CURLE_OK)
-            // Restarting the handle has failed so just cancel it.
-            cancel();
     }
+
+    if (d->m_multipartHandle)
+        d->m_multipartHandle->contentEnded();
+
+    if (client()) {
+        client()->didFinishLoading(this);
+        CurlCacheManager::getInstance().didFinishLoading(*this);
+    }
 }
 
-bool ResourceHandle::shouldUseCredentialStorage()
+void ResourceHandle::didFail()
 {
-    return (!client() || client()->shouldUseCredentialStorage(this)) && firstRequest().url().protocolIsInHTTPFamily();
+    if (d->m_cancelled)
+        return;
+    URL url = ""
+    if (client()) {
+        client()->didFail(this, ResourceError(d->m_curlHandle, d->m_sslErrors));
+        CurlCacheManager::getInstance().didFail(*this);
+    }
 }
 
-void ResourceHandle::platformLoadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
+bool ResourceHandle::shouldUseCredentialStorage()
 {
-    SynchronousLoaderClient client;
-    RefPtr<ResourceHandle> handle = adoptRef(new ResourceHandle(context, request, &client, false, false));
-
-    handle.get()->dispatchSynchronousJob();
-
-    error = client.error();
-    data.swap(client.mutableData());
-    response = client.response();
+    return (!client() || client()->shouldUseCredentialStorage(this)) && firstRequest().url().protocolIsInHTTPFamily();
 }
 
 void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
 {
+    ASSERT(isMainThread());
+
     String partition = firstRequest().cachePartition();
 
     if (!d->m_user.isNull() && !d->m_pass.isNull()) {
@@ -188,6 +470,8 @@
 
 void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge, const Credential& credential)
 {
+    ASSERT(isMainThread());
+
     if (challenge != d->m_currentWebChallenge)
         return;
 
@@ -211,6 +495,8 @@
 
 void ResourceHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge& challenge)
 {
+    ASSERT(isMainThread());
+
     if (challenge != d->m_currentWebChallenge)
         return;
 
@@ -220,6 +506,8 @@
 
 void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challenge)
 {
+    ASSERT(isMainThread());
+
     if (challenge != d->m_currentWebChallenge)
         return;
 
@@ -237,10 +525,8 @@
     ASSERT_NOT_REACHED();
 }
 
-const char* const errorDomainCurl = "CurlErrorDomain";
-
 #if ENABLE(WEB_TIMING)
-static void calculateWebTimingInformations(ResourceHandleInternal* d)
+void ResourceHandle::calculateWebTimingInformations()
 {
     double preTransferTime = 0;
     double dnslookupTime = 0;
@@ -263,8 +549,10 @@
 }
 #endif
 
-static void handleLocalReceiveResponse(ResourceHandle* job, ResourceHandleInternal* d)
+void ResourceHandle::handleLocalReceiveResponse()
 {
+    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.
@@ -273,48 +561,11 @@
     URL url = ""
     ASSERT(url.isValid());
     d->m_response.setURL(url);
-    if (d->client())
-        d->client()->didReceiveResponse(job, ResourceResponse(d->m_response));
+    if (client())
+        client()->didReceiveResponse(this, ResourceResponse(d->m_response));
     d->m_response.setResponseFired(true);
 }
 
-// called with data after all headers have been processed via headerCallback
-static size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* data)
-{
-    ResourceHandle* job = static_cast<ResourceHandle*>(data);
-    ResourceHandleInternal* d = job->getInternal();
-    if (d->m_cancelled)
-        return 0;
-
-    // We should never be called when deferred loading is activated.
-    ASSERT(!d->m_defersLoading);
-
-    size_t totalSize = size * nmemb;
-
-    // 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
-    long httpCode = 0;
-    CURLcode errCd = d->m_curlHandle.getResponseCode(httpCode);
-    if (CURLE_OK == errCd && httpCode >= 300 && httpCode < 400)
-        return totalSize;
-
-    if (!d->m_response.responseFired()) {
-        handleLocalReceiveResponse(job, d);
-        if (d->m_cancelled)
-            return 0;
-    }
-
-    if (d->m_multipartHandle)
-        d->m_multipartHandle->contentReceived(static_cast<const char*>(ptr), totalSize);
-    else if (d->client()) {
-        d->client()->didReceiveData(job, ptr, totalSize, 0);
-        CurlCacheManager::getInstance().didReceiveData(*job, ptr, totalSize);
-    }
-
-    return totalSize;
-}
-
 inline static bool isHttpInfo(int statusCode)
 {
     return 100 <= statusCode && statusCode < 200;
@@ -439,6 +690,166 @@
     return true;
 }
 
+size_t ResourceHandle::willPrepareSendData(char* ptr, size_t blockSize, size_t numberOfBlocks)
+{
+    if (!d->m_formDataStream.hasMoreElements())
+        return 0;
+
+    size_t size = d->m_formDataStream.read(ptr, blockSize, numberOfBlocks);
+
+    // Something went wrong so cancel the job.
+    if (!size) {
+        cancel();
+        return 0;
+    }
+
+    return size;
+
+}
+
+void ResourceHandle::didReceiveHeaderLine(const String& header)
+{
+    int splitPos = header.find(":");
+    if (splitPos != notFound) {
+        String key = header.left(splitPos).stripWhiteSpace();
+        String value = header.substring(splitPos + 1).stripWhiteSpace();
+
+        if (isAppendableHeader(key))
+            d->m_response.addHTTPHeaderField(key, value);
+        else
+            d->m_response.setHTTPHeaderField(key, value);
+    } else if (header.startsWith("HTTP", false)) {
+        // This is the first line of the response.
+        // Extract the http status text from this.
+        //
+        // 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.
+        long httpCode = 0;
+        d->m_curlHandle.getResponseCode(httpCode);
+
+        String httpCodeString = String::number(httpCode);
+        int statusCodePos = header.find(httpCodeString);
+
+        if (statusCodePos != notFound) {
+            // The status text is after the status code.
+            String status = header.substring(statusCodePos + httpCodeString.length());
+            d->m_response.setHTTPStatusText(status.stripWhiteSpace());
+        }
+    }
+}
+
+void ResourceHandle::didReceiveAllHeaders(long httpCode, long long contentLength)
+{
+    ASSERT(isMainThread());
+
+    d->m_response.setExpectedContentLength(contentLength);
+
+    d->m_response.setURL(d->m_curlHandle.getEffectiveURL());
+
+    d->m_response.setHTTPStatusCode(httpCode);
+    d->m_response.setMimeType(extractMIMETypeFromMediaType(d->m_response.httpHeaderField(HTTPHeaderName::ContentType)).convertToASCIILowercase());
+    d->m_response.setTextEncodingName(extractCharsetFromMediaType(d->m_response.httpHeaderField(HTTPHeaderName::ContentType)));
+
+    if (d->m_response.isMultipart()) {
+        String boundary;
+        bool parsed = MultipartHandle::extractBoundary(d->m_response.httpHeaderField(HTTPHeaderName::ContentType), boundary);
+        if (parsed)
+            d->m_multipartHandle = std::make_unique<MultipartHandle>(this, boundary);
+    }
+
+    // HTTP redirection
+    if (isHttpRedirect(httpCode)) {
+        String location = d->m_response.httpHeaderField(HTTPHeaderName::Location);
+        if (!location.isEmpty()) {
+            URL newURL = URL(firstRequest().url(), location);
+
+            ResourceRequest redirectedRequest = firstRequest();
+            redirectedRequest.setURL(newURL);
+            ResourceResponse response = d->m_response;
+            if (client())
+                client()->willSendRequest(this, WTFMove(redirectedRequest), WTFMove(response));
+
+            firstRequest().setURL(newURL);
+
+            return;
+        }
+    } else if (isHttpAuthentication(httpCode)) {
+        ProtectionSpace protectionSpace;
+        if (getProtectionSpace(this, d->m_response, protectionSpace)) {
+            Credential credential;
+            AuthenticationChallenge challenge(protectionSpace, credential, d->m_authFailureCount, d->m_response, ResourceError());
+            challenge.setAuthenticationClient(this);
+            this->didReceiveAuthenticationChallenge(challenge);
+            d->m_authFailureCount++;
+            return;
+        }
+    }
+
+    if (client()) {
+        if (isHttpNotModified(httpCode)) {
+            const String& url = ""
+            if (CurlCacheManager::getInstance().getCachedResponse(url, d->m_response)) {
+                if (d->m_addedCacheValidationHeaders) {
+                    d->m_response.setHTTPStatusCode(200);
+                    d->m_response.setHTTPStatusText("OK");
+                }
+            }
+        }
+        client()->didReceiveResponse(this, ResourceResponse(d->m_response));
+        CurlCacheManager::getInstance().didReceiveResponse(*this, d->m_response);
+    }
+
+    d->m_response.setResponseFired(true);
+}
+
+void ResourceHandle::didReceiveContentData()
+{
+    ASSERT(isMainThread());
+
+    if (!d->m_response.responseFired())
+        handleLocalReceiveResponse();
+
+    Vector<char> buffer;
+    {
+        LockHolder locker { m_receivedBufferMutex };
+        buffer = WTFMove(m_receivedBuffer);
+    }
+
+    char* ptr = buffer.begin();
+    size_t size = buffer.size();
+
+    if (d->m_multipartHandle)
+        d->m_multipartHandle->contentReceived(static_cast<const char*>(ptr), size);
+    else if (client()) {
+        client()->didReceiveData(this, ptr, size, 0);
+        CurlCacheManager::getInstance().didReceiveData(*this, ptr, size);
+    }
+}
+
+/* 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 ResourceHandle::readCallback(char* ptr, size_t size, size_t nmemb, void* data)
+{
+    ASSERT(!isMainThread());
+
+    ResourceHandle* job = static_cast<ResourceHandle*>(data);
+    ResourceHandleInternal* d = job->getInternal();
+
+    if (d->m_cancelled)
+        return 0;
+
+    // We should never be called when deferred loading is activated.
+    ASSERT(!d->m_defersLoading);
+
+    if (!size || !nmemb)
+        return 0;
+
+    return job->willPrepareSendData(ptr, size, nmemb);
+}
+
 /*
 * This is being called for each HTTP header in the response. This includes '\r\n'
 * for the last line of the header.
@@ -448,8 +859,10 @@
 * update the ResourceResponse and then send it away.
 *
 */
-static size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* data)
+size_t ResourceHandle::headerCallback(char* ptr, size_t size, size_t nmemb, void* data)
 {
+    ASSERT(!isMainThread());
+
     ResourceHandle* job = static_cast<ResourceHandle*>(data);
     ResourceHandleInternal* d = job->getInternal();
     if (d->m_cancelled)
@@ -459,7 +872,6 @@
     ASSERT(!d->m_defersLoading);
 
     size_t totalSize = size * nmemb;
-    ResourceHandleClient* client = d->client();
 
     String header(static_cast<const char*>(ptr), totalSize);
 
@@ -470,7 +882,7 @@
     * The HTTP standard requires to use \r\n but for compatibility it recommends to
     * accept also \n.
     */
-    if (header == String("\r\n") || header == String("\n")) {
+    if (header == AtomicString("\r\n") || header == AtomicString("\n")) {
         long httpCode = 0;
         d->m_curlHandle.getResponseCode(httpCode);
 
@@ -486,108 +898,24 @@
 
         long long contentLength = 0;
         d->m_curlHandle.getContentLenghtDownload(contentLength);
-        d->m_response.setExpectedContentLength(contentLength);
 
-        d->m_response.setURL(d->m_curlHandle.getEffectiveURL());
+        callOnMainThread([job = RefPtr<ResourceHandle>(job), httpCode, contentLength] {
+            if (!job->d->m_cancelled)
+                job->didReceiveAllHeaders(httpCode, contentLength);
+        });
+    } else
+        job->didReceiveHeaderLine(header);
 
-        d->m_response.setHTTPStatusCode(httpCode);
-        d->m_response.setMimeType(extractMIMETypeFromMediaType(d->m_response.httpHeaderField(HTTPHeaderName::ContentType)).convertToASCIILowercase());
-        d->m_response.setTextEncodingName(extractCharsetFromMediaType(d->m_response.httpHeaderField(HTTPHeaderName::ContentType)));
-
-        if (d->m_response.isMultipart()) {
-            String boundary;
-            bool parsed = MultipartHandle::extractBoundary(d->m_response.httpHeaderField(HTTPHeaderName::ContentType), boundary);
-            if (parsed)
-                d->m_multipartHandle = std::make_unique<MultipartHandle>(job, boundary);
-        }
-
-        // HTTP redirection
-        if (isHttpRedirect(httpCode)) {
-            String location = d->m_response.httpHeaderField(HTTPHeaderName::Location);
-            if (!location.isEmpty()) {
-                URL newURL = URL(job->firstRequest().url(), location);
-
-                ResourceRequest redirectedRequest = job->firstRequest();
-                redirectedRequest.setURL(newURL);
-                ResourceResponse response = d->m_response;
-                if (client)
-                    client->willSendRequest(job, WTFMove(redirectedRequest), WTFMove(response));
-
-                d->m_firstRequest.setURL(newURL);
-
-                return totalSize;
-            }
-        } else if (isHttpAuthentication(httpCode)) {
-            ProtectionSpace protectionSpace;
-            if (getProtectionSpace(job, d->m_response, protectionSpace)) {
-                Credential credential;
-                AuthenticationChallenge challenge(protectionSpace, credential, d->m_authFailureCount, d->m_response, ResourceError());
-                challenge.setAuthenticationClient(job);
-                job->didReceiveAuthenticationChallenge(challenge);
-                d->m_authFailureCount++;
-                return totalSize;
-            }
-        }
-
-        if (client) {
-            if (isHttpNotModified(httpCode)) {
-                const String& url = ""
-                if (CurlCacheManager::getInstance().getCachedResponse(url, d->m_response)) {
-                    if (d->m_addedCacheValidationHeaders) {
-                        d->m_response.setHTTPStatusCode(200);
-                        d->m_response.setHTTPStatusText("OK");
-                    }
-                }
-            }
-            client->didReceiveResponse(job, ResourceResponse(d->m_response));
-            CurlCacheManager::getInstance().didReceiveResponse(*job, d->m_response);
-        }
-        d->m_response.setResponseFired(true);
-
-    } else {
-        int splitPos = header.find(":");
-        if (splitPos != -1) {
-            String key = header.left(splitPos).stripWhiteSpace();
-            String value = header.substring(splitPos + 1).stripWhiteSpace();
-
-            if (isAppendableHeader(key))
-                d->m_response.addHTTPHeaderField(key, value);
-            else
-                d->m_response.setHTTPHeaderField(key, value);
-        } else if (header.startsWith("HTTP", false)) {
-            // This is the first line of the response.
-            // Extract the http status text from this.
-            //
-            // 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.
-            long httpCode = 0;
-            d->m_curlHandle.getResponseCode(httpCode);
-
-            String httpCodeString = String::number(httpCode);
-            int statusCodePos = header.find(httpCodeString);
-
-            if (statusCodePos != -1) {
-                // The status text is after the status code.
-                String status = header.substring(statusCodePos + httpCodeString.length());
-                d->m_response.setHTTPStatusText(status.stripWhiteSpace());
-            }
-
-        }
-    }
-
     return totalSize;
 }
 
-/* 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 readCallback(char* ptr, size_t size, size_t nmemb, void* data)
+// called with data after all headers have been processed via headerCallback
+size_t ResourceHandle::writeCallback(char* ptr, size_t size, size_t nmemb, void* data)
 {
+    ASSERT(!isMainThread());
+
     ResourceHandle* job = static_cast<ResourceHandle*>(data);
     ResourceHandleInternal* d = job->getInternal();
-
     if (d->m_cancelled)
         return 0;
 
@@ -594,112 +922,83 @@
     // We should never be called when deferred loading is activated.
     ASSERT(!d->m_defersLoading);
 
-    if (!size || !nmemb)
-        return 0;
+    size_t totalSize = size * nmemb;
 
-    if (!d->m_formDataStream.hasMoreElements())
-        return 0;
+    // 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
+    long httpCode = 0;
+    CURLcode errCd = d->m_curlHandle.getResponseCode(httpCode);
+    if (CURLE_OK == errCd && httpCode >= 300 && httpCode < 400)
+        return totalSize;
 
-    size_t sent = d->m_formDataStream.read(ptr, size, nmemb);
+    bool shouldCall { false };
+    {
+        LockHolder locker(job->m_receivedBufferMutex);
+        
+        if (job->m_receivedBuffer.isEmpty())
+            shouldCall = true;
+        
+        job->m_receivedBuffer.append(ptr, totalSize);
+    }
 
-    // Something went wrong so cancel the job.
-    if (!sent)
-        job->cancel();
+    if (shouldCall) {
+        callOnMainThread([job = RefPtr<ResourceHandle>(job)] {
+            if (!job->d->m_cancelled)
+                job->didReceiveContentData();
+        });
+    }
 
-    return sent;
+    return totalSize;
 }
 
-static inline size_t getFormElementsCount(ResourceHandle* job)
+// sync loader
+
+void ResourceHandle::platformLoadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
 {
-    RefPtr<FormData> formData = job->firstRequest().httpBody();
+    ASSERT(isMainThread());
 
-    if (!formData)
-        return 0;
+    SynchronousLoaderClient client;
+    RefPtr<ResourceHandle> handle = adoptRef(new ResourceHandle(context, request, &client, false, false));
 
-    // Resolve the blob elements so the formData can correctly report it's size.
-    formData = formData->resolveBlobReferences();
-    size_t size = formData->elements().size();
-    job->firstRequest().setHTTPBody(WTFMove(formData));
+    handle.get()->dispatchSynchronousJob();
 
-    return size;
+    error = client.error();
+    data.swap(client.mutableData());
+    response = client.response();
 }
 
-static void setupFormData(ResourceHandle* job, bool isPostRequest)
+void ResourceHandle::dispatchSynchronousJob()
 {
-    ResourceHandleInternal* d = job->getInternal();
-    Vector<FormDataElement> elements = job->firstRequest().httpBody()->elements();
-    size_t numElements = elements.size();
+    URL kurl = firstRequest().url();
 
-    static const long long maxCurlOffT = d->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();
+    if (kurl.protocolIsData()) {
+        handleDataURL();
+        return;
     }
 
-    // cURL guesses that we want chunked encoding as long as we specify the header
-    if (chunkedTransfer)
-        d->m_curlHandle.appendRequestHeader("Transfer-Encoding: chunked");
-    else {
-        if (isPostRequest)
-            d->m_curlHandle.setPostFieldLarge(size);
-        else
-            d->m_curlHandle.setInFileSizeLarge(size);
-    }
-
-    d->m_curlHandle.setReadCallbackFunction(readCallback, job);
-}
-
-void ResourceHandle::setupPUT()
-{
     ResourceHandleInternal* d = getInternal();
-    d->m_curlHandle.enableHttpPutRequest();
 
-    // Disable the Expect: 100 continue header
-    d->m_curlHandle.appendRequestHeader("Expect:");
+    // If defersLoading is true and we call curl_easy_perform
+    // on a paused handle, libcURL would do the transfert anyway
+    // and we would assert so force defersLoading to be false.
+    d->m_defersLoading = false;
 
-    size_t numElements = getFormElementsCount(this);
-    if (!numElements)
-        return;
+    initialize();
 
-    setupFormData(this, false);
-}
+    // curl_easy_perform blocks until the transfert is finished.
+    CURLcode ret = d->m_curlHandle.perform();
 
-void ResourceHandle::setupPOST()
-{
-    ResourceHandleInternal* d = getInternal();
-    d->m_curlHandle.enableHttpPostRequest();
+#if ENABLE(WEB_TIMING)
+    calculateWebTimingInformations();
+#endif
 
-    size_t numElements = getFormElementsCount(this);
-    if (!numElements)
-        return;
-
-    // Do not stream for simple POST data
-    if (numElements == 1) {
-        firstRequest().httpBody()->flatten(d->m_postBytes);
-        if (d->m_postBytes.size())
-            d->m_curlHandle.setPostFields(d->m_postBytes.data(), d->m_postBytes.size());
-        return;
+    if (client()) {
+        if (ret != CURLE_OK)
+            client()->didFail(this, ResourceError(d->m_curlHandle, d->m_sslErrors));
+        else
+            client()->didReceiveResponse(this, ResourceResponse(d->m_response));
     }
-
-    setupFormData(this, true);
 }
 
 void ResourceHandle::handleDataURL()
@@ -763,218 +1062,6 @@
         client()->didFinishLoading(this);
 }
 
-void ResourceHandle::dispatchSynchronousJob()
-{
-    URL kurl = firstRequest().url();
-
-    if (kurl.protocolIsData()) {
-        handleDataURL();
-        return;
-    }
-
-    ResourceHandleInternal* d = getInternal();
-
-    // If defersLoading is true and we call curl_easy_perform
-    // on a paused handle, libcURL would do the transfert anyway
-    // and we would assert so force defersLoading to be false.
-    d->m_defersLoading = false;
-
-    initialize();
-
-    // curl_easy_perform blocks until the transfert is finished.
-    CURLcode ret = d->m_curlHandle.perform();
-
-    if (ret != CURLE_OK) {
-        ResourceError error(ASCIILiteral(errorDomainCurl), ret, kurl, String(curl_easy_strerror(ret)));
-        error.setSSLErrors(d->m_sslErrors);
-        d->client()->didFail(this, error);
-    } else {
-        if (d->client())
-            d->client()->didReceiveResponse(this, ResourceResponse(d->m_response));
-    }
-
-#if ENABLE(WEB_TIMING)
-    calculateWebTimingInformations(d);
-#endif
-}
-
-void ResourceHandle::applyAuthentication()
-{
-    ResourceRequest& request = firstRequest();
-    // m_user/m_pass are credentials given manually, for instance, by the arguments passed to XMLHttpRequest.open().
-    ResourceHandleInternal* d = getInternal();
-
-    String partition = request.cachePartition();
-
-    if (shouldUseCredentialStorage()) {
-        if (d->m_user.isEmpty() && d->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.
-            d->m_initialCredential = CredentialStorage::defaultCredentialStorage().get(partition, request.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(d->m_user, d->m_pass, CredentialPersistenceNone), request.url());
-        }
-    }
-
-    String user = d->m_user;
-    String password = d->m_pass;
-
-    if (!d->m_initialCredential.isEmpty()) {
-        user = d->m_initialCredential.user();
-        password = d->m_initialCredential.password();
-        d->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.
-
-    // curl CURLOPT_USERPWD expects username:password
-    d->m_curlHandle.setHttpAuthUserPass(user, password);
-}
-
-void ResourceHandle::initialize()
-{
-    CurlContext& context = CurlContext::singleton();
-
-    URL url = ""
-
-    // Remove any fragment part, otherwise curl will send it as part of the request.
-    url.removeFragmentIdentifier();
-
-    ResourceHandleInternal* d = getInternal();
-    String urlString = url.string();
-
-    if (url.isLocalFile()) {
-        // Remove any query part sent to a local file.
-        if (!url.query().isEmpty()) {
-            // By setting the query to a null string it'll be removed.
-            url.setQuery(String());
-            urlString = url.string();
-        }
-        // Determine the MIME type based on the path.
-        d->m_response.setMimeType(MIMETypeRegistry::getMIMETypeForPath(url));
-    }
-
-    if (d->m_defersLoading) {
-        CURLcode error = d->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);
-    }
-
-#ifndef NDEBUG
-    d->m_curlHandle.enableVerboseIfUsed();
-    d->m_curlHandle.enableStdErrIfUsed();
-#endif
-
-    d->m_curlHandle.setSslVerifyPeer(CurlHandle::VerifyPeerEnable);
-    d->m_curlHandle.setSslVerifyHost(CurlHandle::VerifyHostStrictNameCheck);
-    d->m_curlHandle.setPrivateData(this);
-    d->m_curlHandle.setWriteCallbackFunction(writeCallback, this);
-    d->m_curlHandle.setHeaderCallbackFunction(headerCallback, this);
-    d->m_curlHandle.enableAutoReferer();
-    d->m_curlHandle.enableFollowLocation();
-    d->m_curlHandle.enableHttpAuthentication(CURLAUTH_ANY);
-    d->m_curlHandle.enableShareHandle();
-    d->m_curlHandle.enableTimeout();
-    d->m_curlHandle.enableAllowedProtocols();
-    setSSLClientCertificate(this);
-
-    if (CurlContext::singleton().shouldIgnoreSSLErrors())
-        d->m_curlHandle.setSslVerifyPeer(CurlHandle::VerifyPeerDisable);
-    else
-        setSSLVerifyOptions(this);
-
-    d->m_curlHandle.enableCAInfoIfExists();
-
-    d->m_curlHandle.enableAcceptEncoding();
-    d->m_curlHandle.setUrl(urlString);
-    d->m_curlHandle.enableCookieJarIfExists();
-
-    d->m_curlHandle.clearRequestHeaders();
-
-    if (firstRequest().httpHeaderFields().size() > 0) {
-        HTTPHeaderMap customHeaders = firstRequest().httpHeaderFields();
-
-        bool hasCacheHeaders = customHeaders.contains(HTTPHeaderName::IfModifiedSince) || customHeaders.contains(HTTPHeaderName::IfNoneMatch);
-        if (!hasCacheHeaders && CurlCacheManager::getInstance().isCached(url)) {
-            CurlCacheManager::getInstance().addCacheEntryClient(url, this);
-            HTTPHeaderMap& requestHeaders = CurlCacheManager::getInstance().requestHeaders(url);
-
-            // append additional cache information
-            HTTPHeaderMap::const_iterator it = requestHeaders.begin();
-            HTTPHeaderMap::const_iterator end = requestHeaders.end();
-            while (it != end) {
-                customHeaders.set(it->key, it->value);
-                ++it;
-            }
-            d->m_addedCacheValidationHeaders = true;
-        }
-
-        for (auto customHeader : customHeaders)
-            d->m_curlHandle.appendRequestHeader(customHeader.key, customHeader.value);
-    }
-
-    String method = firstRequest().httpMethod();
-    if ("GET" == method)
-        d->m_curlHandle.enableHttpGetRequest();
-    else if ("POST" == method)
-        setupPOST();
-    else if ("PUT" == method)
-        setupPUT();
-    else if ("HEAD" == method)
-        d->m_curlHandle.enableHttpHeadRequest();
-    else {
-        d->m_curlHandle.setHttpCustomRequest(method);
-        setupPUT();
-    }
-
-    d->m_curlHandle.enableRequestHeaders();
-
-    applyAuthentication();
-
-    d->m_curlHandle.enableProxyIfExists();
-}
-
-void ResourceHandle::handleCurlMsg(CURLMsg* msg)
-{
-    ResourceHandleInternal* d = getInternal();
-
-    if (CURLE_OK == msg->data.result) {
-#if ENABLE(WEB_TIMING)
-        calculateWebTimingInformations(d);
-#endif
-        if (!d->m_response.responseFired()) {
-            handleLocalReceiveResponse(this, d);
-            if (d->m_cancelled)
-                return;
-        }
-
-        if (d->m_multipartHandle)
-            d->m_multipartHandle->contentEnded();
-
-        if (d->client()) {
-            d->client()->didFinishLoading(this);
-            CurlCacheManager::getInstance().didFinishLoading(*this);
-        }
-    } else {
-        URL url = ""
-#ifndef NDEBUG
-        fprintf(stderr, "Curl ERROR for url='', error: '%s'\n", url.string().utf8().data(), curl_easy_strerror(msg->data.result));
-#endif
-        if (d->client()) {
-            ResourceError resourceError(ASCIILiteral(errorDomainCurl), msg->data.result, url, String(curl_easy_strerror(msg->data.result)));
-            resourceError.setSSLErrors(d->m_sslErrors);
-            d->client()->didFail(this, resourceError);
-            CurlCacheManager::getInstance().didFail(*this);
-        }
-    }
-}
-
 } // namespace WebCore
 
 #endif

Deleted: trunk/Source/WebCore/platform/network/curl/ResourceHandleManager.cpp (219605 => 219606)


--- trunk/Source/WebCore/platform/network/curl/ResourceHandleManager.cpp	2017-07-18 07:20:33 UTC (rev 219605)
+++ trunk/Source/WebCore/platform/network/curl/ResourceHandleManager.cpp	2017-07-18 07:20:34 UTC (rev 219606)
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2004, 2006 Apple Inc.  All rights reserved.
- * Copyright (C) 2006 Michael Emmel [email protected]
- * Copyright (C) 2007 Alp Toker <[email protected]>
- * Copyright (C) 2007 Holger Hans Peter Freyther
- * Copyright (C) 2008 Collabora Ltd.
- * Copyright (C) 2008 Nuanti Ltd.
- * Copyright (C) 2009 Appcelerator Inc.
- * Copyright (C) 2009 Brent Fulgham <[email protected]>
- * Copyright (C) 2010 Patrick Gansterer <[email protected]>
- * Copyright (C) 2013 Peter Gal <[email protected]>, University of Szeged
- * Copyright (C) 2013 Alex Christensen <[email protected]>
- * Copyright (C) 2013 University of Szeged
- * 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. ``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
- * 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 "ResourceHandleManager.h"
-
-#if USE(CURL)
-
-#include "CredentialStorage.h"
-#include "HTTPHeaderNames.h"
-#include "HTTPParsers.h"
-#include "MultipartHandle.h"
-#include "ResourceError.h"
-#include "ResourceHandle.h"
-#include "ResourceHandleClient.h"
-#include "ResourceHandleInternal.h"
-#include "ResourceRequest.h"
-#include "ResourceResponse.h"
-#include "SSLHandle.h"
-#include "TextEncoding.h"
-#include <wtf/text/CString.h>
-#include <wtf/text/StringView.h>
-
-#if OS(WINDOWS)
-#else
-#include <sys/param.h>
-#define MAX_PATH MAXPATHLEN
-#endif
-
-#include <errno.h>
-#include <stdio.h>
-#if ENABLE(WEB_TIMING)
-#include <wtf/CurrentTime.h>
-#endif
-#include <wtf/Lock.h>
-#include <wtf/Threading.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-const int selectTimeoutMS = 5;
-static const Seconds pollTime { 50_ms };
-const int maxRunningJobs = 128;
-
-ResourceHandleManager::ResourceHandleManager()
-    : m_downloadTimer(*this, &ResourceHandleManager::downloadTimerCallback)
-    , m_runningJobs(0)
-{
-
-}
-
-ResourceHandleManager::~ResourceHandleManager()
-{
-
-}
-
-ResourceHandleManager* ResourceHandleManager::sharedInstance()
-{
-    static ResourceHandleManager* sharedInstance = 0;
-    if (!sharedInstance)
-        sharedInstance = new ResourceHandleManager();
-    return sharedInstance;
-}
-
-void ResourceHandleManager::downloadTimerCallback()
-{
-    startScheduledJobs();
-
-    fd_set fdread;
-    fd_set fdwrite;
-    fd_set fdexcep;
-    int maxfd = 0;
-
-    struct timeval timeout;
-    timeout.tv_sec = 0;
-    timeout.tv_usec = selectTimeoutMS * 1000;       // select waits microseconds
-
-    // Retry 'select' if it was interrupted by a process signal.
-    int rc = 0;
-    do {
-        m_curlMultiHandle.getFdSet(fdread, fdwrite, fdexcep, maxfd);
-
-        // When the 3 file descriptors are empty, winsock will return -1
-        // and bail out, stopping the file download. So make sure we
-        // have valid file descriptors before calling select.
-        if (maxfd >= 0)
-            rc = ::select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);
-    } while (rc == -1 && errno == EINTR);
-
-    if (-1 == rc) {
-#ifndef NDEBUG
-        perror("bad: select() returned -1: ");
-#endif
-        return;
-    }
-
-    int runningHandles = 0;
-    while (m_curlMultiHandle.perform(runningHandles) == CURLM_CALL_MULTI_PERFORM) { }
-
-    // check the curl messages indicating completed transfers
-    // and free their resources
-    while (true) {
-        int messagesInQueue = 0;
-        CURLMsg* msg = m_curlMultiHandle.readInfo(messagesInQueue);
-        if (!msg)
-            break;
-
-        // find the node which has same d->m_handle as completed transfer
-        CURL* handle = msg->easy_handle;
-        ASSERT(handle);
-        ResourceHandle* job = nullptr;
-        CURLcode err = curl_easy_getinfo(handle, CURLINFO_PRIVATE, &job);
-        ASSERT_UNUSED(err, CURLE_OK == err);
-        ASSERT(job);
-        if (!job)
-            continue;
-        ResourceHandleInternal* d = job->getInternal();
-
-        if (d->m_cancelled) {
-            removeFromCurl(job);
-            continue;
-        }
-
-        if (CURLMSG_DONE != msg->msg)
-            continue;
-
-        job->handleCurlMsg(msg);
-        removeFromCurl(job);
-    }
-
-    bool started = startScheduledJobs(); // new jobs might have been added in the meantime
-
-    if (!m_downloadTimer.isActive() && (started || (runningHandles > 0)))
-        m_downloadTimer.startOneShot(pollTime);
-}
-
-void ResourceHandleManager::removeFromCurl(ResourceHandle* job)
-{
-    ResourceHandleInternal* d = job->getInternal();
-    ASSERT(d->m_curlHandle.handle());
-    if (!d->m_curlHandle.handle())
-        return;
-    m_runningJobs--;
-
-    m_curlMultiHandle.removeHandle(d->m_curlHandle.handle());
-    job->deref();
-}
-
-void ResourceHandleManager::add(ResourceHandle* job)
-{
-    // we can be called from within curl, so to avoid re-entrancy issues
-    // schedule this job to be added the next time we enter curl download loop
-    job->ref();
-    m_resourceHandleList.append(job);
-    if (!m_downloadTimer.isActive())
-        m_downloadTimer.startOneShot(pollTime);
-}
-
-bool ResourceHandleManager::removeScheduledJob(ResourceHandle* job)
-{
-    int size = m_resourceHandleList.size();
-    for (int i = 0; i < size; i++) {
-        if (job == m_resourceHandleList[i]) {
-            m_resourceHandleList.remove(i);
-            job->deref();
-            return true;
-        }
-    }
-    return false;
-}
-
-bool ResourceHandleManager::startScheduledJobs()
-{
-    // TODO: Create a separate stack of jobs for each domain.
-
-    bool started = false;
-    while (!m_resourceHandleList.isEmpty() && m_runningJobs < maxRunningJobs) {
-        ResourceHandle* job = m_resourceHandleList[0];
-        m_resourceHandleList.remove(0);
-        startJob(job);
-        started = true;
-    }
-    return started;
-}
-
-void ResourceHandleManager::startJob(ResourceHandle* job)
-{
-    job->initialize();
-
-    m_runningJobs++;
-
-    CURLMcode ret = m_curlMultiHandle.addHandle(job->getInternal()->m_curlHandle.handle());
-
-    // don't call perform, because events must be async
-    // timeout will occur and do curl_multi_perform
-    if (ret && ret != CURLM_CALL_MULTI_PERFORM) {
-#ifndef NDEBUG
-        fprintf(stderr, "Error %d starting job %s\n", ret, encodeWithURLEscapeSequences(job->firstRequest().url().string()).latin1().data());
-#endif
-        job->cancel();
-        return;
-    }
-}
-
-void ResourceHandleManager::cancel(ResourceHandle* job)
-{
-    if (removeScheduledJob(job))
-        return;
-
-    ResourceHandleInternal* d = job->getInternal();
-    d->m_cancelled = true;
-    if (!m_downloadTimer.isActive())
-        m_downloadTimer.startOneShot(pollTime);
-}
-
-} // namespace WebCore
-
-#endif

Deleted: trunk/Source/WebCore/platform/network/curl/ResourceHandleManager.h (219605 => 219606)


--- trunk/Source/WebCore/platform/network/curl/ResourceHandleManager.h	2017-07-18 07:20:33 UTC (rev 219605)
+++ trunk/Source/WebCore/platform/network/curl/ResourceHandleManager.h	2017-07-18 07:20:34 UTC (rev 219606)
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Inc.  All rights reserved.
- * Copyright (C) 2006 Michael Emmel [email protected]
- * 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. ``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
- * 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.
- */
-
-#ifndef ResourceHandleManager_h
-#define ResourceHandleManager_h
-
-#include "CurlContext.h"
-#include "Frame.h"
-#include "Timer.h"
-#include "ResourceHandleClient.h"
-
-#if PLATFORM(WIN)
-#include <winsock2.h>
-#include <windows.h>
-#endif
-
-#include <wtf/Vector.h>
-#include <wtf/text/CString.h>
-#include <wtf/text/WTFString.h>
-
-namespace WebCore {
-
-class ResourceHandleManager {
-public:
-    static ResourceHandleManager* sharedInstance();
-    void add(ResourceHandle*);
-    void cancel(ResourceHandle*);
-
-private:
-    ResourceHandleManager();
-    ~ResourceHandleManager();
-    void downloadTimerCallback();
-    void removeFromCurl(ResourceHandle*);
-    bool removeScheduledJob(ResourceHandle*);
-    void startJob(ResourceHandle*);
-    bool startScheduledJobs();
-
-    Timer m_downloadTimer;
-    Vector<ResourceHandle*> m_resourceHandleList;
-    int m_runningJobs;
-
-    CurlMultiHandle m_curlMultiHandle;
-};
-
-}
-
-#endif
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to