1635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project/*
2635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Copyright (C) 2007 Apple Inc.  All rights reserved.
3635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *
4635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Redistribution and use in source and binary forms, with or without
5635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * modification, are permitted provided that the following conditions
6635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * are met:
7635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
8635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
9635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
10635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
11635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *    documentation and/or other materials provided with the distribution.
12635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *
13635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project */
25635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
26635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "config.h"
27635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "WebKitDLL.h"
28635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "WebDownload.h"
29635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
30635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "DefaultDownloadDelegate.h"
31635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "MarshallingHelpers.h"
32635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "WebError.h"
33635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "WebKit.h"
34635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "WebKitLogging.h"
35635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "WebMutableURLRequest.h"
36635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "WebURLAuthenticationChallenge.h"
37635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "WebURLCredential.h"
38635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "WebURLResponse.h"
39635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
40635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <wtf/platform.h>
41dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include <wtf/text/CString.h>
42635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
43635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <io.h>
44635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <sys/stat.h>
45635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <sys/types.h>
46635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
47635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <WebCore/AuthenticationCF.h>
48635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <WebCore/BString.h>
49231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include <WebCore/CredentialStorage.h>
502fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include <WebCore/DownloadBundle.h>
51643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#include <WebCore/LoaderRunLoopCF.h>
52635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <WebCore/ResourceError.h>
53635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <WebCore/ResourceHandle.h>
54635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <WebCore/ResourceRequest.h>
55635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <WebCore/ResourceResponse.h>
56635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <wtf/CurrentTime.h>
57635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
58635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectusing namespace WebCore;
59635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
60635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// CFURLDownload Callbacks ----------------------------------------------------------------
61635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void didStartCallback(CFURLDownloadRef download, const void *clientInfo);
62635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic CFURLRequestRef willSendRequestCallback(CFURLDownloadRef download, CFURLRequestRef request, CFURLResponseRef redirectionResponse, const void *clientInfo);
63635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void didReceiveAuthenticationChallengeCallback(CFURLDownloadRef download, CFURLAuthChallengeRef challenge, const void *clientInfo);
64635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void didReceiveResponseCallback(CFURLDownloadRef download, CFURLResponseRef response, const void *clientInfo);
65635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void willResumeWithResponseCallback(CFURLDownloadRef download, CFURLResponseRef response, UInt64 startingByte, const void *clientInfo);
66635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void didReceiveDataCallback(CFURLDownloadRef download, CFIndex length, const void *clientInfo);
67635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic Boolean shouldDecodeDataOfMIMETypeCallback(CFURLDownloadRef download, CFStringRef encodingType, const void *clientInfo);
68635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void decideDestinationWithSuggestedObjectNameCallback(CFURLDownloadRef download, CFStringRef objectName, const void *clientInfo);
69635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void didCreateDestinationCallback(CFURLDownloadRef download, CFURLRef path, const void *clientInfo);
70635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void didFinishCallback(CFURLDownloadRef download, const void *clientInfo);
71635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void didFailCallback(CFURLDownloadRef download, CFErrorRef error, const void *clientInfo);
72635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
73635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid WebDownload::init(ResourceHandle* handle, const ResourceRequest& request, const ResourceResponse& response, IWebDownloadDelegate* delegate)
74635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
75635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_delegate = delegate ? delegate : DefaultDownloadDelegate::sharedInstance();
76635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLConnectionRef connection = handle->connection();
77635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!connection) {
78635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG_ERROR("WebDownload::WebDownload(ResourceHandle*,...) called with an inactive ResourceHandle");
79635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return;
80635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
81635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
82635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLDownloadClient client = {0, this, 0, 0, 0, didStartCallback, willSendRequestCallback, didReceiveAuthenticationChallengeCallback,
83635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        didReceiveResponseCallback, willResumeWithResponseCallback, didReceiveDataCallback, shouldDecodeDataOfMIMETypeCallback,
84635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        decideDestinationWithSuggestedObjectNameCallback, didCreateDestinationCallback, didFinishCallback, didFailCallback};
85635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
86635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_request.adoptRef(WebMutableURLRequest::createInstance(request));
87635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_download.adoptCF(CFURLDownloadCreateAndStartWithLoadingConnection(0, connection, request.cfURLRequest(), response.cfURLResponse(), &client));
88635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
89635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // It is possible for CFURLDownloadCreateAndStartWithLoadingConnection() to fail if the passed in CFURLConnection is not in a "downloadable state"
90635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // However, we should never hit that case
91635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!m_download) {
92635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        ASSERT_NOT_REACHED();
93635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG_ERROR("WebDownload - Failed to create WebDownload from existing connection (%s)", request.url().string().utf8().data());
94635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    } else
95635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG(Download, "WebDownload - Created WebDownload %p from existing connection (%s)", this, request.url().string().utf8().data());
96635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
97635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // The CFURLDownload either starts successfully and retains the CFURLConnection,
98635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // or it fails to creating and we have a now-useless connection with a dangling ref.
99635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Either way, we need to release the connection to balance out ref counts
100635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    handle->releaseConnectionForDownload();
101635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFRelease(connection);
102635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
103635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
104635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid WebDownload::init(const KURL& url, IWebDownloadDelegate* delegate)
105635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
106635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_delegate = delegate ? delegate : DefaultDownloadDelegate::sharedInstance();
107635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LOG_ERROR("Delegate is %p", m_delegate.get());
108635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
109635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ResourceRequest request(url);
110635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLRequestRef cfRequest = request.cfURLRequest();
111635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
112635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLDownloadClient client = {0, this, 0, 0, 0, didStartCallback, willSendRequestCallback, didReceiveAuthenticationChallengeCallback,
113635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                  didReceiveResponseCallback, willResumeWithResponseCallback, didReceiveDataCallback, shouldDecodeDataOfMIMETypeCallback,
114635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                  decideDestinationWithSuggestedObjectNameCallback, didCreateDestinationCallback, didFinishCallback, didFailCallback};
115635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_request.adoptRef(WebMutableURLRequest::createInstance(request));
116635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_download.adoptCF(CFURLDownloadCreate(0, cfRequest, &client));
117635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
118635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLDownloadScheduleWithCurrentMessageQueue(m_download.get());
119643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    CFURLDownloadScheduleDownloadWithRunLoop(m_download.get(), loaderRunLoop(), kCFRunLoopDefaultMode);
120635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
121635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LOG(Download, "WebDownload - Initialized download of url %s in WebDownload %p", url.string().utf8().data(), this);
122635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
123635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
124635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// IWebDownload -------------------------------------------------------------------
125635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
126635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebDownload::initWithRequest(
127635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        /* [in] */ IWebURLRequest* request,
128635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        /* [in] */ IWebDownloadDelegate* delegate)
129635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
130635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    COMPtr<WebMutableURLRequest> webRequest;
131635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!request || FAILED(request->QueryInterface(&webRequest))) {
132635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG(Download, "WebDownload - initWithRequest failed - not a WebMutableURLRequest");
133635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_FAIL;
134635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
135635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
136635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!delegate)
137635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_FAIL;
138635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_delegate = delegate;
139635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LOG(Download, "Delegate is %p", m_delegate.get());
140635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
141635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    RetainPtr<CFURLRequestRef> cfRequest = webRequest->resourceRequest().cfURLRequest();
142635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
143635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLDownloadClient client = {0, this, 0, 0, 0, didStartCallback, willSendRequestCallback, didReceiveAuthenticationChallengeCallback,
144635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                  didReceiveResponseCallback, willResumeWithResponseCallback, didReceiveDataCallback, shouldDecodeDataOfMIMETypeCallback,
145635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                  decideDestinationWithSuggestedObjectNameCallback, didCreateDestinationCallback, didFinishCallback, didFailCallback};
146635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_request.adoptRef(WebMutableURLRequest::createInstance(webRequest.get()));
147635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_download.adoptCF(CFURLDownloadCreate(0, cfRequest.get(), &client));
148635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
149635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // If for some reason the download failed to create,
150635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // we have particular cleanup to do
151635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!m_download) {
152635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_request = 0;
153635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_FAIL;
154635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
155635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
156635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLDownloadScheduleWithCurrentMessageQueue(m_download.get());
157643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    CFURLDownloadScheduleDownloadWithRunLoop(m_download.get(), loaderRunLoop(), kCFRunLoopDefaultMode);
158635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
159635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LOG(Download, "WebDownload - initWithRequest complete, started download of url %s", webRequest->resourceRequest().url().string().utf8().data());
160635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return S_OK;
161635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
162635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
163635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebDownload::initToResumeWithBundle(
164635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        /* [in] */ BSTR bundlePath,
165635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        /* [in] */ IWebDownloadDelegate* delegate)
166635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
167635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LOG(Download, "Attempting resume of download bundle %s", String(bundlePath, SysStringLen(bundlePath)).ascii().data());
168635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1692fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    RetainPtr<CFDataRef> resumeData(AdoptCF, DownloadBundle::extractResumeData(String(bundlePath, SysStringLen(bundlePath))));
1702fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
171635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!resumeData)
172635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_FAIL;
173635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
174635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!delegate)
175635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_FAIL;
176635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_delegate = delegate;
177635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LOG(Download, "Delegate is %p", m_delegate.get());
178635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
179635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLDownloadClient client = {0, this, 0, 0, 0, didStartCallback, willSendRequestCallback, didReceiveAuthenticationChallengeCallback,
180635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                  didReceiveResponseCallback, willResumeWithResponseCallback, didReceiveDataCallback, shouldDecodeDataOfMIMETypeCallback,
181635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                                  decideDestinationWithSuggestedObjectNameCallback, didCreateDestinationCallback, didFinishCallback, didFailCallback};
182635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
183635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    RetainPtr<CFURLRef> pathURL(AdoptCF, MarshallingHelpers::PathStringToFileCFURLRef(String(bundlePath, SysStringLen(bundlePath))));
184635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(pathURL);
185635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
186635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_download.adoptCF(CFURLDownloadCreateWithResumeData(0, resumeData.get(), pathURL.get(), &client));
187635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
188635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!m_download) {
189635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG(Download, "Failed to create CFURLDownloadRef for resume");
190635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_FAIL;
191635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
192635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
193635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_bundlePath = String(bundlePath, SysStringLen(bundlePath));
194635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Attempt to remove the ".download" extension from the bundle for the final file destination
195635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Failing that, we clear m_destination and will ask the delegate later once the download starts
1962fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (m_bundlePath.endsWith(DownloadBundle::fileExtension(), false)) {
197231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        m_destination = m_bundlePath.threadsafeCopy();
1982fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        m_destination.truncate(m_destination.length() - DownloadBundle::fileExtension().length());
199635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    } else
200635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_destination = String();
201635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
202635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLDownloadScheduleWithCurrentMessageQueue(m_download.get());
203643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    CFURLDownloadScheduleDownloadWithRunLoop(m_download.get(), loaderRunLoop(), kCFRunLoopDefaultMode);
204635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
205635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LOG(Download, "WebDownload - initWithRequest complete, resumed download of bundle %s", String(bundlePath, SysStringLen(bundlePath)).ascii().data());
206635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return S_OK;
207635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
208635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
209635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebDownload::start()
210635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
211635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LOG(Download, "WebDownload - Starting download (%p)", this);
212635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!m_download)
213635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_FAIL;
214635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
215635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLDownloadStart(m_download.get());
216635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: 4950477 - CFURLDownload neglects to make the didStart() client call upon starting the download.
217635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // This is a somewhat critical call, so we'll fake it for now!
218635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    didStart();
219635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
220635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return S_OK;
221635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
222635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
223635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebDownload::cancel()
224635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
225635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LOG(Download, "WebDownload - Cancelling download (%p)", this);
226635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!m_download)
227635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_FAIL;
228635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
229635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLDownloadCancel(m_download.get());
230635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_download = 0;
231635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return S_OK;
232635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
233635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
234635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebDownload::cancelForResume()
235635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
236635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LOG(Download, "WebDownload - Cancelling download (%p), writing resume information to file if possible", this);
237635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(m_download);
238635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!m_download)
239635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_FAIL;
240635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
241635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    HRESULT hr = S_OK;
242635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    RetainPtr<CFDataRef> resumeData;
243635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_destination.isEmpty()) {
244635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CFURLDownloadCancel(m_download.get());
245635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        goto exit;
246635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
247635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
248635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLDownloadSetDeletesUponFailure(m_download.get(), false);
249635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLDownloadCancel(m_download.get());
250635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
2512fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    resumeData.adoptCF(CFURLDownloadCopyResumeData(m_download.get()));
252635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!resumeData) {
253635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG(Download, "WebDownload - Unable to create resume data for download (%p)", this);
254635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        goto exit;
255635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
256635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
2572fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    DownloadBundle::appendResumeData(resumeData.get(), m_bundlePath);
2582fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
259635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectexit:
260635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_download = 0;
261635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return hr;
262635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
263635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
264635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebDownload::deletesFileUponFailure(
265635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        /* [out, retval] */ BOOL* result)
266635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
267635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!m_download)
268635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_FAIL;
269635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    *result = CFURLDownloadDeletesUponFailure(m_download.get());
270635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return S_OK;
271635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
272635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
273635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebDownload::setDeletesFileUponFailure(
274635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        /* [in] */ BOOL deletesFileUponFailure)
275635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
276635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!m_download)
277635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_FAIL;
278635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLDownloadSetDeletesUponFailure(m_download.get(), !!deletesFileUponFailure);
279635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return S_OK;
280635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
281635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
282635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebDownload::setDestination(
283635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        /* [in] */ BSTR path,
284635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        /* [in] */ BOOL allowOverwrite)
285635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
286635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!m_download)
287635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_FAIL;
288635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
289635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_destination = String(path, SysStringLen(path));
2902fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    m_bundlePath = m_destination + DownloadBundle::fileExtension();
291635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
292635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLRef pathURL = MarshallingHelpers::PathStringToFileCFURLRef(m_bundlePath);
293635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLDownloadSetDestination(m_download.get(), pathURL, !!allowOverwrite);
294635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFRelease(pathURL);
295635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
296635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LOG(Download, "WebDownload - Set destination to %s", m_bundlePath.ascii().data());
297635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
298635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return S_OK;
299635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
300635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
301635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// IWebURLAuthenticationChallengeSender -------------------------------------------------------------------
302635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
303635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebDownload::cancelAuthenticationChallenge(
304635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        /* [in] */ IWebURLAuthenticationChallenge*)
305635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
306635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_download) {
307635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CFURLDownloadCancel(m_download.get());
308635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_download = 0;
309635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
310635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
311635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: Do we need a URL or description for this error code?
312635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ResourceError error(String(WebURLErrorDomain), WebURLErrorUserCancelledAuthentication, "", "");
313635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    COMPtr<WebError> webError(AdoptCOM, WebError::createInstance(error));
314635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_delegate->didFailWithError(this, webError.get());
315635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
316635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return S_OK;
317635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
318635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
319635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebDownload::continueWithoutCredentialForAuthenticationChallenge(
320635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        /* [in] */ IWebURLAuthenticationChallenge* challenge)
321635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
322635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    COMPtr<WebURLAuthenticationChallenge> webChallenge(Query, challenge);
323635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!webChallenge)
324635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_NOINTERFACE;
325635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
326635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_download)
327635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CFURLDownloadUseCredential(m_download.get(), 0, webChallenge->authenticationChallenge().cfURLAuthChallengeRef());
328635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return S_OK;
329635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
330635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
331635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHRESULT STDMETHODCALLTYPE WebDownload::useCredential(
332635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        /* [in] */ IWebURLCredential* credential,
333635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        /* [in] */ IWebURLAuthenticationChallenge* challenge)
334635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
335635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    COMPtr<WebURLAuthenticationChallenge> webChallenge(Query, challenge);
336635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!webChallenge)
337635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_NOINTERFACE;
338635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
339635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    COMPtr<WebURLCredential> webCredential(Query, credential);
340635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!webCredential)
341635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return E_NOINTERFACE;
342635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
343635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    RetainPtr<CFURLCredentialRef> cfCredential(AdoptCF, createCF(webCredential->credential()));
344635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
345635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_download)
346635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        CFURLDownloadUseCredential(m_download.get(), cfCredential.get(), webChallenge->authenticationChallenge().cfURLAuthChallengeRef());
347635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return S_OK;
348635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
349635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
350635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// CFURLDownload Callbacks -------------------------------------------------------------------
351635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid WebDownload::didStart()
352635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
353635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#ifndef NDEBUG
354635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_startTime = m_dataTime = currentTime();
355635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_received = 0;
356635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LOG(Download, "DOWNLOAD - Started %p at %.3f seconds", this, m_startTime);
357635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
358635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (FAILED(m_delegate->didBegin(this)))
359635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG_ERROR("DownloadDelegate->didBegin failed");
360635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
361635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
362635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectCFURLRequestRef WebDownload::willSendRequest(CFURLRequestRef request, CFURLResponseRef response)
363635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
364635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    COMPtr<WebMutableURLRequest> webRequest(AdoptCOM, WebMutableURLRequest::createInstance(ResourceRequest(request)));
365635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    COMPtr<WebURLResponse> webResponse(AdoptCOM, WebURLResponse::createInstance(ResourceResponse(response)));
366635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    COMPtr<IWebMutableURLRequest> finalRequest;
367635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
368635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (FAILED(m_delegate->willSendRequest(this, webRequest.get(), webResponse.get(), &finalRequest)))
369635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG_ERROR("DownloadDelegate->willSendRequest failed");
370635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
371635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!finalRequest)
372635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return 0;
373635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
374635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    COMPtr<WebMutableURLRequest> finalWebRequest(AdoptCOM, WebMutableURLRequest::createInstance(finalRequest.get()));
375635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_request = finalWebRequest.get();
376635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFURLRequestRef result = finalWebRequest->resourceRequest().cfURLRequest();
377635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CFRetain(result);
378635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return result;
379635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
380635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
381635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid WebDownload::didReceiveAuthenticationChallenge(CFURLAuthChallengeRef challenge)
382635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
3830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // Try previously stored credential first.
3840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!CFURLAuthChallengeGetPreviousFailureCount(challenge)) {
385231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        Credential credential = CredentialStorage::get(core(CFURLAuthChallengeGetProtectionSpace(challenge)));
386231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (!credential.isEmpty()) {
387231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            RetainPtr<CFURLCredentialRef> cfCredential(AdoptCF, createCF(credential));
388231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            CFURLDownloadUseCredential(m_download.get(), cfCredential.get(), challenge);
3890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return;
3900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        }
3910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
3920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
393635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    COMPtr<IWebURLAuthenticationChallenge> webChallenge(AdoptCOM,
394635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        WebURLAuthenticationChallenge::createInstance(AuthenticationChallenge(challenge, 0), this));
395635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
396635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (SUCCEEDED(m_delegate->didReceiveAuthenticationChallenge(this, webChallenge.get())))
397635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return;
398635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
399635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    cancelAuthenticationChallenge(webChallenge.get());
400635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
401635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
402635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid WebDownload::didReceiveResponse(CFURLResponseRef response)
403635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
404635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    COMPtr<WebURLResponse> webResponse(AdoptCOM, WebURLResponse::createInstance(ResourceResponse(response)));
405635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (FAILED(m_delegate->didReceiveResponse(this, webResponse.get())))
406635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG_ERROR("DownloadDelegate->didReceiveResponse failed");
407635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
408635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
409635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid WebDownload::willResumeWithResponse(CFURLResponseRef response, UInt64 fromByte)
410635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
411635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    COMPtr<WebURLResponse> webResponse(AdoptCOM, WebURLResponse::createInstance(ResourceResponse(response)));
412635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (FAILED(m_delegate->willResumeWithResponse(this, webResponse.get(), fromByte)))
413635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG_ERROR("DownloadDelegate->willResumeWithResponse failed");
414635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
415635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
416635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid WebDownload::didReceiveData(CFIndex length)
417635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
418635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#ifndef NDEBUG
419635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_received += length;
420635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    double current = currentTime();
421635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (current - m_dataTime > 2.0)
422635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG(Download, "DOWNLOAD - %p hanged for %.3f seconds - Received %i bytes for a total of %i", this, current - m_dataTime, length, m_received);
423635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_dataTime = current;
424635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
425635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (FAILED(m_delegate->didReceiveDataOfLength(this, length)))
426635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG_ERROR("DownloadDelegate->didReceiveData failed");
427635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
428635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
429635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectbool WebDownload::shouldDecodeDataOfMIMEType(CFStringRef mimeType)
430635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
431635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    BOOL result;
432635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (FAILED(m_delegate->shouldDecodeSourceDataOfMIMEType(this, BString(mimeType), &result))) {
433635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG_ERROR("DownloadDelegate->shouldDecodeSourceDataOfMIMEType failed");
434635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return false;
435635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
436635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return !!result;
437635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
438635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
439635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid WebDownload::decideDestinationWithSuggestedObjectName(CFStringRef name)
440635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
441635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (FAILED(m_delegate->decideDestinationWithSuggestedFilename(this, BString(name))))
442635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG_ERROR("DownloadDelegate->decideDestinationWithSuggestedObjectName failed");
443635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
444635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
445635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid WebDownload::didCreateDestination(CFURLRef destination)
446635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
447635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // The concept of the ".download bundle" is internal to the WebDownload, so therefore
448635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // we try to mask the delegate from its existence as much as possible by telling it the final
449635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // destination was created, when in reality the bundle was created
450635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
451635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    String createdDestination = MarshallingHelpers::FileCFURLRefToPathString(destination);
452635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
453635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // At this point in receiving CFURLDownload callbacks, we should definitely have the bundle path stored locally
454635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // and it should match with the file that CFURLDownload created
455635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(createdDestination == m_bundlePath);
456635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // And we should also always have the final-destination stored
457635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(!m_destination.isEmpty());
458635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
459635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    BString path(m_destination);
460635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (FAILED(m_delegate->didCreateDestination(this, path)))
461635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG_ERROR("DownloadDelegate->didCreateDestination failed");
462635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
463635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
464635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid WebDownload::didFinish()
465635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
466635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#ifndef NDEBUG
467635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LOG(Download, "DOWNLOAD - Finished %p after %i bytes and %.3f seconds", this, m_received, currentTime() - m_startTime);
468635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
469635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
470635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(!m_bundlePath.isEmpty() && !m_destination.isEmpty());
471635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LOG(Download, "WebDownload - Moving file from bundle %s to destination %s", m_bundlePath.ascii().data(), m_destination.ascii().data());
472635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
473635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // We try to rename the bundle to the final file name.  If that fails, we give the delegate one more chance to chose
474635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // the final file name, then we just leave it
475635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!MoveFileEx(m_bundlePath.charactersWithNullTermination(), m_destination.charactersWithNullTermination(), 0)) {
476635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG_ERROR("Failed to move bundle %s to %s on completion\nError - %i", m_bundlePath.ascii().data(), m_destination.ascii().data(), GetLastError());
477635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
478635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        bool reportBundlePathAsFinalPath = true;
479635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
480635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        BString destinationBSTR(m_destination.characters(), m_destination.length());
481635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (FAILED(m_delegate->decideDestinationWithSuggestedFilename(this, destinationBSTR)))
482635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            LOG_ERROR("delegate->decideDestinationWithSuggestedFilename() failed");
483635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
484635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // The call to m_delegate->decideDestinationWithSuggestedFilename() should have changed our destination, so we'll try the move
485635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // one last time.
486635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (!m_destination.isEmpty())
487635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (MoveFileEx(m_bundlePath.charactersWithNullTermination(), m_destination.charactersWithNullTermination(), 0))
488635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                reportBundlePathAsFinalPath = false;
489635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
490635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // We either need to tell the delegate our final filename is the bundle filename, or is the file name they just told us to use
491635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (reportBundlePathAsFinalPath) {
492635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            BString bundleBSTR(m_bundlePath);
493635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_delegate->didCreateDestination(this, bundleBSTR);
494635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        } else {
495635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            BString finalDestinationBSTR = BString(m_destination);
496635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_delegate->didCreateDestination(this, finalDestinationBSTR);
497635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
498635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
499635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
500635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // It's extremely likely the call to delegate->didFinish() will deref this, so lets not let that cause our destruction just yet
501635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    COMPtr<WebDownload> protect = this;
502635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (FAILED(m_delegate->didFinish(this)))
503635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG_ERROR("DownloadDelegate->didFinish failed");
504635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
505635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_download = 0;
506635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
507635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
508635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid WebDownload::didFail(CFErrorRef error)
509635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
510635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    COMPtr<WebError> webError(AdoptCOM, WebError::createInstance(ResourceError(error)));
511635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (FAILED(m_delegate->didFailWithError(this, webError.get())))
512635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        LOG_ERROR("DownloadDelegate->didFailWithError failed");
513635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
514635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
515635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// CFURLDownload Callbacks ----------------------------------------------------------------
516635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid didStartCallback(CFURLDownloadRef, const void *clientInfo)
517635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ ((WebDownload*)clientInfo)->didStart(); }
518635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
519635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectCFURLRequestRef willSendRequestCallback(CFURLDownloadRef, CFURLRequestRef request, CFURLResponseRef redirectionResponse, const void *clientInfo)
520635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ return ((WebDownload*)clientInfo)->willSendRequest(request, redirectionResponse); }
521635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
522635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid didReceiveAuthenticationChallengeCallback(CFURLDownloadRef, CFURLAuthChallengeRef challenge, const void *clientInfo)
523635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ ((WebDownload*)clientInfo)->didReceiveAuthenticationChallenge(challenge); }
524635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
525635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid didReceiveResponseCallback(CFURLDownloadRef, CFURLResponseRef response, const void *clientInfo)
526635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ ((WebDownload*)clientInfo)->didReceiveResponse(response); }
527635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
528635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid willResumeWithResponseCallback(CFURLDownloadRef, CFURLResponseRef response, UInt64 startingByte, const void *clientInfo)
529635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ ((WebDownload*)clientInfo)->willResumeWithResponse(response, startingByte); }
530635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
531635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid didReceiveDataCallback(CFURLDownloadRef, CFIndex length, const void *clientInfo)
532635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ ((WebDownload*)clientInfo)->didReceiveData(length); }
533635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
534635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectBoolean shouldDecodeDataOfMIMETypeCallback(CFURLDownloadRef, CFStringRef encodingType, const void *clientInfo)
535635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ return ((WebDownload*)clientInfo)->shouldDecodeDataOfMIMEType(encodingType); }
536635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
537635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid decideDestinationWithSuggestedObjectNameCallback(CFURLDownloadRef, CFStringRef objectName, const void *clientInfo)
538635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ ((WebDownload*)clientInfo)->decideDestinationWithSuggestedObjectName(objectName); }
539635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
540635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid didCreateDestinationCallback(CFURLDownloadRef, CFURLRef path, const void *clientInfo)
541635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ ((WebDownload*)clientInfo)->didCreateDestination(path); }
542635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
543635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid didFinishCallback(CFURLDownloadRef, const void *clientInfo)
544635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ ((WebDownload*)clientInfo)->didFinish(); }
545635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
546635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid didFailCallback(CFURLDownloadRef, CFErrorRef error, const void *clientInfo)
547635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ ((WebDownload*)clientInfo)->didFail(error); }
548