Downloads in WK2 on Windows should write resume data to bundle
authorjhoneycutt@apple.com <jhoneycutt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 29 Jan 2011 08:34:46 +0000 (08:34 +0000)
committerjhoneycutt@apple.com <jhoneycutt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 29 Jan 2011 08:34:46 +0000 (08:34 +0000)
https://bugs.webkit.org/show_bug.cgi?id=53282
<rdar://problem/8753077>

Reviewed by Alice Liu.

Source/WebCore:

* WebCore.vcproj/WebCore.vcproj:
Added new files to project.

* platform/network/cf/DownloadBundle.h: Added.
* platform/network/win/DownloadBundleWin.cpp: Added.
(WebCore::DownloadBundle::magicNumber):
Moved from WebKit's WebDownload so that WebKit and WebKit2 can share
it.
(WebCore::DownloadBundle::fileExtension):
Ditto.
(WebCore::DownloadBundle::appendResumeData):
Ditto - but modified to return bool rather than HRESULT and to clean up
whitespace.
(WebCore::DownloadBundle::extractResumeData):
Ditto - modified to clean up whitespace.

Source/WebKit/win:

* WebDownload.cpp:
(WebDownload::bundlePathForTargetPath):
Use the new WebCore::DownloadBundle function.
(WebDownload::request):

* WebDownload.h:
Removed declarations for functions that were moved to a new location.

* WebDownloadCFNet.cpp:
(WebDownload::initToResumeWithBundle):
Use the new WebCore::DownloadBundle function.
(WebDownload::cancelForResume):
Fix a leak of the resume data CFDataRef by using adoptCF(). Use the new
WebCore::DownloadBundle function.

Source/WebKit2:

* WebProcess/Downloads/Download.cpp:
(WebKit::Download::decideDestinationWithSuggestedFilename):
Call didDecideDestination(), now that the destination is decided.

* WebProcess/Downloads/Download.h:
Declare didDecideDestination(). Added member variables to hold the
destination file path and the download bundle path.
(WebKit::Download::destination):
Return the path to the final destination for this download.

* WebProcess/Downloads/cf/DownloadCFNet.cpp:
(WebKit::Download::start):
Remove the name of an unused param.
(WebKit::Download::startWithHandle):
Ditto.
(WebKit::Download::cancel):
Tell CFNetwork not to delete the file upon failure, and tell it to
cancel the download. Copy the resume data for the download, and append
it to the download bundle. Call didCancel() with an empty
DataReference, since we have written our own resume data.
(WebKit::decideDestinationWithSuggestedObjectNameCallback):
Remove some unused param names. Removed the call to
CFURLDownloadSetDestination() - this is now handled in
Download::didDecideDestination().
(WebKit::didCreateDestinationCallback):
Report that the final destination was created, rather than the download
bundle, matching old WebKit.
(WebKit::Download::didDecideDestination):
Store the final destination and the download bundle paths, and call
CFURLDownloadSetDestination(), passing the path to the download bundle.

* WebProcess/Downloads/curl/DownloadCurl.cpp:
(WebKit::Download::didDecideDestination):
Stubbed.

* WebProcess/Downloads/mac/DownloadMac.mm:
(WebKit::Download::didDecideDestination):
Stubbed - unneeded on the Mac.

* WebProcess/Downloads/qt/DownloadQt.cpp:
(WebKit::Download::didDecideDestination):
Stubbed.

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

15 files changed:
Source/WebCore/ChangeLog
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/platform/network/cf/DownloadBundle.h [new file with mode: 0644]
Source/WebCore/platform/network/win/DownloadBundleWin.cpp [new file with mode: 0644]
Source/WebKit/win/ChangeLog
Source/WebKit/win/WebDownload.cpp
Source/WebKit/win/WebDownload.h
Source/WebKit/win/WebDownloadCFNet.cpp
Source/WebKit2/ChangeLog
Source/WebKit2/WebProcess/Downloads/Download.cpp
Source/WebKit2/WebProcess/Downloads/Download.h
Source/WebKit2/WebProcess/Downloads/cf/DownloadCFNet.cpp
Source/WebKit2/WebProcess/Downloads/curl/DownloadCurl.cpp
Source/WebKit2/WebProcess/Downloads/mac/DownloadMac.mm
Source/WebKit2/WebProcess/Downloads/qt/DownloadQt.cpp

index 6da72c3..7e4096d 100644 (file)
@@ -1,3 +1,27 @@
+2011-01-28  Jon Honeycutt  <jhoneycutt@apple.com>
+
+        Downloads in WK2 on Windows should write resume data to bundle
+        https://bugs.webkit.org/show_bug.cgi?id=53282
+        <rdar://problem/8753077>
+
+        Reviewed by Alice Liu.
+
+        * WebCore.vcproj/WebCore.vcproj:
+        Added new files to project.
+
+        * platform/network/cf/DownloadBundle.h: Added.
+        * platform/network/win/DownloadBundleWin.cpp: Added.
+        (WebCore::DownloadBundle::magicNumber):
+        Moved from WebKit's WebDownload so that WebKit and WebKit2 can share
+        it.
+        (WebCore::DownloadBundle::fileExtension):
+        Ditto.
+        (WebCore::DownloadBundle::appendResumeData):
+        Ditto - but modified to return bool rather than HRESULT and to clean up
+        whitespace.
+        (WebCore::DownloadBundle::extractResumeData):
+        Ditto - modified to clean up whitespace.
+
 2011-01-29  Sheriff Bot  <webkit.review.bot@gmail.com>
 
         Unreviewed, rolling out r77050.
index 821784e..1422df4 100755 (executable)
                                                </FileConfiguration>
                                        </File>
                                        <File
+                                               RelativePath="..\platform\network\cf\DownloadBundle.h"
+                                               >
+                                       </File>
+                                       <File
                                                RelativePath="..\platform\network\cf\FormDataStreamCFNet.cpp"
                                                >
                                                <FileConfiguration
                                        Name="win"
                                        >
                                        <File
+                                               RelativePath="..\platform\network\win\DownloadBundleWin.cpp"
+                                               >
+                                       </File>
+                                       <File
                                                RelativePath="..\platform\network\win\NetworkStateNotifierWin.cpp"
                                                >
                                        </File>
diff --git a/Source/WebCore/platform/network/cf/DownloadBundle.h b/Source/WebCore/platform/network/cf/DownloadBundle.h
new file mode 100644 (file)
index 0000000..d159277
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 Apple Inc.  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 COMPUTER, 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 COMPUTER, 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 DownloadBundle_h
+#define DownloadBundle_h
+
+namespace WTF {
+    class String;
+}
+
+namespace WebCore {
+
+namespace DownloadBundle {
+
+bool appendResumeData(CFDataRef resumeData, const WTF::String& bundlePath);
+CFDataRef extractResumeData(const WTF::String& bundlePath);
+const WTF::String& fileExtension();
+
+}
+
+}
+
+#endif // DownloadBundle_h
diff --git a/Source/WebCore/platform/network/win/DownloadBundleWin.cpp b/Source/WebCore/platform/network/win/DownloadBundleWin.cpp
new file mode 100644 (file)
index 0000000..8a091da
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2011 Apple Inc.  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 COMPUTER, 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 COMPUTER, 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 "DownloadBundle.h"
+
+#include <io.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+using WTF::String;
+
+namespace WebCore {
+
+namespace DownloadBundle {
+
+static UInt32 magicNumber()
+{
+    return 0xDECAF4EA;
+}
+
+const String& fileExtension()
+{
+    DEFINE_STATIC_LOCAL(const String, extension, (".download"));
+    return extension;
+}
+
+bool appendResumeData(CFDataRef resumeData, const String& bundlePath)
+{
+    if (!resumeData) {
+        LOG_ERROR("Invalid resume data to write to bundle path");
+        return false;
+    }
+    if (bundlePath.isEmpty()) {
+        LOG_ERROR("Cannot write resume data to empty download bundle path");
+        return false;
+    }
+
+    String nullifiedPath = bundlePath;
+    FILE* bundle = 0;
+    if (_wfopen_s(&bundle, nullifiedPath.charactersWithNullTermination(), TEXT("ab")) || !bundle) {
+        LOG_ERROR("Failed to open file %s to append resume data", bundlePath.ascii().data());
+        return false;
+    }
+
+    bool result = false;
+
+    const UInt8* resumeBytes = CFDataGetBytePtr(resumeData);
+    ASSERT(resumeBytes);
+    if (!resumeBytes)
+        goto exit;
+
+    UInt32 resumeLength = CFDataGetLength(resumeData);
+    ASSERT(resumeLength > 0);
+    if (resumeLength < 1)
+        goto exit;
+
+    if (fwrite(resumeBytes, 1, resumeLength, bundle) != resumeLength) {
+        LOG_ERROR("Failed to write resume data to the bundle - errno(%i)", errno);
+        goto exit;
+    }
+
+    if (fwrite(&resumeLength, 4, 1, bundle) != 1) {
+        LOG_ERROR("Failed to write footer length to the bundle - errno(%i)", errno);
+        goto exit;
+    }
+
+    const UInt32& magic = magicNumber();
+    if (fwrite(&magic, 4, 1, bundle) != 1) {
+        LOG_ERROR("Failed to write footer magic number to the bundle - errno(%i)", errno);
+        goto exit;
+    }
+
+    result = true;
+exit:
+    fclose(bundle);
+    return result;
+}
+
+CFDataRef extractResumeData(const String& bundlePath)
+{
+    if (bundlePath.isEmpty()) {
+        LOG_ERROR("Cannot create resume data from empty download bundle path");
+        return 0;
+    }
+
+    // Open a handle to the bundle file
+    String nullifiedPath = bundlePath;
+    FILE* bundle = 0;
+    if (_wfopen_s(&bundle, nullifiedPath.charactersWithNullTermination(), TEXT("r+b")) || !bundle) {
+        LOG_ERROR("Failed to open file %s to get resume data", bundlePath.ascii().data());
+        return 0;
+    }
+
+    CFDataRef result = 0;
+    Vector<UInt8> footerBuffer;
+
+    // Stat the file to get its size
+    struct _stat64 fileStat;
+    if (_fstat64(_fileno(bundle), &fileStat))
+        goto exit;
+
+    // Check for the bundle magic number at the end of the file
+    fpos_t footerMagicNumberPosition = fileStat.st_size - 4;
+    ASSERT(footerMagicNumberPosition >= 0);
+    if (footerMagicNumberPosition < 0)
+        goto exit;
+    if (fsetpos(bundle, &footerMagicNumberPosition))
+        goto exit;
+
+    UInt32 footerMagicNumber = 0;
+    if (fread(&footerMagicNumber, 4, 1, bundle) != 1) {
+        LOG_ERROR("Failed to read footer magic number from the bundle - errno(%i)", errno);
+        goto exit;
+    }
+
+    if (footerMagicNumber != magicNumber()) {
+        LOG_ERROR("Footer's magic number does not match 0x%X - errno(%i)", magicNumber(), errno);
+        goto exit;
+    }
+
+    // Now we're *reasonably* sure this is a .download bundle we actually wrote.
+    // Get the length of the resume data
+    fpos_t footerLengthPosition = fileStat.st_size - 8;
+    ASSERT(footerLengthPosition >= 0);
+    if (footerLengthPosition < 0)
+        goto exit;
+
+    if (fsetpos(bundle, &footerLengthPosition))
+        goto exit;
+
+    UInt32 footerLength = 0;
+    if (fread(&footerLength, 4, 1, bundle) != 1) {
+        LOG_ERROR("Failed to read ResumeData length from the bundle - errno(%i)", errno);
+        goto exit;
+    }
+
+    // Make sure theres enough bytes to read in for the resume data, and perform the read
+    fpos_t footerStartPosition = fileStat.st_size - 8 - footerLength;
+    ASSERT(footerStartPosition >= 0);
+    if (footerStartPosition < 0)
+        goto exit;
+    if (fsetpos(bundle, &footerStartPosition))
+        goto exit;
+
+    footerBuffer.resize(footerLength);
+    if (fread(footerBuffer.data(), 1, footerLength, bundle) != footerLength) {
+        LOG_ERROR("Failed to read ResumeData from the bundle - errno(%i)", errno);
+        goto exit;
+    }
+
+    // CFURLDownload will seek to the appropriate place in the file (before our footer) and start overwriting from there
+    // However, say we were within a few hundred bytes of the end of a download when it was paused -
+    // The additional footer extended the length of the file beyond its final length, and there will be junk data leftover
+    // at the end.  Therefore, now that we've retrieved the footer data, we need to truncate it.
+    if (errno_t resizeError = _chsize_s(_fileno(bundle), footerStartPosition)) {
+        LOG_ERROR("Failed to truncate the resume footer off the end of the file - errno(%i)", resizeError);
+        goto exit;
+    }
+
+    // Finally, make the resume data.  Now, it is possible by some twist of fate the bundle magic number
+    // was naturally at the end of the file and its not actually a valid bundle.  That, or someone engineered
+    // it that way to try to attack us.  In that cause, this CFData will successfully create but when we 
+    // actually try to start the CFURLDownload using this bogus data, it will fail and we will handle that gracefully
+    result = CFDataCreate(0, footerBuffer.data(), footerLength);
+exit:
+    fclose(bundle);
+    return result;
+}
+
+} // namespace DownloadBundle
+
+} // namespace WebCore
index 26cf0c5..1cb37aa 100644 (file)
@@ -1,3 +1,26 @@
+2011-01-28  Jon Honeycutt  <jhoneycutt@apple.com>
+
+        Downloads in WK2 on Windows should write resume data to bundle
+        https://bugs.webkit.org/show_bug.cgi?id=53282
+        <rdar://problem/8753077>
+
+        Reviewed by Alice Liu.
+
+        * WebDownload.cpp:
+        (WebDownload::bundlePathForTargetPath):
+        Use the new WebCore::DownloadBundle function.
+        (WebDownload::request):
+
+        * WebDownload.h:
+        Removed declarations for functions that were moved to a new location.
+
+        * WebDownloadCFNet.cpp:
+        (WebDownload::initToResumeWithBundle):
+        Use the new WebCore::DownloadBundle function.
+        (WebDownload::cancelForResume):
+        Fix a leak of the resume data CFDataRef by using adoptCF(). Use the new
+        WebCore::DownloadBundle function.
+
 2011-01-28  Dan Bernstein  <mitz@apple.com>
 
         Reviewed by Sam Weinig.
index fc72232..45e36cc 100644 (file)
 #include "WebURLResponse.h"
 #include <wtf/text/CString.h>
 
-#include <io.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
 #pragma warning(push, 0)
 #include <WebCore/BString.h>
+#include <WebCore/DownloadBundle.h>
 #include <WebCore/NotImplemented.h>
 #include <WebCore/ResourceError.h>
 #include <WebCore/ResourceHandle.h>
 
 using namespace WebCore;
 
-// Download Bundle file utilities ----------------------------------------------------------------
-const String& WebDownload::bundleExtension()
-{
-   DEFINE_STATIC_LOCAL(const String, bundleExtension, (".download"));
-   return bundleExtension;
-}
-
-UInt32 WebDownload::bundleMagicNumber()
-{
-   return 0xDECAF4EA;
-}
-
 // WebDownload ----------------------------------------------------------------
 
 WebDownload::WebDownload()
@@ -165,7 +150,7 @@ HRESULT STDMETHODCALLTYPE WebDownload::bundlePathForTargetPath(
     if (bundle[bundle.length()-1] == '/')
         bundle.truncate(1);
 
-    bundle += bundleExtension();
+    bundle += DownloadBundle::fileExtension();
     *bundlePath = SysAllocStringLen(bundle.characters(), bundle.length());
     if (!*bundlePath)
        return E_FAIL;
@@ -182,148 +167,3 @@ HRESULT STDMETHODCALLTYPE WebDownload::request(
     }
     return S_OK;
 }
-
-// Download Bundle file utilities ----------------------------------------------------------------
-
-CFDataRef WebDownload::extractResumeDataFromBundle(const String& bundlePath)
-{
-    if (bundlePath.isEmpty()) {
-        LOG_ERROR("Cannot create resume data from empty download bundle path");
-        return 0;
-    }
-    
-    // Open a handle to the bundle file
-    String nullifiedPath = bundlePath;
-    FILE* bundle = 0;
-    if (_wfopen_s(&bundle, nullifiedPath.charactersWithNullTermination(), TEXT("r+b")) || !bundle) {
-        LOG_ERROR("Failed to open file %s to get resume data", bundlePath.ascii().data());
-        return 0;
-    }
-
-    CFDataRef result = 0;
-    Vector<UInt8> footerBuffer;
-    
-    // Stat the file to get its size
-    struct _stat64 fileStat;
-    if (_fstat64(_fileno(bundle), &fileStat))
-        goto exit;
-    
-    // Check for the bundle magic number at the end of the file
-    fpos_t footerMagicNumberPosition = fileStat.st_size - 4;
-    ASSERT(footerMagicNumberPosition >= 0);
-    if (footerMagicNumberPosition < 0)
-        goto exit;
-    if (fsetpos(bundle, &footerMagicNumberPosition))
-        goto exit;
-
-    UInt32 footerMagicNumber = 0;
-    if (fread(&footerMagicNumber, 4, 1, bundle) != 1) {
-        LOG_ERROR("Failed to read footer magic number from the bundle - errno(%i)", errno);  
-        goto exit;
-    }
-
-    if (footerMagicNumber != bundleMagicNumber()) {
-        LOG_ERROR("Footer's magic number does not match 0x%X - errno(%i)", bundleMagicNumber(), errno);  
-        goto exit;
-    }
-
-    // Now we're *reasonably* sure this is a .download bundle we actually wrote. 
-    // Get the length of the resume data
-    fpos_t footerLengthPosition = fileStat.st_size - 8;
-    ASSERT(footerLengthPosition >= 0);
-    if (footerLengthPosition < 0)
-        goto exit;
-
-    if (fsetpos(bundle, &footerLengthPosition))
-        goto exit;
-
-    UInt32 footerLength = 0;
-    if (fread(&footerLength, 4, 1, bundle) != 1) {
-        LOG_ERROR("Failed to read ResumeData length from the bundle - errno(%i)", errno);  
-        goto exit;
-    }
-
-    // Make sure theres enough bytes to read in for the resume data, and perform the read
-    fpos_t footerStartPosition = fileStat.st_size - 8 - footerLength;
-    ASSERT(footerStartPosition >= 0);
-    if (footerStartPosition < 0)
-        goto exit;
-    if (fsetpos(bundle, &footerStartPosition))
-        goto exit;
-
-    footerBuffer.resize(footerLength);
-    if (fread(footerBuffer.data(), 1, footerLength, bundle) != footerLength) {
-        LOG_ERROR("Failed to read ResumeData from the bundle - errno(%i)", errno);  
-        goto exit;
-    }
-
-    // CFURLDownload will seek to the appropriate place in the file (before our footer) and start overwriting from there
-    // However, say we were within a few hundred bytes of the end of a download when it was paused -
-    // The additional footer extended the length of the file beyond its final length, and there will be junk data leftover
-    // at the end.  Therefore, now that we've retrieved the footer data, we need to truncate it.
-    if (errno_t resizeError = _chsize_s(_fileno(bundle), footerStartPosition)) {
-        LOG_ERROR("Failed to truncate the resume footer off the end of the file - errno(%i)", resizeError);
-        goto exit;
-    }
-
-    // Finally, make the resume data.  Now, it is possible by some twist of fate the bundle magic number
-    // was naturally at the end of the file and its not actually a valid bundle.  That, or someone engineered
-    // it that way to try to attack us.  In that cause, this CFData will successfully create but when we 
-    // actually try to start the CFURLDownload using this bogus data, it will fail and we will handle that gracefully
-    result = CFDataCreate(0, footerBuffer.data(), footerLength);
-exit:
-    fclose(bundle);
-    return result;
-}
-
-HRESULT WebDownload::appendResumeDataToBundle(CFDataRef resumeData, const String& bundlePath)
-{
-    if (!resumeData) {
-        LOG_ERROR("Invalid resume data to write to bundle path");
-        return E_FAIL;
-    }
-    if (bundlePath.isEmpty()) {
-        LOG_ERROR("Cannot write resume data to empty download bundle path");
-        return E_FAIL;
-    }
-
-    String nullifiedPath = bundlePath;
-    FILE* bundle = 0;
-    if (_wfopen_s(&bundle, nullifiedPath.charactersWithNullTermination(), TEXT("ab")) || !bundle) {
-        LOG_ERROR("Failed to open file %s to append resume data", bundlePath.ascii().data());
-        return E_FAIL;
-    }
-
-    HRESULT hr = E_FAIL;
-
-    const UInt8* resumeBytes = CFDataGetBytePtr(resumeData);
-    ASSERT(resumeBytes);
-    if (!resumeBytes)
-        goto exit;
-
-    UInt32 resumeLength = CFDataGetLength(resumeData);
-    ASSERT(resumeLength > 0);
-    if (resumeLength < 1)
-        goto exit;
-
-    if (fwrite(resumeBytes, 1, resumeLength, bundle) != resumeLength) {
-        LOG_ERROR("Failed to write resume data to the bundle - errno(%i)", errno);
-        goto exit;
-    }
-
-    if (fwrite(&resumeLength, 4, 1, bundle) != 1) {
-        LOG_ERROR("Failed to write footer length to the bundle - errno(%i)", errno);
-        goto exit;
-    }
-
-    const UInt32& magic = bundleMagicNumber();
-    if (fwrite(&magic, 4, 1, bundle) != 1) {
-        LOG_ERROR("Failed to write footer magic number to the bundle - errno(%i)", errno);
-        goto exit;
-    }
-    
-    hr = S_OK;
-exit:
-    fclose(bundle);
-    return hr;
-}
index bbb645e..3e8e734 100644 (file)
@@ -122,11 +122,6 @@ public:
 #endif
 
 protected:
-    static CFDataRef extractResumeDataFromBundle(const WTF::String&);
-    static HRESULT appendResumeDataToBundle(CFDataRef, const WTF::String&);
-    static const WTF::String& bundleExtension();
-    static UInt32 bundleMagicNumber();
-
     ULONG m_refCount;
 
     WTF::String m_destination;
index a199315..5a1f1bc 100644 (file)
@@ -48,6 +48,7 @@
 #include <WebCore/AuthenticationCF.h>
 #include <WebCore/BString.h>
 #include <WebCore/CredentialStorage.h>
+#include <WebCore/DownloadBundle.h>
 #include <WebCore/LoaderRunLoopCF.h>
 #include <WebCore/ResourceError.h>
 #include <WebCore/ResourceHandle.h>
@@ -167,8 +168,8 @@ HRESULT STDMETHODCALLTYPE WebDownload::initToResumeWithBundle(
 {
     LOG(Download, "Attempting resume of download bundle %s", String(bundlePath, SysStringLen(bundlePath)).ascii().data());
 
-    RetainPtr<CFDataRef> resumeData(AdoptCF, extractResumeDataFromBundle(String(bundlePath, SysStringLen(bundlePath))));
-    
+    RetainPtr<CFDataRef> resumeData(AdoptCF, DownloadBundle::extractResumeData(String(bundlePath, SysStringLen(bundlePath))));
+
     if (!resumeData)
         return E_FAIL;
 
@@ -194,9 +195,9 @@ HRESULT STDMETHODCALLTYPE WebDownload::initToResumeWithBundle(
     m_bundlePath = String(bundlePath, SysStringLen(bundlePath));
     // Attempt to remove the ".download" extension from the bundle for the final file destination
     // Failing that, we clear m_destination and will ask the delegate later once the download starts
-    if (m_bundlePath.endsWith(bundleExtension(), false)) {
+    if (m_bundlePath.endsWith(DownloadBundle::fileExtension(), false)) {
         m_destination = m_bundlePath.threadsafeCopy();
-        m_destination.truncate(m_destination.length() - bundleExtension().length());
+        m_destination.truncate(m_destination.length() - DownloadBundle::fileExtension().length());
     } else
         m_destination = String();
     
@@ -249,14 +250,14 @@ HRESULT STDMETHODCALLTYPE WebDownload::cancelForResume()
     CFURLDownloadSetDeletesUponFailure(m_download.get(), false);
     CFURLDownloadCancel(m_download.get());
 
-    resumeData = CFURLDownloadCopyResumeData(m_download.get());
+    resumeData.adoptCF(CFURLDownloadCopyResumeData(m_download.get()));
     if (!resumeData) {
         LOG(Download, "WebDownload - Unable to create resume data for download (%p)", this);
         goto exit;
     }
 
-    appendResumeDataToBundle(resumeData.get(), m_bundlePath);
-   
+    DownloadBundle::appendResumeData(resumeData.get(), m_bundlePath);
+
 exit:
     m_download = 0;
     return hr;
@@ -288,7 +289,7 @@ HRESULT STDMETHODCALLTYPE WebDownload::setDestination(
         return E_FAIL;
 
     m_destination = String(path, SysStringLen(path));
-    m_bundlePath = m_destination + bundleExtension();
+    m_bundlePath = m_destination + DownloadBundle::fileExtension();
 
     CFURLRef pathURL = MarshallingHelpers::PathStringToFileCFURLRef(m_bundlePath);
     CFURLDownloadSetDestination(m_download.get(), pathURL, !!allowOverwrite);
index f82faf1..b07a494 100644 (file)
@@ -1,3 +1,54 @@
+2011-01-28  Jon Honeycutt  <jhoneycutt@apple.com>
+
+        Downloads in WK2 on Windows should write resume data to bundle
+        https://bugs.webkit.org/show_bug.cgi?id=53282
+        <rdar://problem/8753077>
+
+        Reviewed by Alice Liu.
+
+        * WebProcess/Downloads/Download.cpp:
+        (WebKit::Download::decideDestinationWithSuggestedFilename):
+        Call didDecideDestination(), now that the destination is decided.
+
+        * WebProcess/Downloads/Download.h:
+        Declare didDecideDestination(). Added member variables to hold the
+        destination file path and the download bundle path.
+        (WebKit::Download::destination):
+        Return the path to the final destination for this download.
+
+        * WebProcess/Downloads/cf/DownloadCFNet.cpp:
+        (WebKit::Download::start):
+        Remove the name of an unused param.
+        (WebKit::Download::startWithHandle):
+        Ditto.
+        (WebKit::Download::cancel):
+        Tell CFNetwork not to delete the file upon failure, and tell it to
+        cancel the download. Copy the resume data for the download, and append
+        it to the download bundle. Call didCancel() with an empty
+        DataReference, since we have written our own resume data.
+        (WebKit::decideDestinationWithSuggestedObjectNameCallback):
+        Remove some unused param names. Removed the call to
+        CFURLDownloadSetDestination() - this is now handled in
+        Download::didDecideDestination().
+        (WebKit::didCreateDestinationCallback):
+        Report that the final destination was created, rather than the download
+        bundle, matching old WebKit.
+        (WebKit::Download::didDecideDestination):
+        Store the final destination and the download bundle paths, and call
+        CFURLDownloadSetDestination(), passing the path to the download bundle.
+
+        * WebProcess/Downloads/curl/DownloadCurl.cpp:
+        (WebKit::Download::didDecideDestination):
+        Stubbed.
+
+        * WebProcess/Downloads/mac/DownloadMac.mm:
+        (WebKit::Download::didDecideDestination):
+        Stubbed - unneeded on the Mac.
+
+        * WebProcess/Downloads/qt/DownloadQt.cpp:
+        (WebKit::Download::didDecideDestination):
+        Stubbed.
+
 2011-01-29  Jeff Miller  <jeffm@apple.com>
 
         Reviewed by Anders Carlsson.
index 4a8a0c6..0dead92 100644 (file)
@@ -95,6 +95,8 @@ String Download::decideDestinationWithSuggestedFilename(const String& filename,
     if (m_sandboxExtension)
         m_sandboxExtension->consume();
 
+    didDecideDestination(destination, allowOverwrite);
+
     return destination;
 }
 
index 97d3a62..22f04a9 100644 (file)
@@ -82,6 +82,11 @@ public:
     void didFinish();
     void didFail(const WebCore::ResourceError&, const CoreIPC::DataReference& resumeData);
     void didCancel(const CoreIPC::DataReference& resumeData);
+    void didDecideDestination(const String&, bool allowOverwrite);
+
+#if USE(CFNETWORK)
+    const String& destination() const { return m_destination; }
+#endif
 
 private:
     Download(uint64_t downloadID, const WebCore::ResourceRequest&);
@@ -98,6 +103,8 @@ private:
     RetainPtr<WKDownloadAsDelegate> m_delegate;
 #endif
 #if USE(CFNETWORK)
+    String m_destination;
+    String m_bundlePath;
     RetainPtr<CFURLDownloadRef> m_download;
 #endif
 };
index ebc37b0..a60cff1 100644 (file)
@@ -30,6 +30,7 @@
 #include "NotImplemented.h"
 
 #pragma warning(push, 0)
+#include <WebCore/DownloadBundle.h>
 #include <WebCore/LoaderRunLoopCF.h>
 #include <WebCore/ResourceError.h>
 #include <WebCore/ResourceHandle.h>
@@ -53,7 +54,7 @@ static void didCreateDestinationCallback(CFURLDownloadRef download, CFURLRef pat
 static void didFinishCallback(CFURLDownloadRef download, const void* clientInfo);
 static void didFailCallback(CFURLDownloadRef download, CFErrorRef error, const void* clientInfo);
 
-void Download::start(WebPage* initiatingWebPage)
+void Download::start(WebPage*)
 {
     ASSERT(!m_download);
 
@@ -71,7 +72,7 @@ void Download::start(WebPage* initiatingWebPage)
     CFURLDownloadScheduleDownloadWithRunLoop(m_download.get(), loaderRunLoop(), kCFRunLoopDefaultMode);
 }
 
-void Download::startWithHandle(WebPage* initiatingPage, ResourceHandle* handle, const ResourceRequest& initialRequest, const ResourceResponse& response)
+void Download::startWithHandle(WebPage*, ResourceHandle* handle, const ResourceRequest& initialRequest, const ResourceResponse& response)
 {
     ASSERT(!m_download);
 
@@ -99,7 +100,18 @@ void Download::startWithHandle(WebPage* initiatingPage, ResourceHandle* handle,
 
 void Download::cancel()
 {
-    notImplemented();
+    ASSERT(m_download);
+    if (!m_download)
+        return;
+
+    CFURLDownloadSetDeletesUponFailure(m_download.get(), false);
+    CFURLDownloadCancel(m_download.get());
+
+    RetainPtr<CFDataRef> resumeData(AdoptCF, CFURLDownloadCopyResumeData(m_download.get()));
+    if (resumeData)
+        DownloadBundle::appendResumeData(resumeData.get(), m_bundlePath);
+
+    didCancel(CoreIPC::DataReference());
 }
 
 void Download::platformInvalidate()
@@ -152,24 +164,34 @@ Boolean shouldDecodeDataOfMIMETypeCallback(CFURLDownloadRef, CFStringRef encodin
     return downloadFromClientInfo(clientInfo)->shouldDecodeSourceDataOfMIMEType(encodingType);
 }
 
-void decideDestinationWithSuggestedObjectNameCallback(CFURLDownloadRef cfURLDownloadRef, CFStringRef objectName, const void* clientInfo)
+void decideDestinationWithSuggestedObjectNameCallback(CFURLDownloadRef, CFStringRef objectName, const void* clientInfo)
 { 
     Download* download = downloadFromClientInfo(clientInfo);
     bool allowOverwrite;
-    String destination = download->decideDestinationWithSuggestedFilename(objectName, allowOverwrite);
-    if (destination.isNull())
-        return;
+    download->decideDestinationWithSuggestedFilename(objectName, allowOverwrite);
+}
 
-    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, const void* clientInfo)
+{
+    // The concept of the ".download bundle" is internal to the Download, so we try to hide its
+    // existence by reporting the final destination was created, when in reality the bundle was created.
+
+    Download* download = downloadFromClientInfo(clientInfo);
+    download->didCreateDestination(download->destination());
 }
 
-void didCreateDestinationCallback(CFURLDownloadRef, CFURLRef url, const void* clientInfo)
-{ 
-    RetainPtr<CFStringRef> path(AdoptCF, CFURLCopyFileSystemPath(url, kCFURLWindowsPathStyle));
-    String result(path.get());
-    downloadFromClientInfo(clientInfo)->didCreateDestination(result);
+void Download::didDecideDestination(const String& destination, bool allowOverwrite)
+{
+    ASSERT(!destination.isEmpty());
+    if (destination.isEmpty())
+        return;
+
+    m_destination = destination;
+    m_bundlePath = destination + DownloadBundle::fileExtension();
+
+    RetainPtr<CFStringRef> bundlePath(AdoptCF, CFStringCreateWithCharactersNoCopy(0, reinterpret_cast<const UniChar*>(m_bundlePath.characters()), m_bundlePath.length(), kCFAllocatorNull));
+    RetainPtr<CFURLRef> bundlePathURL(AdoptCF, CFURLCreateWithFileSystemPath(0, bundlePath.get(), kCFURLWindowsPathStyle, false));
+    CFURLDownloadSetDestination(m_download.get(), bundlePathURL.get(), allowOverwrite);
 }
 
 void didFinishCallback(CFURLDownloadRef, const void* clientInfo)
index a3d6ffa..92993f2 100644 (file)
@@ -53,4 +53,9 @@ void Download::platformInvalidate()
     notImplemented();
 }
 
+void Download::didDecideDestination(const String& destination, bool allowOverwrite)
+{
+    notImplemented();
+}
+
 } // namespace WebKit
index fd9c0e2..35b7743 100644 (file)
@@ -169,6 +169,10 @@ void Download::platformInvalidate()
     m_nsURLDownload = nullptr;
 }
 
+void Download::didDecideDestination(const String& destination, bool allowOverwrite)
+{
+}
+
 } // namespace WebKit
 
 @implementation WKDownloadAsDelegate
index 0250e77..a5aa633 100644 (file)
@@ -52,4 +52,9 @@ void Download::platformInvalidate()
     notImplemented();
 }
 
+void Download::didDecideDestination(const String& destination, bool allowOverwrite)
+{
+    notImplemented();
+}
+
 } // namespace WebKit