[Curl] Reimplement CurlDownload with CurlRequest
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 4 Oct 2017 03:15:28 +0000 (03:15 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 4 Oct 2017 03:15:28 +0000 (03:15 +0000)
https://bugs.webkit.org/show_bug.cgi?id=177779

Patch by Basuke Suzuki <Basuke.Suzuki@sony.com> on 2017-10-03
Reviewed by Alex Christensen.

Source/WebCore:

* platform/network/curl/CurlContext.cpp:
(WebCore::CurlHandle::enableAllowedProtocols):
(WebCore::CurlHandle::enableFollowLocation): Deleted.
(WebCore::CurlHandle::getEffectiveURL): Deleted.
* platform/network/curl/CurlContext.h:
* platform/network/curl/CurlDownload.cpp:
(WebCore::CurlDownload::~CurlDownload):
(WebCore::CurlDownload::init):
(WebCore::CurlDownload::start):
(WebCore::CurlDownload::cancel):
(WebCore::CurlDownload::createCurlRequest):
(WebCore::CurlDownload::curlDidReceiveResponse):
(WebCore::CurlDownload::curlDidReceiveBuffer):
(WebCore::CurlDownload::curlDidComplete):
(WebCore::CurlDownload::curlDidFailWithError):
(WebCore::CurlDownload::shouldRedirectAsGET):
(WebCore::CurlDownload::willSendRequest):
(WebCore::CurlDownload::getResponse const): Deleted.
(WebCore::CurlDownload::retain): Deleted.
(WebCore::CurlDownload::release): Deleted.
(WebCore::CurlDownload::setupTransfer): Deleted.
(WebCore::CurlDownload::didCompleteTransfer): Deleted.
(WebCore::CurlDownload::didCancelTransfer): Deleted.
(WebCore::CurlDownload::closeFile): Deleted.
(WebCore::CurlDownload::moveFileToDestination): Deleted.
(WebCore::CurlDownload::writeDataToFile): Deleted.
(WebCore::CurlDownload::didReceiveHeader): Deleted.
(WebCore::CurlDownload::didReceiveData): Deleted.
(WebCore::CurlDownload::didReceiveResponse): Deleted.
(WebCore::CurlDownload::didReceiveDataOfLength): Deleted.
(WebCore::CurlDownload::didFinish): Deleted.
(WebCore::CurlDownload::didFail): Deleted.
(WebCore::CurlDownload::writeCallback): Deleted.
(WebCore::CurlDownload::headerCallback): Deleted.
* platform/network/curl/CurlDownload.h:
(WebCore::CurlDownloadListener::didReceiveResponse):
* platform/network/curl/CurlRequest.cpp:
(WebCore::CurlRequest::didReceiveData):
(WebCore::CurlRequest::finalizeTransfer):
(WebCore::CurlRequest::enableDownloadToFile):
(WebCore::CurlRequest::getDownloadedFilePath):
(WebCore::CurlRequest::writeDataToDownloadFileIfEnabled):
(WebCore::CurlRequest::closeDownloadFile):
* platform/network/curl/CurlRequest.h:
(WebCore::CurlRequest::create):
* platform/network/curl/ResourceHandleCurlDelegate.cpp:
(WebCore::ResourceHandleCurlDelegate::createCurlRequest):
* platform/network/curl/ResourceHandleCurlDelegate.h:

Source/WebKitLegacy/win:

* WebDownload.h:
* WebDownloadCurl.cpp:
(WebDownload::init):
(WebDownload::didReceiveResponse):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@222828 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
Source/WebCore/ChangeLog
Source/WebCore/platform/network/curl/CurlContext.cpp
Source/WebCore/platform/network/curl/CurlContext.h
Source/WebCore/platform/network/curl/CurlDownload.cpp
Source/WebCore/platform/network/curl/CurlDownload.h
Source/WebCore/platform/network/curl/CurlRequest.cpp
Source/WebCore/platform/network/curl/CurlRequest.h
Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.cpp
Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.h
Source/WebKitLegacy/win/ChangeLog
Source/WebKitLegacy/win/WebDownload.h
Source/WebKitLegacy/win/WebDownloadCurl.cpp

index b2276f5..cdc6547 100644 (file)
@@ -1,3 +1,59 @@
+2017-10-03  Basuke Suzuki  <Basuke.Suzuki@sony.com>
+
+        [Curl] Reimplement CurlDownload with CurlRequest
+        https://bugs.webkit.org/show_bug.cgi?id=177779
+
+        Reviewed by Alex Christensen.
+
+        * platform/network/curl/CurlContext.cpp:
+        (WebCore::CurlHandle::enableAllowedProtocols):
+        (WebCore::CurlHandle::enableFollowLocation): Deleted.
+        (WebCore::CurlHandle::getEffectiveURL): Deleted.
+        * platform/network/curl/CurlContext.h:
+        * platform/network/curl/CurlDownload.cpp:
+        (WebCore::CurlDownload::~CurlDownload):
+        (WebCore::CurlDownload::init):
+        (WebCore::CurlDownload::start):
+        (WebCore::CurlDownload::cancel):
+        (WebCore::CurlDownload::createCurlRequest):
+        (WebCore::CurlDownload::curlDidReceiveResponse):
+        (WebCore::CurlDownload::curlDidReceiveBuffer):
+        (WebCore::CurlDownload::curlDidComplete):
+        (WebCore::CurlDownload::curlDidFailWithError):
+        (WebCore::CurlDownload::shouldRedirectAsGET):
+        (WebCore::CurlDownload::willSendRequest):
+        (WebCore::CurlDownload::getResponse const): Deleted.
+        (WebCore::CurlDownload::retain): Deleted.
+        (WebCore::CurlDownload::release): Deleted.
+        (WebCore::CurlDownload::setupTransfer): Deleted.
+        (WebCore::CurlDownload::didCompleteTransfer): Deleted.
+        (WebCore::CurlDownload::didCancelTransfer): Deleted.
+        (WebCore::CurlDownload::closeFile): Deleted.
+        (WebCore::CurlDownload::moveFileToDestination): Deleted.
+        (WebCore::CurlDownload::writeDataToFile): Deleted.
+        (WebCore::CurlDownload::didReceiveHeader): Deleted.
+        (WebCore::CurlDownload::didReceiveData): Deleted.
+        (WebCore::CurlDownload::didReceiveResponse): Deleted.
+        (WebCore::CurlDownload::didReceiveDataOfLength): Deleted.
+        (WebCore::CurlDownload::didFinish): Deleted.
+        (WebCore::CurlDownload::didFail): Deleted.
+        (WebCore::CurlDownload::writeCallback): Deleted.
+        (WebCore::CurlDownload::headerCallback): Deleted.
+        * platform/network/curl/CurlDownload.h:
+        (WebCore::CurlDownloadListener::didReceiveResponse):
+        * platform/network/curl/CurlRequest.cpp:
+        (WebCore::CurlRequest::didReceiveData):
+        (WebCore::CurlRequest::finalizeTransfer):
+        (WebCore::CurlRequest::enableDownloadToFile):
+        (WebCore::CurlRequest::getDownloadedFilePath):
+        (WebCore::CurlRequest::writeDataToDownloadFileIfEnabled):
+        (WebCore::CurlRequest::closeDownloadFile):
+        * platform/network/curl/CurlRequest.h:
+        (WebCore::CurlRequest::create):
+        * platform/network/curl/ResourceHandleCurlDelegate.cpp:
+        (WebCore::ResourceHandleCurlDelegate::createCurlRequest):
+        * platform/network/curl/ResourceHandleCurlDelegate.h:
+
 2017-10-03  Zalan Bujtas <zalan@apple.com>
 
         Move scroll snap point unregistration from willBeRemovedFromTree to willBeDestroyed
index bfae5a8..358bae7 100644 (file)
@@ -414,15 +414,6 @@ void CurlHandle::enableAllowedProtocols()
     static const long allowedProtocols = CURLPROTO_FILE | CURLPROTO_FTP | CURLPROTO_FTPS | CURLPROTO_HTTP | CURLPROTO_HTTPS;
 
     curl_easy_setopt(m_handle, CURLOPT_PROTOCOLS, allowedProtocols);
-    curl_easy_setopt(m_handle, CURLOPT_REDIR_PROTOCOLS, allowedProtocols);
-}
-
-void CurlHandle::enableFollowLocation()
-{
-    static const long maxNumberOfRedirectCount = 10;
-
-    curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, 1L);
-    curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS, maxNumberOfRedirectCount);
 }
 
 void CurlHandle::enableHttpAuthentication(long option)
@@ -532,19 +523,6 @@ void CurlHandle::setSslCtxCallbackFunction(curl_ssl_ctx_callback callbackFunc, v
     curl_easy_setopt(m_handle, CURLOPT_SSL_CTX_FUNCTION, callbackFunc);
 }
 
-URL CurlHandle::getEffectiveURL()
-{
-    if (!m_handle)
-        return URL();
-
-    char* url;
-    CURLcode errorCode = curl_easy_getinfo(m_handle, CURLINFO_EFFECTIVE_URL, &url);
-    if (errorCode != CURLE_OK)
-        return URL();
-
-    return URL(URL(), url);
-}
-
 std::optional<uint16_t> CurlHandle::getPrimaryPort()
 {
     if (!m_handle)
index 153f2f3..9bcd3b7 100644 (file)
@@ -247,8 +247,6 @@ public:
     void enableAcceptEncoding();
     void enableAllowedProtocols();
 
-    void enableFollowLocation();
-
     void enableHttpAuthentication(long);
     void setHttpAuthUserPass(const String&, const String&);
 
@@ -274,7 +272,6 @@ public:
     void setSslCtxCallbackFunction(curl_ssl_ctx_callback, void*);
 
     // Status
-    URL getEffectiveURL();
     std::optional<uint16_t> getPrimaryPort();
     std::optional<long> getResponseCode();
     std::optional<long> getHttpConnectCode();
index 6c4e9a5..4a895a1 100644 (file)
 
 #if USE(CURL)
 
-#include "CurlContext.h"
-#include "CurlSSLHandle.h"
-#include "HTTPHeaderNames.h"
 #include "HTTPParsers.h"
 #include "ResourceRequest.h"
-#include <wtf/MainThread.h>
-#include <wtf/text/CString.h>
-
-using namespace WebCore;
+#include "ResourceResponse.h"
+#include "SharedBuffer.h"
 
 namespace WebCore {
 
-// CurlDownload --------------------------------------------------------------------------
-
-CurlDownload::CurlDownload() = default;
-
 CurlDownload::~CurlDownload()
 {
-    closeFile();
-    moveFileToDestination();
+    if (m_curlRequest)
+        m_curlRequest->setDelegate(nullptr);
 }
 
-void CurlDownload::init(CurlDownloadListener* listener, const URL& url)
+void CurlDownload::init(CurlDownloadListener& listener, const URL& url)
 {
-    if (!listener)
-        return;
-
-    m_listener = listener;
+    m_listener = &listener;
     m_request.setURL(url);
 }
 
-void CurlDownload::init(CurlDownloadListener* listener, ResourceHandle*, const ResourceRequest& request, const ResourceResponse&)
+void CurlDownload::init(CurlDownloadListener& listener, ResourceHandle*, const ResourceRequest& request, const ResourceResponse&)
 {
-    if (!listener)
-        return;
-
-    m_listener = listener;
+    m_listener = &listener;
     m_request = request.isolatedCopy();
 }
 
 bool CurlDownload::start()
 {
-    CurlJobManager::singleton().add(this);
+    ASSERT(isMainThread());
+
+    m_curlRequest = createCurlRequest(m_request);
+    m_curlRequest->enableDownloadToFile();
+    m_curlRequest->start();
+
     return true;
 }
 
 bool CurlDownload::cancel()
 {
-    CurlJobManager::singleton().cancel(this);
-    return true;
-}
+    m_isCancelled = true;
 
-ResourceResponse CurlDownload::getResponse() const
-{
-    return m_response;
-}
+    if (!m_curlRequest)
+        m_curlRequest->cancel();
 
-void CurlDownload::retain()
-{
-    ref();
-}
-
-void CurlDownload::release()
-{
-    deref();
+    return true;
 }
 
-CURL* CurlDownload::setupTransfer()
+Ref<CurlRequest> CurlDownload::createCurlRequest(ResourceRequest& request)
 {
-    m_curlHandle = std::make_unique<CurlHandle>();
-    m_curlHandle->initialize();
-    m_curlHandle->enableShareHandle();
-
-    m_curlHandle->setUrl(m_request.url());
-    m_curlHandle->appendRequestHeaders(m_request.httpHeaderFields());
-    m_curlHandle->setHeaderCallbackFunction(headerCallback, this);
-    m_curlHandle->setWriteCallbackFunction(writeCallback, this);
-    m_curlHandle->enableFollowLocation();
-    m_curlHandle->enableHttpAuthentication(CURLAUTH_ANY);
-    m_curlHandle->setCACertPath(CurlContext::singleton().sslHandle().getCACertPath());
-
-    return m_curlHandle->handle();
+    return CurlRequest::create(request, this);
 }
 
-void CurlDownload::didCompleteTransfer(CURLcode result)
+void CurlDownload::curlDidReceiveResponse(const CurlResponse& response)
 {
-    callOnMainThread([protectedThis = makeRef(*this), result] {
-        if (result == CURLE_OK)
-            protectedThis->didFinish();
-        else
-            protectedThis->didFail();
-    });
-
-    m_curlHandle = nullptr;
-}
+    ASSERT(isMainThread());
 
-void CurlDownload::didCancelTransfer()
-{
-    m_curlHandle = nullptr;
-}
+    if (m_isCancelled)
+        return;
 
-void CurlDownload::closeFile()
-{
-    LockHolder locker(m_mutex);
+    m_response = ResourceResponse(response);
 
-    if (m_tempHandle != invalidPlatformFileHandle) {
-        WebCore::closeFile(m_tempHandle);
-        m_tempHandle = invalidPlatformFileHandle;
+    if (m_response.shouldRedirect()) {
+        willSendRequest();
+        return;
     }
+
+    if (m_listener)
+        m_listener->didReceiveResponse(m_response);
+
+    m_curlRequest->completeDidReceiveResponse();
 }
 
-void CurlDownload::moveFileToDestination()
+
+void CurlDownload::curlDidReceiveBuffer(Ref<SharedBuffer>&& buffer)
 {
-    LockHolder locker(m_mutex);
+    ASSERT(isMainThread());
 
-    if (m_destination.isEmpty())
+    if (m_isCancelled)
         return;
 
-    moveFile(m_tempPath, m_destination);
+    if (m_listener)
+        m_listener->didReceiveDataOfLength(buffer->size());
 }
 
-void CurlDownload::writeDataToFile(const char* data, int size)
+void CurlDownload::curlDidComplete()
 {
-    if (m_tempPath.isEmpty())
-        m_tempPath = openTemporaryFile("download", m_tempHandle);
+    ASSERT(isMainThread());
 
-    if (m_tempHandle != invalidPlatformFileHandle)
-        writeToFile(m_tempHandle, data, size);
-}
+    if (m_isCancelled)
+        return;
 
-void CurlDownload::didReceiveHeader(const String& header)
-{
-    LockHolder locker(m_mutex);
-
-    if (header == "\r\n" || header == "\n") {
-        auto httpCode = m_curlHandle->getResponseCode();
-
-        if (httpCode && *httpCode >= 200 && *httpCode < 300) {
-            auto url = m_curlHandle->getEffectiveURL();
-
-            callOnMainThread([protectedThis = makeRef(*this), url = url.isolatedCopy()] {
-                protectedThis->m_response.setURL(url);
-                protectedThis->m_response.setMimeType(extractMIMETypeFromMediaType(protectedThis->m_response.httpHeaderField(HTTPHeaderName::ContentType)));
-                protectedThis->m_response.setTextEncodingName(extractCharsetFromMediaType(protectedThis->m_response.httpHeaderField(HTTPHeaderName::ContentType)));
-
-                protectedThis->didReceiveResponse();
-            });
-        }
-    } else {
-        callOnMainThread([protectedThis = makeRef(*this), header = header.isolatedCopy()] {
-            int splitPos = header.find(":");
-            if (splitPos != -1)
-                protectedThis->m_response.setHTTPHeaderField(header.left(splitPos), header.substring(splitPos + 1).stripWhiteSpace());
-        });
+    if (!m_destination.isEmpty()) {
+        if (m_curlRequest && !m_curlRequest->getDownloadedFilePath().isEmpty())
+            moveFile(m_curlRequest->getDownloadedFilePath(), m_destination);
     }
+
+    if (m_listener)
+        m_listener->didFinish();
 }
 
-void CurlDownload::didReceiveData(void* data, int size)
+void CurlDownload::curlDidFailWithError(const ResourceError& resourceError)
 {
-    LockHolder locker(m_mutex);
+    ASSERT(isMainThread());
 
-    callOnMainThread([protectedThis = makeRef(*this), size] {
-        protectedThis->didReceiveDataOfLength(size);
-    });
+    if (m_isCancelled)
+        return;
 
-    writeDataToFile(static_cast<const char*>(data), size);
-}
+    if (m_deletesFileUponFailure && m_curlRequest && !m_curlRequest->getDownloadedFilePath().isEmpty())
+        deleteFile(m_curlRequest->getDownloadedFilePath());
 
-void CurlDownload::didReceiveResponse()
-{
     if (m_listener)
-        m_listener->didReceiveResponse();
+        m_listener->didFail();
 }
 
-void CurlDownload::didReceiveDataOfLength(int size)
+bool CurlDownload::shouldRedirectAsGET(const ResourceRequest& request, bool crossOrigin)
 {
-    if (m_listener)
-        m_listener->didReceiveDataOfLength(size);
-}
+    if ((request.httpMethod() == "GET") || (request.httpMethod() == "HEAD"))
+        return false;
 
-void CurlDownload::didFinish()
-{
-    closeFile();
-    moveFileToDestination();
+    if (!request.url().protocolIsInHTTPFamily())
+        return true;
 
-    if (m_listener)
-        m_listener->didFinish();
-}
+    if (m_response.isSeeOther())
+        return true;
 
-void CurlDownload::didFail()
-{
-    closeFile();
-    {
-        LockHolder locker(m_mutex);
+    if ((m_response.isMovedPermanently() || m_response.isFound()) && (request.httpMethod() == "POST"))
+        return true;
 
-        if (m_deletesFileUponFailure)
-            deleteFile(m_tempPath);
-    }
+    if (crossOrigin && (request.httpMethod() == "DELETE"))
+        return true;
 
-    if (m_listener)
-        m_listener->didFail();
+    return false;
 }
 
-size_t CurlDownload::writeCallback(char* ptr, size_t size, size_t nmemb, void* data)
+void CurlDownload::willSendRequest()
 {
-    size_t totalSize = size * nmemb;
-    CurlDownload* download = reinterpret_cast<CurlDownload*>(data);
+    ASSERT(isMainThread());
 
-    if (download)
-        download->didReceiveData(static_cast<void*>(ptr), totalSize);
+    static const int maxRedirects = 20;
 
-    return totalSize;
-}
+    if (m_redirectCount++ > maxRedirects) {
+        if (m_listener)
+            m_listener->didFail();
+        return;
+    }
 
-size_t CurlDownload::headerCallback(char* ptr, size_t size, size_t nmemb, void* data)
-{
-    size_t totalSize = size * nmemb;
-    CurlDownload* download = reinterpret_cast<CurlDownload*>(data);
+    String location = m_response.httpHeaderField(HTTPHeaderName::Location);
+    URL newURL = URL(m_request.url(), location);
+    bool crossOrigin = !protocolHostAndPortAreEqual(m_request.url(), newURL);
+
+    ResourceRequest newRequest = m_request;
+    newRequest.setURL(newURL);
 
-    String header(static_cast<const char*>(ptr), totalSize);
+    if (shouldRedirectAsGET(newRequest, crossOrigin)) {
+        newRequest.setHTTPMethod("GET");
+        newRequest.setHTTPBody(nullptr);
+        newRequest.clearHTTPContentType();
+    }
+
+    if (crossOrigin) {
+        // If the network layer carries over authentication headers from the original request
+        // in a cross-origin redirect, we want to clear those headers here. 
+        newRequest.clearHTTPAuthorization();
+        newRequest.clearHTTPOrigin();
+    }
 
-    if (download)
-        download->didReceiveHeader(header);
+    m_curlRequest->cancel();
+    m_curlRequest->setDelegate(nullptr);
 
-    return totalSize;
+    m_curlRequest = createCurlRequest(newRequest);
+    m_curlRequest->start();
 }
 
 }
index e70a248..5bb7a1d 100644 (file)
 
 #pragma once
 
-#include "CurlJobManager.h"
-#include "FileSystem.h"
-#include "ResourceHandle.h"
+#if USE(CURL)
+
+#include "CurlRequest.h"
+#include "CurlRequestDelegate.h"
 #include "ResourceRequest.h"
 #include "ResourceResponse.h"
-#include <wtf/Lock.h>
-#include <wtf/Threading.h>
 
 namespace WebCore {
 
+class CurlRequest;
+class ResourceHandle;
+
 class CurlDownloadListener {
 public:
-    virtual void didReceiveResponse() { }
+    virtual void didReceiveResponse(const ResourceResponse&) { }
     virtual void didReceiveDataOfLength(int) { }
     virtual void didFinish() { }
     virtual void didFail() { }
 };
 
-class CurlDownload : public ThreadSafeRefCounted<CurlDownload>, public CurlJobClient {
+class CurlDownload : public ThreadSafeRefCounted<CurlDownload>, public CurlRequestDelegate {
 public:
-    CurlDownload();
+    CurlDownload() = default;
     ~CurlDownload();
 
-    void init(CurlDownloadListener*, const URL&);
-    void init(CurlDownloadListener*, ResourceHandle*, const ResourceRequest&, const ResourceResponse&);
+    void init(CurlDownloadListener&, const URL&);
+    void init(CurlDownloadListener&, ResourceHandle*, const ResourceRequest&, const ResourceResponse&);
 
     void setListener(CurlDownloadListener* listener) { m_listener = listener; }
 
     bool start();
     bool cancel();
 
-    ResourceResponse getResponse() const;
-
     bool deletesFileUponFailure() const { return m_deletesFileUponFailure; }
     void setDeletesFileUponFailure(bool deletesFileUponFailure) { m_deletesFileUponFailure = deletesFileUponFailure; }
 
     void setDestination(const String& destination) { m_destination = destination; }
 
 private:
-    void retain() override;
-    void release() override;
-
-    CURL* handle() override { return m_curlHandle ? m_curlHandle->handle() : nullptr; }
-    CURL* setupTransfer() override;
-    void didCompleteTransfer(CURLcode) override;
-    void didCancelTransfer() override;
-
-    void closeFile();
-    void moveFileToDestination();
-    void writeDataToFile(const char* data, int size);
-
-    // Called on download thread.
-    void didReceiveHeader(const String& header);
-    void didReceiveData(void* data, int size);
+    Ref<CurlRequest> createCurlRequest(ResourceRequest&);
+    void curlDidReceiveResponse(const CurlResponse&) override;
+    void curlDidReceiveBuffer(Ref<SharedBuffer>&&) override;
+    void curlDidComplete() override;
+    void curlDidFailWithError(const ResourceError&) override;
 
-    // Called on main thread.
-    void didReceiveResponse();
-    void didReceiveDataOfLength(int size);
-    void didFinish();
-    void didFail();
+    bool shouldRedirectAsGET(const ResourceRequest&, bool crossOrigin);
+    void willSendRequest();
 
-    static size_t writeCallback(char* ptr, size_t, size_t nmemb, void* data);
-    static size_t headerCallback(char* ptr, size_t, size_t nmemb, void* data);
+    CurlDownloadListener* m_listener { nullptr };
+    bool m_isCancelled { false };
 
-    std::unique_ptr<CurlHandle> m_curlHandle;
     ResourceRequest m_request;
     ResourceResponse m_response;
-
-    String m_tempPath;
-    String m_destination;
-    PlatformFileHandle m_tempHandle { invalidPlatformFileHandle };
     bool m_deletesFileUponFailure { false };
-    mutable Lock m_mutex;
-    CurlDownloadListener* m_listener { nullptr };
+    String m_destination;
+    unsigned m_redirectCount { 0 };
+    RefPtr<CurlRequest> m_curlRequest;
 };
 
-}
+} // namespace WebCore
+
+#endif
index adea73c..8d366c5 100644 (file)
@@ -326,6 +326,8 @@ size_t CurlRequest::didReceiveData(Ref<SharedBuffer>&& buffer)
 
     auto receiveBytes = buffer->size();
 
+    writeDataToDownloadFileIfEnabled(buffer);
+
     if (receiveBytes) {
         callDelegate([this, buffer = WTFMove(buffer)](CurlRequestDelegate* delegate) mutable {
             if (delegate)
@@ -381,6 +383,7 @@ void CurlRequest::didCancelTransfer()
 void CurlRequest::finalizeTransfer()
 {
     m_formDataStream = nullptr;
+    closeDownloadFile();
     m_curlHandle = nullptr;
 }
 
@@ -590,6 +593,43 @@ void CurlRequest::pausedStatusChanged()
     }
 }
 
+void CurlRequest::enableDownloadToFile()
+{
+    LockHolder locker(m_downloadMutex);
+    m_isEnabledDownloadToFile = true;
+}
+
+const String& CurlRequest::getDownloadedFilePath()
+{
+    LockHolder locker(m_downloadMutex);
+    return m_downloadFilePath;
+}
+
+void CurlRequest::writeDataToDownloadFileIfEnabled(const SharedBuffer& buffer)
+{
+    LockHolder locker(m_downloadMutex);
+
+    if (!m_isEnabledDownloadToFile)
+        return;
+
+    if (m_downloadFilePath.isEmpty())
+        m_downloadFilePath = openTemporaryFile("download", m_downloadFileHandle);
+
+    if (m_downloadFileHandle != invalidPlatformFileHandle)
+        writeToFile(m_downloadFileHandle, buffer.data(), buffer.size());
+}
+
+void CurlRequest::closeDownloadFile()
+{
+    LockHolder locker(m_downloadMutex);
+
+    if (m_downloadFileHandle == invalidPlatformFileHandle)
+        return;
+
+    WebCore::closeFile(m_downloadFileHandle);
+    m_downloadFileHandle = invalidPlatformFileHandle;
+}
+
 CURLcode CurlRequest::willSetupSslCtxCallback(CURL*, void* sslCtx, void* userData)
 {
     return static_cast<CurlRequest*>(userData)->willSetupSslCtx(sslCtx);
index 61f2e23..212534a 100644 (file)
@@ -28,6 +28,7 @@
 #include "CurlJobManager.h"
 #include "CurlResponse.h"
 #include "CurlSSLVerifier.h"
+#include "FileSystem.h"
 #include "FormDataStreamCurl.h"
 #include "NetworkLoadMetrics.h"
 #include "ResourceRequest.h"
@@ -43,7 +44,11 @@ class CurlRequest : public ThreadSafeRefCounted<CurlRequest>, public CurlJobClie
     WTF_MAKE_NONCOPYABLE(CurlRequest);
 
 public:
-    CurlRequest(const ResourceRequest&, CurlRequestDelegate* = nullptr, bool shouldSuspend = false);
+    static Ref<CurlRequest> create(const ResourceRequest& request, CurlRequestDelegate* delegate, bool shouldSuspend = false)
+    {
+        return adoptRef(*new CurlRequest(request, delegate, shouldSuspend));
+    }
+
     virtual ~CurlRequest() { }
 
     void setDelegate(CurlRequestDelegate* delegate) { m_delegate = delegate;  }
@@ -59,6 +64,10 @@ public:
     // Processing for DidReceiveResponse
     void completeDidReceiveResponse();
 
+    // Download
+    void enableDownloadToFile();
+    const String& getDownloadedFilePath();
+
     NetworkLoadMetrics getNetworkLoadMetrics() { return m_networkLoadMetrics.isolatedCopy(); }
 
 private:
@@ -69,6 +78,8 @@ private:
         FinishTransfer
     };
 
+    CurlRequest(const ResourceRequest&, CurlRequestDelegate*, bool shouldSuspend);
+
     void retain() override { ref(); }
     void release() override { deref(); }
     CURL* handle() override { return m_curlHandle ? m_curlHandle->handle() : nullptr; }
@@ -103,6 +114,10 @@ private:
     void pausedStatusChanged();
     bool isPaused() const { return m_isPausedOfRequest || m_isPausedOfCallback; };
 
+    // Download
+    void writeDataToDownloadFileIfEnabled(const SharedBuffer&);
+    void closeDownloadFile();
+
     // Callback functions for curl
     static CURLcode willSetupSslCtxCallback(CURL*, void*, void*);
     static size_t willSendDataCallback(char*, size_t, size_t, void*);
@@ -134,6 +149,11 @@ private:
     bool m_isPausedOfRequest { false };
     bool m_isPausedOfCallback { false };
 
+    Lock m_downloadMutex;
+    bool m_isEnabledDownloadToFile { false };
+    String m_downloadFilePath;
+    PlatformFileHandle m_downloadFileHandle { invalidPlatformFileHandle };
+
     NetworkLoadMetrics m_networkLoadMetrics;
 };
 
index 0fab7ba..500ed5b 100644 (file)
@@ -147,7 +147,7 @@ void ResourceHandleCurlDelegate::dispatchSynchronousJob()
     m_curlRequest->start(true);
 }
 
-RefPtr<CurlRequest> ResourceHandleCurlDelegate::createCurlRequest(ResourceRequest& request)
+Ref<CurlRequest> ResourceHandleCurlDelegate::createCurlRequest(ResourceRequest& request)
 {
     ASSERT(isMainThread());
 
@@ -170,7 +170,7 @@ RefPtr<CurlRequest> ResourceHandleCurlDelegate::createCurlRequest(ResourceReques
         }
     }
 
-    return adoptRef(new CurlRequest(request, this, m_defersLoading));
+    return CurlRequest::create(request, this, m_defersLoading);
 }
 
 bool ResourceHandleCurlDelegate::cancelledOrClientless()
index 0e48107..3848cf0 100644 (file)
@@ -68,7 +68,7 @@ private:
 
     bool cancelledOrClientless();
 
-    RefPtr<CurlRequest> createCurlRequest(ResourceRequest&);
+    Ref<CurlRequest> createCurlRequest(ResourceRequest&);
     void curlDidReceiveResponse(const CurlResponse&) override;
     void curlDidReceiveBuffer(Ref<SharedBuffer>&&) override;
     void curlDidComplete() override;
@@ -86,7 +86,7 @@ private:
     ResourceHandle* m_handle;
     std::unique_ptr<MultipartHandle> m_multipartHandle;
     unsigned m_authFailureCount { 0 };
-    int m_redirectCount { 0 };
+    unsigned m_redirectCount { 0 };
 
     ResourceRequest m_firstRequest;
     ResourceRequest m_currentRequest;
index b5b67eb..b797c28 100644 (file)
@@ -1,3 +1,15 @@
+2017-10-03  Basuke Suzuki  <Basuke.Suzuki@sony.com>
+
+        [Curl] Reimplement CurlDownload with CurlRequest
+        https://bugs.webkit.org/show_bug.cgi?id=177779
+
+        Reviewed by Alex Christensen.
+
+        * WebDownload.h:
+        * WebDownloadCurl.cpp:
+        (WebDownload::init):
+        (WebDownload::didReceiveResponse):
+
 2017-09-29  Chris Dumez  <cdumez@apple.com>
 
         Split some logic out of VisitedLinkStore and make it reusable
index 2117e78..6ad7346 100644 (file)
@@ -97,7 +97,7 @@ public:
     void didFinish();
     void didFail(CFErrorRef);
 #elif USE(CURL)
-    virtual void didReceiveResponse();
+    virtual void didReceiveResponse(const WebCore::ResourceResponse&);
     virtual void didReceiveDataOfLength(int size);
     virtual void didFinish();
     virtual void didFail();
index d014280..160e9bb 100644 (file)
@@ -43,6 +43,8 @@
 #include <sys/types.h>
 
 #include <WebCore/BString.h>
+#include <WebCore/CurlDownload.h>
+#include <WebCore/FileSystem.h>
 #include <WebCore/NotImplemented.h>
 #include <WebCore/ResourceError.h>
 #include <WebCore/ResourceHandle.h>
@@ -64,7 +66,7 @@ void WebDownload::init(ResourceHandle* handle, const ResourceRequest& request, c
     m_delegate = delegate;
 
     m_download = adoptRef(new CurlDownload());
-    m_download->init(this, handle, request, response);
+    m_download->init(*this, handle, request, response);
 }
 
 void WebDownload::init(const URL& url, IWebDownloadDelegate* delegate)
@@ -72,7 +74,7 @@ void WebDownload::init(const URL& url, IWebDownloadDelegate* delegate)
     m_delegate = delegate;
 
     m_download = adoptRef(new CurlDownload());
-    m_download->init(this, url);
+    m_download->init(*this, url);
 }
 
 // IWebDownload -------------------------------------------------------------------
@@ -204,12 +206,11 @@ HRESULT WebDownload::useCredential(
    return E_FAIL;
 }
 
-void WebDownload::didReceiveResponse()
+void WebDownload::didReceiveResponse(const ResourceResponse& response)
 {
     COMPtr<WebDownload> protect = this;
 
     if (m_delegate) {
-        ResourceResponse response = m_download->getResponse();
         COMPtr<WebURLResponse> webResponse(AdoptCOM, WebURLResponse::createInstance(response));
         m_delegate->didReceiveResponse(this, webResponse.get());