Reviewed by Maciej, landed by Anders
[WebKit-https.git] / WebCore / platform / network / qt / ResourceHandleManager.cpp
1 /*
2  * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28 #include "config.h"
29
30 #if PLATFORM(KDE)
31 #include <kio/job.h>
32 #endif
33
34 #include <QEvent>
35 #include <QFile>
36
37 #include "FrameQt.h"
38 #include "ResourceHandleManager.h"
39 #include "ResourceHandleInternal.h"
40
41 namespace WebCore {
42
43 static ResourceHandleManager* s_self = 0;
44
45 #if PLATFORM(KDE)
46
47 ResourceHandleManager::ResourceHandleManager()
48     : m_jobToKioMap()
49     , m_kioToJobMap()
50     , m_frameClient(0)
51 {
52 }
53
54 ResourceHandleManager::~ResourceHandleManager()
55 {
56 }
57
58 ResourceHandleManager* ResourceHandleManager::self()
59 {
60     if (!s_self)
61         s_self = new ResourceHandleManager();
62
63     return s_self;
64 }
65
66 void ResourceHandleManager::slotData(KIO::Job* kioJob, const QByteArray& data)
67 {
68     ResourceHandle* job = 0;
69
70     // Check if we know about 'kioJob'...
71     QMap<KIO::Job*, ResourceHandle*>::const_iterator it = m_kioToJobMap.find(kioJob);
72     if (it != m_kioToJobMap.end())
73         job = it.value();
74
75     if (!job)
76         return;
77
78     ResourceHandleInternal* d = job->getInternal();
79     if (!d || !d->m_client)
80         return;
81
82     d->m_client->didReceiveData(job, data.data(), data.size());
83 }
84
85 void ResourceHandleManager::slotMimetype(KIO::Job* kioJob, const QString& type)
86 {
87     ResourceHandle* job = 0;
88
89     // Check if we know about 'kioJob'...
90     QMap<KIO::Job*, ResourceHandle*>::const_iterator it = m_kioToJobMap.find(kioJob);
91     if (it != m_kioToJobMap.end())
92         job = it.value();
93
94     if (!job)
95         return;
96
97     ResourceHandleInternal* d = job->getInternal();
98     if (!d || !d->m_client)
99         return;
100
101     d->m_mimetype = type;
102 }
103
104 void ResourceHandleManager::slotResult(KJob* kjob)
105 {
106     KIO::Job* kioJob = qobject_cast<KIO::Job*>(kjob);
107     if (!kioJob)
108         return;
109
110     ResourceHandle* job = 0;
111
112     // Check if we know about 'kioJob'...
113     QMap<KIO::Job*, ResourceHandle*>::const_iterator it = m_kioToJobMap.find(kioJob);
114     if (it != m_kioToJobMap.end())
115         job = it.value();
116
117     if (!job)
118         return;
119
120     job->setError(kjob->error());
121     remove(job);
122
123     ASSERT(m_frameClient);
124     m_frameClient->checkLoaded();
125 }
126
127 void ResourceHandleManager::remove(ResourceHandle* job)
128 {
129     ResourceHandleInternal* d = job->getInternal();
130     if (!d || !d->m_client)
131         return;
132
133     KIO::Job* kioJob = 0;
134
135     // Check if we know about 'job'...
136     QMap<ResourceHandle*, KIO::Job*>::const_iterator it = m_jobToKioMap.find(job);
137     if (it != m_jobToKioMap.end())
138         kioJob = it.value();
139
140     if (!kioJob)
141         return;
142
143     QString headers = kioJob->queryMetaData("HTTP-Headers");
144     if (job->method() == "GET")
145         d->m_charset = job->extractCharsetFromHeaders(headers);
146     else if (job->method() == "POST") {
147         // Will take care of informing our client...
148         // This must be called before didFinishLoading(),
149         // otherwhise assembleResponseHeaders() is called too early...
150         RefPtr<PlatformResponseQt> response(new PlatformResponseQt());
151         response->data = headers;    
152         response->url = job->url().url();
153
154         job->receivedResponse(response);
155     }
156
157     d->m_client->receivedAllData(job, 0);
158     d->m_client->didFinishLoading(job);
159
160     m_jobToKioMap.remove(job);
161     m_kioToJobMap.remove(kioJob);
162 }
163
164 void ResourceHandleManager::add(ResourceHandle* job, FrameQtClient* frameClient)
165 {
166     ResourceHandleInternal* d = job->getInternal();
167     DeprecatedString url = d->m_request.url().url();
168
169     KIO::Job* kioJob = 0;
170
171     if (job->method() == "POST") {
172         DeprecatedString postData = job->postData().flattenToString().deprecatedString();
173         QByteArray postDataArray(postData.ascii(), postData.length());
174
175         kioJob = KIO::http_post(KUrl(url), postDataArray, false);
176         kioJob->addMetaData("PropagateHttpHeader", "true");
177         kioJob->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded");
178     } else
179         kioJob = KIO::get(KUrl(url), false, false);
180
181     Q_ASSERT(kioJob != 0);
182
183     QObject::connect(kioJob, SIGNAL(data(KIO::Job*, const QByteArray&)), this, SLOT(slotData(KIO::Job*, const QByteArray&)));
184     QObject::connect(kioJob, SIGNAL(mimetype(KIO::Job*, const QString&)), this, SLOT(slotMimetype(KIO::Job*, const QString&)));
185     QObject::connect(kioJob, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*)));
186
187     m_jobToKioMap.insert(job, kioJob);
188     m_kioToJobMap.insert(kioJob, job);
189
190     if (!m_frameClient)
191         m_frameClient = frameClient;
192     else
193         ASSERT(m_frameClient == frameClient);
194 }
195
196 void ResourceHandleManager::cancel(ResourceHandle* job)
197 {
198     remove(job);
199     job->setError(1);
200 }
201
202 #else
203 // Qt Resource Handle Manager
204
205 QtJob::QtJob(const QString& path)
206     : m_path(path)
207 {
208     startTimer(0);
209 }
210
211 void QtJob::timerEvent(QTimerEvent* e)
212 {
213     killTimer(e->timerId());
214
215     QFile f(m_path);
216     QByteArray data;
217     if (f.open(QIODevice::ReadOnly)) {
218         data = f.readAll();
219         f.close();
220     };
221
222     emit finished(this, data);
223
224     deleteLater();
225 }
226
227 ResourceHandleManager::ResourceHandleManager()
228     : m_frameClient(0)
229 {
230 }
231
232 ResourceHandleManager::~ResourceHandleManager()
233 {
234 }
235
236 ResourceHandleManager* ResourceHandleManager::self()
237 {
238     if (!s_self)
239         s_self = new ResourceHandleManager();
240
241     return s_self;
242 }
243
244 void ResourceHandleManager::remove(ResourceHandle* job)
245 {
246     ResourceHandleInternal* d = job->getInternal();
247     if (!d || !d->m_client)
248         return;
249
250     // Check if we know about 'job'...
251     QtJob *qtJob = m_resourceToJob.value(job);
252     if (!qtJob)
253         return;
254
255     d->m_client->receivedAllData(job, 0);
256     d->m_client->didFinishLoading(job);
257
258     m_resourceToJob.remove(job);
259     m_jobToResource.remove(qtJob);
260 }
261
262 void ResourceHandleManager::add(ResourceHandle* resource, FrameQtClient* frameClient)
263 {
264     ResourceHandleInternal* d = resource->getInternal();
265
266     if (resource->method() == "POST"
267         || !d->m_request.url().isLocalFile()) {
268         // ### not supported for the local filesystem
269         return;
270     }
271     QtJob* qtJob =  new QtJob(d->m_request.url().path());
272     connect(qtJob, SIGNAL(finished(QtJob *, const QByteArray &)),
273             this, SLOT(deliverJobData(QtJob *, const QByteArray &)));
274
275     m_resourceToJob.insert(resource, qtJob);
276     m_jobToResource.insert(qtJob, resource);
277
278     if (!m_frameClient)
279         m_frameClient = frameClient;
280     else
281         ASSERT(m_frameClient == frameClient);
282 }
283
284 void ResourceHandleManager::cancel(ResourceHandle* job)
285 {
286     remove(job);
287     job->setError(1);
288 }
289
290 void ResourceHandleManager::deliverJobData(QtJob* job, const QByteArray& data)
291 {
292     ResourceHandle* handle = m_jobToResource.value(job);
293     if (!handle)
294         return;
295
296     ResourceHandleInternal* d = handle->getInternal();
297     if (!d || !d->m_client)
298         return;
299
300     d->m_client->didReceiveData(handle, data.data(), data.size());
301
302     handle->setError(0);
303     remove(handle);
304
305     ASSERT(m_frameClient);
306     m_frameClient->checkLoaded();
307 }
308
309 #endif
310
311 } // namespace WebCore
312
313 #include "ResourceHandleManager.moc"