Title: [218637] trunk/Source/WebCore
Revision
218637
Author
[email protected]
Date
2017-06-21 09:48:43 -0700 (Wed, 21 Jun 2017)

Log Message

[Curl] Extract CurlDownloadManager as shared background task handler
https://bugs.webkit.org/show_bug.cgi?id=173557

Curl resource handling should be shared by other part of Curl
network stack. CurlDownloadManager is extracted as stand alone
CurlManager singleton class to be ready for others
(i.e. ResourceHandle).

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

* PlatformWinCairo.cmake:
* platform/network/curl/CookieJarCurl.cpp:
(WebCore::setCookiesFromDOM):
(WebCore::cookiesForSession):
* platform/network/curl/CurlDownload.cpp:
(WebCore::CurlDownload::init):
(WebCore::CurlDownload::start):
(WebCore::CurlDownload::cancel):
(WebCore::CurlDownload::didReceiveHeader):
(WebCore::CurlDownload::handleCurlMsg):
(WebCore::CurlDownloadManager::CurlDownloadManager): Deleted.
(WebCore::CurlDownloadManager::~CurlDownloadManager): Deleted.
(WebCore::CurlDownloadManager::add): Deleted.
(WebCore::CurlDownloadManager::remove): Deleted.
(WebCore::CurlDownloadManager::getActiveDownloadCount): Deleted.
(WebCore::CurlDownloadManager::getPendingDownloadCount): Deleted.
(WebCore::CurlDownloadManager::startThreadIfNeeded): Deleted.
(WebCore::CurlDownloadManager::stopThread): Deleted.
(WebCore::CurlDownloadManager::stopThreadIfIdle): Deleted.
(WebCore::CurlDownloadManager::updateHandleList): Deleted.
(WebCore::CurlDownloadManager::addToCurl): Deleted.
(WebCore::CurlDownloadManager::removeFromCurl): Deleted.
(WebCore::CurlDownloadManager::downloadThread): Deleted.
* platform/network/curl/CurlDownload.h:
(WebCore::CurlDownloadManager::getMultiHandle): Deleted.
(WebCore::CurlDownloadManager::runThread): Deleted.
(WebCore::CurlDownloadManager::setRunThread): Deleted.
* platform/network/curl/CurlManager.cpp: Added.
(WebCore::CurlManager::CurlManager):
(WebCore::CurlManager::~CurlManager):
(WebCore::CurlManager::add):
(WebCore::CurlManager::remove):
(WebCore::CurlManager::getActiveCount):
(WebCore::CurlManager::getPendingCount):
(WebCore::CurlManager::startThreadIfNeeded):
(WebCore::CurlManager::stopThread):
(WebCore::CurlManager::stopThreadIfIdle):
(WebCore::CurlManager::updateHandleList):
(WebCore::CurlManager::addToCurl):
(WebCore::CurlManager::removeFromCurl):
(WebCore::CurlManager::workerThread):
(WebCore::CurlUtils::getEffectiveURL):
(WebCore::CurlSharedResources::mutexFor):
(WebCore::CurlSharedResources::lock):
(WebCore::CurlSharedResources::unlock):
* platform/network/curl/CurlManager.h: Added.
(WebCore::CurlManager::singleton):
(WebCore::CurlManager::getCurlShareHandle):
(WebCore::CurlManager::getMultiHandle):
(WebCore::CurlManager::runThread):
(WebCore::CurlManager::setRunThread):
* platform/network/curl/ResourceHandleManager.cpp:
(WebCore::ResourceHandleManager::ResourceHandleManager):
(WebCore::ResourceHandleManager::~ResourceHandleManager):
(WebCore::handleLocalReceiveResponse):
(WebCore::getProtectionSpace):
(WebCore::headerCallback):
(WebCore::ResourceHandleManager::downloadTimerCallback):
(WebCore::getCurlEffectiveURL): Deleted.
(WebCore::sharedResourceMutex): Deleted.
(WebCore::curl_lock_callback): Deleted.
(WebCore::curl_unlock_callback): Deleted.
(WebCore::ResourceHandleManager::getCurlShareHandle): Deleted.
* platform/network/curl/ResourceHandleManager.h:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (218636 => 218637)


--- trunk/Source/WebCore/ChangeLog	2017-06-21 16:25:16 UTC (rev 218636)
+++ trunk/Source/WebCore/ChangeLog	2017-06-21 16:48:43 UTC (rev 218637)
@@ -1,3 +1,80 @@
+2017-06-21  Basuke Suzuki  <[email protected]>
+
+        [Curl] Extract CurlDownloadManager as shared background task handler
+        https://bugs.webkit.org/show_bug.cgi?id=173557
+
+        Curl resource handling should be shared by other part of Curl
+        network stack. CurlDownloadManager is extracted as stand alone
+        CurlManager singleton class to be ready for others
+        (i.e. ResourceHandle).
+
+        Reviewed by Alex Christensen.
+
+        * PlatformWinCairo.cmake:
+        * platform/network/curl/CookieJarCurl.cpp:
+        (WebCore::setCookiesFromDOM):
+        (WebCore::cookiesForSession):
+        * platform/network/curl/CurlDownload.cpp:
+        (WebCore::CurlDownload::init):
+        (WebCore::CurlDownload::start):
+        (WebCore::CurlDownload::cancel):
+        (WebCore::CurlDownload::didReceiveHeader):
+        (WebCore::CurlDownload::handleCurlMsg):
+        (WebCore::CurlDownloadManager::CurlDownloadManager): Deleted.
+        (WebCore::CurlDownloadManager::~CurlDownloadManager): Deleted.
+        (WebCore::CurlDownloadManager::add): Deleted.
+        (WebCore::CurlDownloadManager::remove): Deleted.
+        (WebCore::CurlDownloadManager::getActiveDownloadCount): Deleted.
+        (WebCore::CurlDownloadManager::getPendingDownloadCount): Deleted.
+        (WebCore::CurlDownloadManager::startThreadIfNeeded): Deleted.
+        (WebCore::CurlDownloadManager::stopThread): Deleted.
+        (WebCore::CurlDownloadManager::stopThreadIfIdle): Deleted.
+        (WebCore::CurlDownloadManager::updateHandleList): Deleted.
+        (WebCore::CurlDownloadManager::addToCurl): Deleted.
+        (WebCore::CurlDownloadManager::removeFromCurl): Deleted.
+        (WebCore::CurlDownloadManager::downloadThread): Deleted.
+        * platform/network/curl/CurlDownload.h:
+        (WebCore::CurlDownloadManager::getMultiHandle): Deleted.
+        (WebCore::CurlDownloadManager::runThread): Deleted.
+        (WebCore::CurlDownloadManager::setRunThread): Deleted.
+        * platform/network/curl/CurlManager.cpp: Added.
+        (WebCore::CurlManager::CurlManager):
+        (WebCore::CurlManager::~CurlManager):
+        (WebCore::CurlManager::add):
+        (WebCore::CurlManager::remove):
+        (WebCore::CurlManager::getActiveCount):
+        (WebCore::CurlManager::getPendingCount):
+        (WebCore::CurlManager::startThreadIfNeeded):
+        (WebCore::CurlManager::stopThread):
+        (WebCore::CurlManager::stopThreadIfIdle):
+        (WebCore::CurlManager::updateHandleList):
+        (WebCore::CurlManager::addToCurl):
+        (WebCore::CurlManager::removeFromCurl):
+        (WebCore::CurlManager::workerThread):
+        (WebCore::CurlUtils::getEffectiveURL):
+        (WebCore::CurlSharedResources::mutexFor):
+        (WebCore::CurlSharedResources::lock):
+        (WebCore::CurlSharedResources::unlock):
+        * platform/network/curl/CurlManager.h: Added.
+        (WebCore::CurlManager::singleton):
+        (WebCore::CurlManager::getCurlShareHandle):
+        (WebCore::CurlManager::getMultiHandle):
+        (WebCore::CurlManager::runThread):
+        (WebCore::CurlManager::setRunThread):
+        * platform/network/curl/ResourceHandleManager.cpp:
+        (WebCore::ResourceHandleManager::ResourceHandleManager):
+        (WebCore::ResourceHandleManager::~ResourceHandleManager):
+        (WebCore::handleLocalReceiveResponse):
+        (WebCore::getProtectionSpace):
+        (WebCore::headerCallback):
+        (WebCore::ResourceHandleManager::downloadTimerCallback):
+        (WebCore::getCurlEffectiveURL): Deleted.
+        (WebCore::sharedResourceMutex): Deleted.
+        (WebCore::curl_lock_callback): Deleted.
+        (WebCore::curl_unlock_callback): Deleted.
+        (WebCore::ResourceHandleManager::getCurlShareHandle): Deleted.
+        * platform/network/curl/ResourceHandleManager.h:
+
 2017-06-21  Jeremy Jones  <[email protected]>
 
         Include audio/vnd.wave as a valid mime-type for wav files.

Modified: trunk/Source/WebCore/PlatformWinCairo.cmake (218636 => 218637)


--- trunk/Source/WebCore/PlatformWinCairo.cmake	2017-06-21 16:25:16 UTC (rev 218636)
+++ trunk/Source/WebCore/PlatformWinCairo.cmake	2017-06-21 16:48:43 UTC (rev 218637)
@@ -34,6 +34,7 @@
     platform/network/curl/CurlCacheEntry.cpp
     platform/network/curl/CurlCacheManager.cpp
     platform/network/curl/CurlDownload.cpp
+    platform/network/curl/CurlManager.cpp
     platform/network/curl/DNSCurl.cpp
     platform/network/curl/FormDataStreamCurl.cpp
     platform/network/curl/MultipartHandle.cpp

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


--- trunk/Source/WebCore/platform/network/curl/CookieJarCurl.cpp	2017-06-21 16:25:16 UTC (rev 218636)
+++ trunk/Source/WebCore/platform/network/curl/CookieJarCurl.cpp	2017-06-21 16:48:43 UTC (rev 218637)
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
  *  License as published by the Free Software Foundation; either
@@ -20,9 +22,10 @@
 #if USE(CURL)
 
 #include "Cookie.h"
+#include "CurlManager.h"
 #include "NotImplemented.h"
+#include "ResourceHandleManager.h"
 #include "URL.h"
-#include "ResourceHandleManager.h"
 
 #include <wtf/DateMath.h>
 #include <wtf/HashMap.h>
@@ -246,7 +249,7 @@
         return;
 
     const char* cookieJarFileName = ResourceHandleManager::sharedInstance()->getCookieJarFileName();
-    CURLSH* curlsh = ResourceHandleManager::sharedInstance()->getCurlShareHandle();
+    CURLSH* curlsh = CurlManager::singleton().getCurlShareHandle();
 
     curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookieJarFileName);
     curl_easy_setopt(curl, CURLOPT_SHARE, curlsh);
@@ -275,7 +278,7 @@
     if (!curl)
         return cookies;
 
-    CURLSH* curlsh = ResourceHandleManager::sharedInstance()->getCurlShareHandle();
+    CURLSH* curlsh = CurlManager::singleton().getCurlShareHandle();
 
     curl_easy_setopt(curl, CURLOPT_SHARE, curlsh);
 

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


--- trunk/Source/WebCore/platform/network/curl/CurlDownload.cpp	2017-06-21 16:25:16 UTC (rev 218636)
+++ trunk/Source/WebCore/platform/network/curl/CurlDownload.cpp	2017-06-21 16:48:43 UTC (rev 218637)
@@ -31,7 +31,6 @@
 
 #include "HTTPHeaderNames.h"
 #include "HTTPParsers.h"
-#include "ResourceHandleManager.h"
 #include "ResourceRequest.h"
 #include <wtf/MainThread.h>
 #include <wtf/text/CString.h>
@@ -40,197 +39,8 @@
 
 namespace WebCore {
 
-// CurlDownloadManager -------------------------------------------------------------------
-
-CurlDownloadManager::CurlDownloadManager()
-{
-    curl_global_init(CURL_GLOBAL_ALL);
-    m_curlMultiHandle = curl_multi_init();
-}
-
-CurlDownloadManager::~CurlDownloadManager()
-{
-    stopThread();
-    curl_multi_cleanup(m_curlMultiHandle);
-    curl_global_cleanup();
-}
-
-bool CurlDownloadManager::add(CURL* curlHandle)
-{
-    {
-        LockHolder locker(m_mutex);
-        m_pendingHandleList.append(curlHandle);
-    }
-
-    startThreadIfNeeded();
-
-    return true;
-}
-
-bool CurlDownloadManager::remove(CURL* curlHandle)
-{
-    LockHolder locker(m_mutex);
-
-    m_removedHandleList.append(curlHandle);
-
-    return true;
-}
-
-int CurlDownloadManager::getActiveDownloadCount() const
-{
-    LockHolder locker(m_mutex);
-    return m_activeHandleList.size();
-}
-
-int CurlDownloadManager::getPendingDownloadCount() const
-{
-    LockHolder locker(m_mutex);
-    return m_pendingHandleList.size();
-}
-
-void CurlDownloadManager::startThreadIfNeeded()
-{
-    if (!runThread()) {
-        if (m_thread)
-            m_thread->waitForCompletion();
-        setRunThread(true);
-        m_thread = Thread::create(downloadThread, this, "downloadThread");
-    }
-}
-
-void CurlDownloadManager::stopThread()
-{
-    setRunThread(false);
-
-    if (m_thread) {
-        m_thread->waitForCompletion();
-        m_thread = nullptr;
-    }
-}
-
-void CurlDownloadManager::stopThreadIfIdle()
-{
-    if (!getActiveDownloadCount() && !getPendingDownloadCount())
-        setRunThread(false);
-}
-
-void CurlDownloadManager::updateHandleList()
-{
-    LockHolder locker(m_mutex);
-
-    // 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);
-    }
-
-    // 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);
-    }
-}
-
-bool CurlDownloadManager::addToCurl(CURL* curlHandle)
-{
-    CURLMcode retval = curl_multi_add_handle(m_curlMultiHandle, curlHandle);
-    if (retval == CURLM_OK) {
-        m_activeHandleList.append(curlHandle);
-        return true;
-    }
-    return false;
-}
-
-bool CurlDownloadManager::removeFromCurl(CURL* curlHandle)
-{
-    int handlePos = m_activeHandleList.find(curlHandle);
-
-    if (handlePos < 0)
-        return true;
-    
-    CURLMcode retval = curl_multi_remove_handle(m_curlMultiHandle, curlHandle);
-    if (retval == CURLM_OK) {
-        m_activeHandleList.remove(handlePos);
-        curl_easy_cleanup(curlHandle);
-        return true;
-    }
-    return false;
-}
-
-void CurlDownloadManager::downloadThread(void* data)
-{
-    CurlDownloadManager* downloadManager = reinterpret_cast<CurlDownloadManager*>(data);
-
-    while (downloadManager->runThread()) {
-
-        downloadManager->updateHandleList();
-
-        // Retry 'select' if it was interrupted by a process signal.
-        int rc = 0;
-        do {
-            fd_set fdread;
-            fd_set fdwrite;
-            fd_set fdexcep;
-
-            int maxfd = 0;
-
-            const int selectTimeoutMS = 5;
-
-            struct timeval timeout;
-            timeout.tv_sec = 0;
-            timeout.tv_usec = selectTimeoutMS * 1000; // select waits microseconds
-
-            FD_ZERO(&fdread);
-            FD_ZERO(&fdwrite);
-            FD_ZERO(&fdexcep);
-            curl_multi_fdset(downloadManager->getMultiHandle(), &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);
-
-        int activeDownloadCount = 0;
-        while (curl_multi_perform(downloadManager->getMultiHandle(), &activeDownloadCount) == CURLM_CALL_MULTI_PERFORM) { }
-
-        int messagesInQueue = 0;
-        CURLMsg* msg = curl_multi_info_read(downloadManager->getMultiHandle(), &messagesInQueue);
-
-        if (!msg)
-            continue;
-
-        CurlDownload* download = 0;
-        CURLcode err = curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &download);
-        UNUSED_PARAM(err);
-
-        if (msg->msg == CURLMSG_DONE) {
-            if (download) {
-                if (msg->data.result == CURLE_OK) {
-                    callOnMainThread([download] {
-                        download->didFinish();
-                        download->deref(); // This matches the ref() in CurlDownload::start().
-                    });
-                } else {
-                    callOnMainThread([download] {
-                        download->didFail();
-                        download->deref(); // This matches the ref() in CurlDownload::start().
-                    });
-                }
-            }
-            downloadManager->removeFromCurl(msg->easy_handle);
-        }
-
-        downloadManager->stopThreadIfIdle();
-    }
-}
-
 // CurlDownload --------------------------------------------------------------------------
 
-CurlDownloadManager CurlDownload::m_downloadManager;
-
 CurlDownload::CurlDownload() = default;
 
 CurlDownload::~CurlDownload()
@@ -275,7 +85,7 @@
     if (certPath)
         curl_easy_setopt(m_curlHandle, CURLOPT_CAINFO, certPath);
 
-    CURLSH* curlsh = ResourceHandleManager::sharedInstance()->getCurlShareHandle();
+    CURLSH* curlsh = CurlManager::singleton().getCurlShareHandle();
     if (curlsh)
         curl_easy_setopt(m_curlHandle, CURLOPT_SHARE, curlsh);
 
@@ -297,12 +107,12 @@
 bool CurlDownload::start()
 {
     ref(); // CurlDownloadManager::downloadThread will call deref when the download has finished.
-    return m_downloadManager.add(m_curlHandle);
+    return CurlManager::singleton().add(m_curlHandle);
 }
 
 bool CurlDownload::cancel()
 {
-    return m_downloadManager.remove(m_curlHandle);
+    return CurlManager::singleton().remove(m_curlHandle);
 }
 
 String CurlDownload::getTempPath() const
@@ -393,7 +203,7 @@
         UNUSED_PARAM(err);
 
         if (httpCode >= 200 && httpCode < 300) {
-            URL url = ""
+            URL url = ""
             callOnMainThread([this, url = "" protectedThis = makeRef(*this)] {
                 m_response.setURL(url);
                 m_response.setMimeType(extractMIMETypeFromMediaType(m_response.httpHeaderField(HTTPHeaderName::ContentType)));
@@ -506,6 +316,29 @@
         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 (218636 => 218637)


--- trunk/Source/WebCore/platform/network/curl/CurlDownload.h	2017-06-21 16:25:16 UTC (rev 218636)
+++ trunk/Source/WebCore/platform/network/curl/CurlDownload.h	2017-06-21 16:48:43 UTC (rev 218637)
@@ -36,47 +36,10 @@
 #include <winsock2.h>
 #endif
 
-#include <curl/curl.h>
+#include "CurlManager.h"
 
 namespace WebCore {
 
-class CurlDownloadManager {
-public:
-    CurlDownloadManager();
-    ~CurlDownloadManager();
-
-    bool add(CURL* curlHandle);
-    bool remove(CURL* curlHandle);
-
-    int getActiveDownloadCount() const;
-    int getPendingDownloadCount() const;
-
-private:
-    void startThreadIfNeeded();
-    void stopThread();
-    void stopThreadIfIdle();
-
-    void updateHandleList();
-
-    CURLM* getMultiHandle() const { return m_curlMultiHandle; }
-
-    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);
-
-    static void downloadThread(void* data);
-
-    RefPtr<Thread> m_thread;
-    CURLM* m_curlMultiHandle { nullptr };
-    Vector<CURL*> m_pendingHandleList;
-    Vector<CURL*> m_activeHandleList;
-    Vector<CURL*> m_removedHandleList;
-    mutable Lock m_mutex;
-    bool m_runThread { false };
-};
-
 class CurlDownloadListener {
 public:
     virtual void didReceiveResponse() { }
@@ -85,7 +48,7 @@
     virtual void didFail() { }
 };
 
-class CurlDownload : public ThreadSafeRefCounted<CurlDownload> {
+class CurlDownload : public ThreadSafeRefCounted<CurlDownload>, public CurlJob {
 public:
     CurlDownload();
     ~CurlDownload();
@@ -107,6 +70,8 @@
 
     void setDestination(const String& destination) { m_destination = destination; }
 
+    virtual CurlJobAction handleCurlMsg(CURLMsg*);
+
 private:
     void closeFile();
     void moveFileToDestination();
@@ -142,10 +107,6 @@
     bool m_deletesFileUponFailure { false };
     mutable Lock m_mutex;
     CurlDownloadListener* m_listener { nullptr };
-
-    static CurlDownloadManager m_downloadManager;
-
-    friend class CurlDownloadManager;
 };
 
 }

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


--- trunk/Source/WebCore/platform/network/curl/CurlManager.cpp	                        (rev 0)
+++ trunk/Source/WebCore/platform/network/curl/CurlManager.cpp	2017-06-21 16:48:43 UTC (rev 218637)
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2013 Apple Inc.  All rights reserved.
+ * Copyright (C) 2017 Sony Interactive Entertainment Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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"
+
+#if USE(CURL)
+#include "CurlManager.h"
+
+#include <wtf/MainThread.h>
+#include <wtf/text/CString.h>
+
+using namespace WebCore;
+
+namespace WebCore {
+
+class CurlSharedResources {
+public:
+    static void lock(CURL*, curl_lock_data, curl_lock_access, void*);
+    static void unlock(CURL*, curl_lock_data, void*);
+
+private:
+    static Lock* mutexFor(curl_lock_data);
+};
+
+// CurlDownloadManager -------------------------------------------------------------------
+
+CurlManager::CurlManager()
+{
+    curl_global_init(CURL_GLOBAL_ALL);
+    m_curlMultiHandle = curl_multi_init();
+    m_curlShareHandle = curl_share_init();
+    curl_share_setopt(m_curlShareHandle, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
+    curl_share_setopt(m_curlShareHandle, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
+    curl_share_setopt(m_curlShareHandle, CURLSHOPT_LOCKFUNC, CurlSharedResources::lock);
+    curl_share_setopt(m_curlShareHandle, CURLSHOPT_UNLOCKFUNC, CurlSharedResources::unlock);
+}
+
+CurlManager::~CurlManager()
+{
+    stopThread();
+    curl_multi_cleanup(m_curlMultiHandle);
+    curl_share_cleanup(m_curlShareHandle);
+    curl_global_cleanup();
+}
+
+bool CurlManager::add(CURL* curlHandle)
+{
+    ASSERT(isMainThread());
+
+    {
+        LockHolder locker(m_mutex);
+        m_pendingHandleList.append(curlHandle);
+    }
+
+    startThreadIfNeeded();
+
+    return true;
+}
+
+bool CurlManager::remove(CURL* curlHandle)
+{
+    LockHolder locker(m_mutex);
+
+    m_removedHandleList.append(curlHandle);
+
+    return true;
+}
+
+int CurlManager::getActiveCount() const
+{
+    LockHolder locker(m_mutex);
+    return m_activeHandleList.size();
+}
+
+int CurlManager::getPendingCount() const
+{
+    LockHolder locker(m_mutex);
+    return m_pendingHandleList.size();
+}
+
+void CurlManager::startThreadIfNeeded()
+{
+    ASSERT(isMainThread());
+
+    if (!runThread()) {
+        if (m_thread)
+            m_thread->waitForCompletion();
+        setRunThread(true);
+        m_thread = Thread::create(workerThread, this, "curlThread");
+    }
+}
+
+void CurlManager::stopThread()
+{
+    ASSERT(isMainThread());
+
+    setRunThread(false);
+
+    if (m_thread) {
+        m_thread->waitForCompletion();
+        m_thread = nullptr;
+    }
+}
+
+void CurlManager::stopThreadIfIdle()
+{
+    if (!getActiveCount() && !getPendingCount())
+        setRunThread(false);
+}
+
+void CurlManager::updateHandleList()
+{
+    LockHolder locker(m_mutex);
+
+    // 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);
+    }
+
+    // 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);
+    }
+}
+
+bool CurlManager::addToCurl(CURL* curlHandle)
+{
+    CURLMcode retval = curl_multi_add_handle(m_curlMultiHandle, curlHandle);
+    if (retval == CURLM_OK) {
+        m_activeHandleList.append(curlHandle);
+        return true;
+    }
+    return false;
+}
+
+bool CurlManager::removeFromCurl(CURL* curlHandle)
+{
+    int handlePos = m_activeHandleList.find(curlHandle);
+
+    if (handlePos < 0)
+        return true;
+    
+    CURLMcode retval = curl_multi_remove_handle(m_curlMultiHandle, curlHandle);
+    if (retval == CURLM_OK) {
+        m_activeHandleList.remove(handlePos);
+        curl_easy_cleanup(curlHandle);
+        return true;
+    }
+    return false;
+}
+
+void CurlManager::workerThread(void* data)
+{
+    ASSERT(!isMainThread());
+
+    CurlManager* manager = reinterpret_cast<CurlManager*>(data);
+
+    while (manager->runThread()) {
+
+        manager->updateHandleList();
+
+        // Retry 'select' if it was interrupted by a process signal.
+        int rc = 0;
+        do {
+            fd_set fdread;
+            fd_set fdwrite;
+            fd_set fdexcep;
+
+            int maxfd = 0;
+
+            const int selectTimeoutMS = 5;
+
+            struct timeval timeout;
+            timeout.tv_sec = 0;
+            timeout.tv_usec = selectTimeoutMS * 1000; // select waits microseconds
+
+            FD_ZERO(&fdread);
+            FD_ZERO(&fdwrite);
+            FD_ZERO(&fdexcep);
+            curl_multi_fdset(manager->getMultiHandle(), &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);
+
+        int activeCount = 0;
+        while (curl_multi_perform(manager->getMultiHandle(), &activeCount) == CURLM_CALL_MULTI_PERFORM) { }
+
+        int messagesInQueue = 0;
+        CURLMsg* msg = curl_multi_info_read(manager->getMultiHandle(), &messagesInQueue);
+
+        if (!msg)
+            continue;
+
+
+        CurlJob* job = nullptr;
+        CURLcode err = curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &job);
+        UNUSED_PARAM(err);
+        ASSERT(job);
+
+        CurlJobAction action = ""
+
+        if (action == CurlJobAction::Finished)
+            manager->removeFromCurl(msg->easy_handle);
+
+        manager->stopThreadIfIdle();
+    }
+}
+
+// CURL Utilities
+
+URL CurlUtils::getEffectiveURL(CURL* handle)
+{
+    const char* url;
+    CURLcode err = curl_easy_getinfo(handle, CURLINFO_EFFECTIVE_URL, &url);
+    if (CURLE_OK != err)
+        return URL();
+    return URL(URL(), url);
+}
+
+// Shared Resource management =======================
+
+Lock* CurlSharedResources::mutexFor(curl_lock_data data)
+{
+    DEPRECATED_DEFINE_STATIC_LOCAL(Lock, cookieMutex, ());
+    DEPRECATED_DEFINE_STATIC_LOCAL(Lock, dnsMutex, ());
+    DEPRECATED_DEFINE_STATIC_LOCAL(Lock, shareMutex, ());
+
+    switch (data) {
+    case CURL_LOCK_DATA_COOKIE:
+        return &cookieMutex;
+    case CURL_LOCK_DATA_DNS:
+        return &dnsMutex;
+    case CURL_LOCK_DATA_SHARE:
+        return &shareMutex;
+    default:
+        ASSERT_NOT_REACHED();
+        return nullptr;
+    }
+}
+
+// libcurl does not implement its own thread synchronization primitives.
+// these two functions provide mutexes for cookies, and for the global DNS
+// cache.
+void CurlSharedResources::lock(CURL* /* handle */, curl_lock_data data, curl_lock_access /* access */, void* /* userPtr */)
+{
+    if (Lock* mutex = CurlSharedResources::mutexFor(data))
+        mutex->lock();
+}
+
+void CurlSharedResources::unlock(CURL* /* handle */, curl_lock_data data, void* /* userPtr */)
+{
+    if (Lock* mutex = CurlSharedResources::mutexFor(data))
+        mutex->unlock();
+}
+
+}
+
+#endif

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


--- trunk/Source/WebCore/platform/network/curl/CurlManager.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/network/curl/CurlManager.h	2017-06-21 16:48:43 UTC (rev 218637)
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2013 Apple Inc.  All rights reserved.
+ * Copyright (C) 2017 Sony Interactive Entertainment Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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. 
+ */
+
+#pragma once
+
+#include <curl/curl.h>
+#include <wtf/Lock.h>
+#include <wtf/Threading.h>
+
+#if PLATFORM(WIN)
+#include <windows.h>
+#include <winsock2.h>
+#endif
+
+#include "URL.h"
+
+namespace WebCore {
+
+enum class CurlJobAction { None, Finished };
+
+class CurlJob {
+public:
+    virtual CurlJobAction handleCurlMsg(CURLMsg*) = 0;
+};
+
+class CurlManager {
+public:
+    static CurlManager& 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 CurlManager shared;
+        return shared;
+    }
+
+    CurlManager();
+    virtual ~CurlManager();
+
+    bool add(CURL* curlHandle);
+    bool remove(CURL* curlHandle);
+
+    int getActiveCount() const;
+    int getPendingCount() const;
+
+    CURLSH* getCurlShareHandle() const { return m_curlShareHandle; }
+
+private:
+    void startThreadIfNeeded();
+    void stopThread();
+    void stopThreadIfIdle();
+
+    void updateHandleList();
+
+    CURLM* getMultiHandle() const { return m_curlMultiHandle; }
+
+    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);
+
+    static void workerThread(void* data);
+
+    RefPtr<Thread> m_thread;
+    CURLM* m_curlMultiHandle { nullptr };
+    Vector<CURL*> m_pendingHandleList;
+    Vector<CURL*> m_activeHandleList;
+    Vector<CURL*> m_removedHandleList;
+    mutable Lock m_mutex;
+    bool m_runThread { false };
+
+    CURLSH* m_curlShareHandle { nullptr };
+
+    friend class CurlJob;
+};
+
+class CurlUtils {
+public:
+    static URL getEffectiveURL(CURL* handle);
+};
+
+}

Modified: trunk/Source/WebCore/platform/network/curl/ResourceHandleManager.cpp (218636 => 218637)


--- trunk/Source/WebCore/platform/network/curl/ResourceHandleManager.cpp	2017-06-21 16:25:16 UTC (rev 218636)
+++ trunk/Source/WebCore/platform/network/curl/ResourceHandleManager.cpp	2017-06-21 16:48:43 UTC (rev 218637)
@@ -42,6 +42,7 @@
 
 #include "CredentialStorage.h"
 #include "CurlCacheManager.h"
+#include "CurlManager.h"
 #include "HTTPHeaderNames.h"
 #include "HTTPParsers.h"
 #include "MIMETypeRegistry.h"
@@ -87,15 +88,6 @@
 const int maxRunningJobs = 128;
 const char* const errorDomainCurl = "CurlErrorDomain";
 
-URL getCurlEffectiveURL(CURL* handle)
-{
-    const char* url;
-    CURLcode err = curl_easy_getinfo(handle, CURLINFO_EFFECTIVE_URL, &url);
-    if (CURLE_OK != err)
-        return URL();
-    return URL(URL(), url);
-}
-
 static const bool ignoreSSLErrors = getenv("WEBKIT_IGNORE_SSL_ERRORS");
 
 static CString certificatePath()
@@ -151,25 +143,6 @@
 #endif
 }
 
-static Lock* sharedResourceMutex(curl_lock_data data)
-{
-    DEPRECATED_DEFINE_STATIC_LOCAL(Lock, cookieMutex, ());
-    DEPRECATED_DEFINE_STATIC_LOCAL(Lock, dnsMutex, ());
-    DEPRECATED_DEFINE_STATIC_LOCAL(Lock, shareMutex, ());
-
-    switch (data) {
-        case CURL_LOCK_DATA_COOKIE:
-            return &cookieMutex;
-        case CURL_LOCK_DATA_DNS:
-            return &dnsMutex;
-        case CURL_LOCK_DATA_SHARE:
-            return &shareMutex;
-        default:
-            ASSERT_NOT_REACHED();
-            return NULL;
-    }
-}
-
 #if ENABLE(WEB_TIMING)
 static void calculateWebTimingInformations(ResourceHandleInternal* d)
 {
@@ -197,21 +170,6 @@
 }
 #endif
 
-// libcurl does not implement its own thread synchronization primitives.
-// these two functions provide mutexes for cookies, and for the global DNS
-// cache.
-static void curl_lock_callback(CURL* /* handle */, curl_lock_data data, curl_lock_access /* access */, void* /* userPtr */)
-{
-    if (Lock* mutex = sharedResourceMutex(data))
-        mutex->lock();
-}
-
-static void curl_unlock_callback(CURL* /* handle */, curl_lock_data data, void* /* userPtr */)
-{
-    if (Lock* mutex = sharedResourceMutex(data))
-        mutex->unlock();
-}
-
 inline static bool isHttpInfo(int statusCode)
 {
     return 100 <= statusCode && statusCode < 200;
@@ -235,20 +193,17 @@
 ResourceHandleManager::ResourceHandleManager()
     : m_downloadTimer(*this, &ResourceHandleManager::downloadTimerCallback)
     , m_cookieJarFileName(cookieJarPath())
-    , m_certificatePath (certificatePath())
+    , m_certificatePath(certificatePath())
     , m_runningJobs(0)
 #ifndef NDEBUG
     , m_logFile(nullptr)
 #endif
 {
-    curl_global_init(CURL_GLOBAL_ALL);
+    CURLSH* h = CurlManager::singleton().getCurlShareHandle();
+    m_curlShareHandle = h;
     m_curlMultiHandle = curl_multi_init();
-    m_curlShareHandle = curl_share_init();
-    curl_share_setopt(m_curlShareHandle, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
-    curl_share_setopt(m_curlShareHandle, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
-    curl_share_setopt(m_curlShareHandle, CURLSHOPT_LOCKFUNC, curl_lock_callback);
-    curl_share_setopt(m_curlShareHandle, CURLSHOPT_UNLOCKFUNC, curl_unlock_callback);
 
+
     initCookieSession();
 
 #ifndef NDEBUG
@@ -261,10 +216,8 @@
 ResourceHandleManager::~ResourceHandleManager()
 {
     curl_multi_cleanup(m_curlMultiHandle);
-    curl_share_cleanup(m_curlShareHandle);
     if (m_cookieJarFileName)
         fastFree(m_cookieJarFileName);
-    curl_global_cleanup();
 
 #ifndef NDEBUG
     if (m_logFile)
@@ -272,11 +225,6 @@
 #endif
 }
 
-CURLSH* ResourceHandleManager::getCurlShareHandle() const
-{
-    return m_curlShareHandle;
-}
-
 void ResourceHandleManager::setCookieJarFileName(const char* cookieJarFileName)
 {
     m_cookieJarFileName = fastStrDup(cookieJarFileName);
@@ -302,7 +250,7 @@
     // which means the ResourceLoader's response does not contain the URL.
     // Run the code here for local files to resolve the issue.
     // TODO: See if there is a better approach for handling this.
-    URL url = ""
+    URL url = ""
     ASSERT(url.isValid());
     d->m_response.setURL(url);
      if (d->client())
@@ -413,7 +361,7 @@
     if (err != CURLE_OK)
         return false;
 
-    URL url = ""
+    URL url = ""
     if (!url.isValid())
         return false;
 
@@ -502,7 +450,7 @@
         curl_easy_getinfo(h, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &contentLength);
         d->m_response.setExpectedContentLength(static_cast<long long int>(contentLength));
 
-        d->m_response.setURL(getCurlEffectiveURL(h));
+        d->m_response.setURL(CurlUtils::getEffectiveURL(h));
 
         d->m_response.setHTTPStatusCode(httpCode);
         d->m_response.setMimeType(extractMIMETypeFromMediaType(d->m_response.httpHeaderField(HTTPHeaderName::ContentType)).convertToASCIILowercase());
@@ -709,7 +657,7 @@
                 CurlCacheManager::getInstance().didFinishLoading(*job);
             }
         } else {
-            URL url = ""
+            URL url = ""
 #ifndef NDEBUG
             fprintf(stderr, "Curl ERROR for url='', error: '%s'\n", url.string().utf8().data(), curl_easy_strerror(msg->data.result));
 #endif

Modified: trunk/Source/WebCore/platform/network/curl/ResourceHandleManager.h (218636 => 218637)


--- trunk/Source/WebCore/platform/network/curl/ResourceHandleManager.h	2017-06-21 16:25:16 UTC (rev 218636)
+++ trunk/Source/WebCore/platform/network/curl/ResourceHandleManager.h	2017-06-21 16:48:43 UTC (rev 218637)
@@ -57,8 +57,6 @@
     void add(ResourceHandle*);
     void cancel(ResourceHandle*);
 
-    CURLSH* getCurlShareHandle() const;
-
     void setCookieJarFileName(const char* cookieJarFileName);
     const char* getCookieJarFileName() const;
 
@@ -100,8 +98,6 @@
 #endif
 };
 
-URL getCurlEffectiveURL(CURL*);
-
 }
 
 #endif
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to