1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "DownloadProxy.h"
28
29#include "AuthenticationChallengeProxy.h"
30#include "DataReference.h"
31#include "DownloadProxyMap.h"
32#include "WebContext.h"
33#include "WebData.h"
34#include "WebProcessMessages.h"
35#include <wtf/text/CString.h>
36#include <wtf/text/WTFString.h>
37
38#if ENABLE(NETWORK_PROCESS)
39#include "NetworkProcessMessages.h"
40#include "NetworkProcessProxy.h"
41#endif
42
43using namespace WebCore;
44
45namespace WebKit {
46
47static uint64_t generateDownloadID()
48{
49    static uint64_t uniqueDownloadID = 0;
50    return ++uniqueDownloadID;
51}
52
53PassRefPtr<DownloadProxy> DownloadProxy::create(DownloadProxyMap& downloadProxyMap, WebContext* webContext)
54{
55    return adoptRef(new DownloadProxy(downloadProxyMap, webContext));
56}
57
58DownloadProxy::DownloadProxy(DownloadProxyMap& downloadProxyMap, WebContext* webContext)
59    : m_downloadProxyMap(downloadProxyMap)
60    , m_webContext(webContext)
61    , m_downloadID(generateDownloadID())
62{
63}
64
65DownloadProxy::~DownloadProxy()
66{
67    ASSERT(!m_webContext);
68}
69
70void DownloadProxy::cancel()
71{
72    if (!m_webContext)
73        return;
74
75#if ENABLE(NETWORK_PROCESS)
76    if (m_webContext->usesNetworkProcess()) {
77        if (NetworkProcessProxy* networkProcess = m_webContext->networkProcess())
78            networkProcess->connection()->send(Messages::NetworkProcess::CancelDownload(m_downloadID), 0);
79        return;
80    }
81#endif
82
83    m_webContext->sendToAllProcesses(Messages::WebProcess::CancelDownload(m_downloadID));
84}
85
86void DownloadProxy::invalidate()
87{
88    ASSERT(m_webContext);
89    m_webContext = 0;
90}
91
92void DownloadProxy::processDidClose()
93{
94    if (!m_webContext)
95        return;
96
97    m_webContext->downloadClient().processDidCrash(m_webContext.get(), this);
98}
99
100void DownloadProxy::didStart(const ResourceRequest& request)
101{
102    m_request = request;
103
104    if (!m_webContext)
105        return;
106
107    m_webContext->downloadClient().didStart(m_webContext.get(), this);
108}
109
110void DownloadProxy::didReceiveAuthenticationChallenge(const AuthenticationChallenge& authenticationChallenge, uint64_t challengeID)
111{
112    if (!m_webContext)
113        return;
114
115    RefPtr<AuthenticationChallengeProxy> authenticationChallengeProxy = AuthenticationChallengeProxy::create(authenticationChallenge, challengeID, m_webContext->networkingProcessConnection());
116
117    m_webContext->downloadClient().didReceiveAuthenticationChallenge(m_webContext.get(), this, authenticationChallengeProxy.get());
118}
119
120void DownloadProxy::didReceiveResponse(const ResourceResponse& response)
121{
122    if (!m_webContext)
123        return;
124
125    m_webContext->downloadClient().didReceiveResponse(m_webContext.get(), this, response);
126}
127
128void DownloadProxy::didReceiveData(uint64_t length)
129{
130    if (!m_webContext)
131        return;
132
133    m_webContext->downloadClient().didReceiveData(m_webContext.get(), this, length);
134}
135
136void DownloadProxy::shouldDecodeSourceDataOfMIMEType(const String& mimeType, bool& result)
137{
138    if (!m_webContext)
139        return;
140
141    result = m_webContext->downloadClient().shouldDecodeSourceDataOfMIMEType(m_webContext.get(), this, mimeType);
142}
143
144void DownloadProxy::decideDestinationWithSuggestedFilename(const String& filename, String& destination, bool& allowOverwrite, SandboxExtension::Handle& sandboxExtensionHandle)
145{
146    if (!m_webContext)
147        return;
148
149    destination = m_webContext->downloadClient().decideDestinationWithSuggestedFilename(m_webContext.get(), this, filename, allowOverwrite);
150
151    if (!destination.isNull())
152        SandboxExtension::createHandle(destination, SandboxExtension::ReadWrite, sandboxExtensionHandle);
153}
154
155void DownloadProxy::didCreateDestination(const String& path)
156{
157    if (!m_webContext)
158        return;
159
160    m_webContext->downloadClient().didCreateDestination(m_webContext.get(), this, path);
161}
162
163void DownloadProxy::didFinish()
164{
165    if (!m_webContext)
166        return;
167
168    m_webContext->downloadClient().didFinish(m_webContext.get(), this);
169
170    // This can cause the DownloadProxy object to be deleted.
171    m_downloadProxyMap.downloadFinished(this);
172}
173
174static PassRefPtr<WebData> createWebData(const CoreIPC::DataReference& data)
175{
176    if (data.isEmpty())
177        return 0;
178
179    return WebData::create(data.data(), data.size());
180}
181
182void DownloadProxy::didFail(const ResourceError& error, const CoreIPC::DataReference& resumeData)
183{
184    if (!m_webContext)
185        return;
186
187    m_resumeData = createWebData(resumeData);
188
189    m_webContext->downloadClient().didFail(m_webContext.get(), this, error);
190
191    // This can cause the DownloadProxy object to be deleted.
192    m_downloadProxyMap.downloadFinished(this);
193}
194
195void DownloadProxy::didCancel(const CoreIPC::DataReference& resumeData)
196{
197    m_resumeData = createWebData(resumeData);
198
199    m_webContext->downloadClient().didCancel(m_webContext.get(), this);
200
201    // This can cause the DownloadProxy object to be deleted.
202    m_downloadProxyMap.downloadFinished(this);
203}
204
205#if PLATFORM(QT)
206void DownloadProxy::startTransfer(const String& filename)
207{
208    if (!m_webContext)
209        return;
210
211    // FIXME (Multi-WebProcess): <rdar://problem/12239483> Downloads shouldn't be handled in the web process.
212    m_webContext->sendToAllProcesses(Messages::WebProcess::StartTransfer(m_downloadID, filename));
213}
214#endif
215
216} // namespace WebKit
217
218