2
* Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
3
* Copyright (C) 2010 Brent Fulgham <bfulgham@webkit.org>
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
14
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24
* THE POSSIBILITY OF SUCH DAMAGE.
30
#include "DataReference.h"
31
#include "DownloadSoupErrors.h"
32
#include <WebCore/NotImplemented.h>
33
#include <WebCore/ResourceHandleInternal.h>
35
#include <wtf/gobject/GOwnPtr.h>
36
#include <wtf/gobject/GRefPtr.h>
37
#include <wtf/text/CString.h>
40
#include <glib/gi18n-lib.h>
43
using namespace WebCore;
47
class DownloadClient : public ResourceHandleClient {
48
WTF_MAKE_NONCOPYABLE(DownloadClient);
50
DownloadClient(Download* download)
51
: m_download(download)
52
, m_handleResponseLaterID(0)
58
if (m_handleResponseLaterID)
59
g_source_remove(m_handleResponseLaterID);
62
void downloadFailed(const ResourceError& error)
64
m_download->didFail(error, CoreIPC::DataReference());
67
void didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
69
m_response = adoptGRef(response.toSoupMessage());
70
m_download->didReceiveResponse(response);
72
if (response.httpStatusCode() >= 400) {
73
downloadFailed(platformDownloadNetworkError(response.httpStatusCode(), response.url().string(), response.httpStatusText()));
77
String suggestedFilename = response.suggestedFilename();
78
if (suggestedFilename.isEmpty()) {
79
KURL url = response.url();
80
url.setQuery(String());
81
url.removeFragmentIdentifier();
82
suggestedFilename = decodeURLEscapeSequences(url.lastPathComponent());
86
String destinationURI = m_download->decideDestinationWithSuggestedFilename(suggestedFilename, overwrite);
87
if (destinationURI.isEmpty()) {
89
GOwnPtr<char> buffer(g_strdup_printf(_("Cannot determine destination URI for download with suggested filename %s"), suggestedFilename.utf8().data()));
90
String errorMessage = String::fromUTF8(buffer.get());
92
String errorMessage = makeString("Cannot determine destination URI for download with suggested filename ", suggestedFilename);
94
downloadFailed(platformDownloadDestinationError(response, errorMessage));
98
GRefPtr<GFile> file = adoptGRef(g_file_new_for_uri(destinationURI.utf8().data()));
99
GOwnPtr<GError> error;
100
m_outputStream = adoptGRef(g_file_replace(file.get(), 0, TRUE, G_FILE_CREATE_NONE, 0, &error.outPtr()));
101
if (!m_outputStream) {
102
downloadFailed(platformDownloadDestinationError(response, error->message));
106
GRefPtr<GFileInfo> info = adoptGRef(g_file_info_new());
107
g_file_info_set_attribute_string(info.get(), "metadata::download-uri", response.url().string().utf8().data());
108
g_file_set_attributes_async(file.get(), info.get(), G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, 0, 0, 0);
110
m_download->didCreateDestination(destinationURI);
113
void didReceiveData(ResourceHandle*, const char* data, int length, int /*encodedDataLength*/)
115
if (m_handleResponseLaterID) {
116
g_source_remove(m_handleResponseLaterID);
121
GOwnPtr<GError> error;
122
g_output_stream_write_all(G_OUTPUT_STREAM(m_outputStream.get()), data, length, &bytesWritten, 0, &error.outPtr());
124
downloadFailed(platformDownloadDestinationError(ResourceResponse(m_response.get()), error->message));
127
m_download->didReceiveData(bytesWritten);
130
void didFinishLoading(ResourceHandle*, double)
133
m_download->didFinish();
136
void didFail(ResourceHandle*, const ResourceError& error)
138
downloadFailed(platformDownloadNetworkError(error.errorCode(), error.failingURL(), error.localizedDescription()));
141
void wasBlocked(ResourceHandle*)
146
void cannotShowURL(ResourceHandle*)
151
void handleResponse()
153
m_handleResponseLaterID = 0;
154
didReceiveResponse(0, m_delayedResponse);
157
static gboolean handleResponseLaterCallback(DownloadClient* downloadClient)
159
downloadClient->handleResponse();
163
void handleResponseLater(const ResourceResponse& response)
166
ASSERT(!m_handleResponseLaterID);
168
m_delayedResponse = response;
170
// Call didReceiveResponse in an idle to make sure the download is added
171
// to the DownloadManager downloads map.
172
m_handleResponseLaterID = g_idle_add_full(G_PRIORITY_DEFAULT, reinterpret_cast<GSourceFunc>(handleResponseLaterCallback), this, 0);
175
Download* m_download;
176
GRefPtr<GFileOutputStream> m_outputStream;
177
GRefPtr<SoupMessage> m_response;
178
ResourceResponse m_delayedResponse;
179
unsigned m_handleResponseLaterID;
182
void Download::start(WebPage*)
184
ASSERT(!m_downloadClient);
185
ASSERT(!m_resourceHandle);
186
m_downloadClient = adoptPtr(new DownloadClient(this));
187
m_resourceHandle = ResourceHandle::create(0, m_request, m_downloadClient.get(), false, false);
191
void Download::startWithHandle(WebPage*, ResourceHandle* resourceHandle, const ResourceResponse& response)
193
ASSERT(!m_downloadClient);
194
ASSERT(!m_resourceHandle);
195
m_downloadClient = adoptPtr(new DownloadClient(this));
196
resourceHandle->setClient(m_downloadClient.get());
197
m_resourceHandle = resourceHandle;
199
static_cast<DownloadClient*>(m_downloadClient.get())->handleResponseLater(response);
202
void Download::cancel()
204
if (!m_resourceHandle)
206
m_resourceHandle->cancel();
207
didCancel(CoreIPC::DataReference());
208
m_resourceHandle = 0;
211
void Download::platformInvalidate()
213
if (m_resourceHandle) {
214
m_resourceHandle->setClient(0);
215
m_resourceHandle->cancel();
216
m_resourceHandle = 0;
218
m_downloadClient.release();
221
void Download::didDecideDestination(const String& /*destination*/, bool /*allowOverwrite*/)
226
void Download::platformDidFinish()
228
m_resourceHandle = 0;
231
void Download::receivedCredential(const AuthenticationChallenge&, const Credential&)
236
void Download::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&)
241
void Download::receivedCancellation(const AuthenticationChallenge&)
246
void Download::continueWithoutCredential(const AuthenticationChallenge &)
251
void Download::useCredential(const AuthenticationChallenge&, const Credential&)
256
void Download::cancelAuthenticationChallenge(const AuthenticationChallenge&)
261
} // namespace WebKit