Reviewed by Anders Carlsson.
authoradachan@apple.com <adachan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 10 Dec 2010 22:58:04 +0000 (22:58 +0000)
committeradachan@apple.com <adachan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 10 Dec 2010 22:58:04 +0000 (22:58 +0000)
        Implement Download::start() and Download::startWithHandle() on Windows.
        https://bugs.webkit.org/show_bug.cgi?id=50844

        * WebProcess/Downloads/Download.h:
        * WebProcess/Downloads/cf/DownloadCFNet.cpp:
        (WebKit::Download::start): Create a CFURLDownloadRef and schedule it.
        (WebKit::Download::startWithHandle): Create a CFURLDownloadRef with the loading connection
        retrieved from the ResourceHandle.
        (WebKit::Download::platformInvalidate):
        (WebKit::downloadFromClientInfo):
        (WebKit::didStartCallback):
        (WebKit::willSendRequestCallback):
        (WebKit::didReceiveAuthenticationChallengeCallback):
        (WebKit::didReceiveResponseCallback):
        (WebKit::willResumeWithResponseCallback):
        (WebKit::didReceiveDataCallback):
        (WebKit::shouldDecodeDataOfMIMETypeCallback):
        (WebKit::decideDestinationWithSuggestedObjectNameCallback):
        (WebKit::didCreateDestinationCallback):
        (WebKit::didFinishCallback):
        (WebKit::didFailCallback):

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

WebKit2/ChangeLog
WebKit2/WebProcess/Downloads/Download.h
WebKit2/WebProcess/Downloads/cf/DownloadCFNet.cpp

index 7bd38af..005f594 100644 (file)
@@ -1,3 +1,29 @@
+2010-12-10  Ada Chan  <adachan@apple.com>
+
+        Reviewed by Anders Carlsson.
+
+        Implement Download::start() and Download::startWithHandle() on Windows.
+        https://bugs.webkit.org/show_bug.cgi?id=50844
+
+        * WebProcess/Downloads/Download.h:
+        * WebProcess/Downloads/cf/DownloadCFNet.cpp:
+        (WebKit::Download::start): Create a CFURLDownloadRef and schedule it.
+        (WebKit::Download::startWithHandle): Create a CFURLDownloadRef with the loading connection
+        retrieved from the ResourceHandle.
+        (WebKit::Download::platformInvalidate):
+        (WebKit::downloadFromClientInfo):
+        (WebKit::didStartCallback):
+        (WebKit::willSendRequestCallback):
+        (WebKit::didReceiveAuthenticationChallengeCallback):
+        (WebKit::didReceiveResponseCallback):
+        (WebKit::willResumeWithResponseCallback):
+        (WebKit::didReceiveDataCallback):
+        (WebKit::shouldDecodeDataOfMIMETypeCallback):
+        (WebKit::decideDestinationWithSuggestedObjectNameCallback):
+        (WebKit::didCreateDestinationCallback):
+        (WebKit::didFinishCallback):
+        (WebKit::didFailCallback):
+
 2010-12-10  Enrica Casucci  <enrica@apple.com>
 
         Windows build fix. Unreviewed.
index 54f325a..2319ec7 100644 (file)
@@ -42,6 +42,10 @@ class WKDownloadAsDelegate;
 #endif
 #endif
 
+#if USE(CFNETWORK)
+#include <CFNetwork/CFURLDownloadPriv.h>
+#endif
+
 namespace CoreIPC {
     class DataReference;
 }
@@ -98,6 +102,9 @@ private:
     RetainPtr<NSURLDownload> m_nsURLDownload;
     RetainPtr<WKDownloadAsDelegate> m_delegate;
 #endif
+#if USE(CFNETWORK)
+    RetainPtr<CFURLDownloadRef> m_download;
+#endif
 };
 
 } // namespace WebKit
index 34fd60e..08c381f 100644 (file)
 
 #include "Download.h"
 
+#include "DataReference.h"
 #include "NotImplemented.h"
 
+#pragma warning(push, 0)
+#include <WebCore/LoaderRunLoopCF.h>
+#include <WebCore/ResourceError.h>
+#include <WebCore/ResourceHandle.h>
+#include <WebCore/ResourceResponse.h>
+#pragma warning(pop)
+
 using namespace WebCore;
 
 namespace WebKit {
 
+// CFURLDownload Callbacks ----------------------------------------------------------------
+static void didStartCallback(CFURLDownloadRef download, const void* clientInfo);
+static CFURLRequestRef willSendRequestCallback(CFURLDownloadRef download, CFURLRequestRef request, CFURLResponseRef redirectionResponse, const void* clientInfo);
+static void didReceiveAuthenticationChallengeCallback(CFURLDownloadRef download, CFURLAuthChallengeRef challenge, const void* clientInfo);
+static void didReceiveResponseCallback(CFURLDownloadRef download, CFURLResponseRef response, const void* clientInfo);
+static void willResumeWithResponseCallback(CFURLDownloadRef download, CFURLResponseRef response, UInt64 startingByte, const void* clientInfo);
+static void didReceiveDataCallback(CFURLDownloadRef download, CFIndex length, const void* clientInfo);
+static Boolean shouldDecodeDataOfMIMETypeCallback(CFURLDownloadRef download, CFStringRef encodingType, const void* clientInfo);
+static void decideDestinationWithSuggestedObjectNameCallback(CFURLDownloadRef download, CFStringRef objectName, const void* clientInfo);
+static void didCreateDestinationCallback(CFURLDownloadRef download, CFURLRef path, const void* clientInfo);
+static void didFinishCallback(CFURLDownloadRef download, const void* clientInfo);
+static void didFailCallback(CFURLDownloadRef download, CFErrorRef error, const void* clientInfo);
+
 void Download::start(WebPage* initiatingWebPage)
 {
-    notImplemented();
+    ASSERT(!m_download);
+
+    CFURLRequestRef cfRequest = m_request.cfURLRequest();
+
+    CFURLDownloadClient client = {0, this, 0, 0, 0, didStartCallback, willSendRequestCallback, didReceiveAuthenticationChallengeCallback, 
+                                  didReceiveResponseCallback, willResumeWithResponseCallback, didReceiveDataCallback, shouldDecodeDataOfMIMETypeCallback, 
+                                  decideDestinationWithSuggestedObjectNameCallback, didCreateDestinationCallback, didFinishCallback, didFailCallback};
+    m_download.adoptCF(CFURLDownloadCreate(0, cfRequest, &client));
+
+    // FIXME: Allow this to be changed by the client.
+    CFURLDownloadSetDeletesUponFailure(m_download.get(), false);
+
+    CFURLDownloadScheduleWithCurrentMessageQueue(m_download.get());
+    CFURLDownloadScheduleDownloadWithRunLoop(m_download.get(), loaderRunLoop(), kCFRunLoopDefaultMode);
 }
 
-void Download::startWithHandle(WebPage* initiatingPage, ResourceHandle*, const ResourceRequest& initialRequest, const ResourceResponse&)
+void Download::startWithHandle(WebPage* initiatingPage, ResourceHandle* handle, const ResourceRequest& initialRequest, const ResourceResponse& response)
 {
-    notImplemented();
+    ASSERT(!m_download);
+
+    CFURLConnectionRef connection = handle->connection();
+    if (!connection)
+        return;
+
+    CFURLDownloadClient client = {0, this, 0, 0, 0, didStartCallback, willSendRequestCallback, didReceiveAuthenticationChallengeCallback, 
+                                  didReceiveResponseCallback, willResumeWithResponseCallback, didReceiveDataCallback, shouldDecodeDataOfMIMETypeCallback,
+                                  decideDestinationWithSuggestedObjectNameCallback, didCreateDestinationCallback, didFinishCallback, didFailCallback};
+
+    m_download.adoptCF(CFURLDownloadCreateAndStartWithLoadingConnection(0, connection, initialRequest.cfURLRequest(), response.cfURLResponse(), &client));
+
+    // It is possible for CFURLDownloadCreateAndStartWithLoadingConnection() to fail if the passed in CFURLConnection is not in a "downloadable state"
+    // However, we should never hit that case
+    if (!m_download)
+        ASSERT_NOT_REACHED();
+
+    // The CFURLDownload either starts successfully and retains the CFURLConnection, 
+    // or it fails to creating and we have a now-useless connection with a dangling ref. 
+    // Either way, we need to release the connection to balance out ref counts
+    handle->releaseConnectionForDownload();
+    CFRelease(connection);
 }
 
 void Download::cancel()
@@ -48,7 +103,83 @@ void Download::cancel()
 
 void Download::platformInvalidate()
 {
+    m_download = nullptr;
+}
+
+// CFURLDownload Callbacks ----------------------------------------------------------------
+static Download* downloadFromClientInfo(const void* clientInfo)
+{
+    return reinterpret_cast<Download*>(const_cast<void*>(clientInfo));
+}
+
+void didStartCallback(CFURLDownloadRef, const void* clientInfo)
+{ 
+    downloadFromClientInfo(clientInfo)->didStart(); 
+}
+
+CFURLRequestRef willSendRequestCallback(CFURLDownloadRef, CFURLRequestRef request, CFURLResponseRef redirectionResponse, const void* clientInfo)
+{ 
+    // CFNetwork requires us to return a retained request.
+    CFRetain(request);
+    return request;
+}
+
+void didReceiveAuthenticationChallengeCallback(CFURLDownloadRef, CFURLAuthChallengeRef challenge, const void* clientInfo)
+{ 
+    // FIXME: implement.
+    notImplemented();
+}
+
+void didReceiveResponseCallback(CFURLDownloadRef, CFURLResponseRef response, const void* clientInfo)
+{
+    downloadFromClientInfo(clientInfo)->didReceiveResponse(ResourceResponse(response)); 
+}
+
+void willResumeWithResponseCallback(CFURLDownloadRef, CFURLResponseRef response, UInt64 startingByte, const void* clientInfo)
+{ 
+    // FIXME: implement.
     notImplemented();
 }
 
+void didReceiveDataCallback(CFURLDownloadRef, CFIndex length, const void* clientInfo)
+{ 
+    downloadFromClientInfo(clientInfo)->didReceiveData(length);
+}
+
+Boolean shouldDecodeDataOfMIMETypeCallback(CFURLDownloadRef, CFStringRef encodingType, const void* clientInfo)
+{ 
+    return downloadFromClientInfo(clientInfo)->shouldDecodeSourceDataOfMIMEType(encodingType);
+}
+
+void decideDestinationWithSuggestedObjectNameCallback(CFURLDownloadRef cfURLDownloadRef, CFStringRef objectName, const void* clientInfo)
+{ 
+    Download* download = downloadFromClientInfo(clientInfo);
+    bool allowOverwrite;
+    String destination = download->decideDestinationWithSuggestedFilename(objectName, allowOverwrite);
+    if (destination.isNull())
+        return;
+
+    RetainPtr<CFStringRef> cfPath(AdoptCF, CFStringCreateWithCharactersNoCopy(0, reinterpret_cast<const UniChar*>(destination.characters()), destination.length(), kCFAllocatorNull));
+    RetainPtr<CFURLRef> pathURL(AdoptCF, CFURLCreateWithFileSystemPath(0, cfPath.get(), kCFURLWindowsPathStyle, false));
+    CFURLDownloadSetDestination(cfURLDownloadRef, pathURL.get(), allowOverwrite);
+}
+
+void didCreateDestinationCallback(CFURLDownloadRef, CFURLRef url, const void* clientInfo)
+{ 
+    RetainPtr<CFStringRef> path(AdoptCF, CFURLCopyFileSystemPath(url, kCFURLWindowsPathStyle));
+    String result(path.get());
+    downloadFromClientInfo(clientInfo)->didCreateDestination(result);
+}
+
+void didFinishCallback(CFURLDownloadRef, const void* clientInfo)
+{ 
+    downloadFromClientInfo(clientInfo)->didFinish();
+}
+
+void didFailCallback(CFURLDownloadRef, CFErrorRef error, const void* clientInfo)
+{ 
+    CoreIPC::DataReference dataReference(0, 0);
+    downloadFromClientInfo(clientInfo)->didFail(ResourceError(error), dataReference);
+}
+
 } // namespace WebKit