KDOMLoader.cpp 12.7 KB
Newer Older
eseidel's avatar
eseidel committed
1
/*
eseidel's avatar
eseidel committed
2
    Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org>
eseidel's avatar
eseidel committed
3
                  2004, 2005 Rob Buis <buis@kde.org>
eseidel's avatar
eseidel committed
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

    Based on khtml code by:
    Copyright (C) 1998 Lars Knoll <knoll@kde.org>
    Copyright (C) 2001-2003 Dirk Mueller <mueller@kde.org>
    Copyright (C) 2003 Apple Computer, Inc

    This file is part of the KDE project

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <kdebug.h>
#ifndef APPLE_CHANGES
#include <kio/scheduler.h>
#endif

eseidel's avatar
eseidel committed
33
#include <kdom/core/DocumentImpl.h>
eseidel's avatar
eseidel committed
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

#include "KDOMCache.h"
#include "KDOMLoader.moc"
#include "KDOMCacheHelper.h"
#include "KDOMCachedImage.h"
#include "KDOMCachedScript.h"
#include "KDOMCachedDocument.h"
#include "KDOMCachedStyleSheet.h"

#define KDOM_CACHE_MAX_JOB_COUNT 32

using namespace KDOM;
    
DocumentLoader::DocumentLoader(KDOMPart *part, DocumentImpl *docImpl)
{
eseidel's avatar
eseidel committed
49
50
51
52
53
54
55
56
    m_part = part;
    m_doc = docImpl;
    m_expireDate = 0;
    m_creationDate = time(0);
    m_autoloadImages = true;
    m_cachePolicy = KIO::CC_Verify;
    
    Cache::s_docLoaderList->append(this);
eseidel's avatar
eseidel committed
57
58
59
60
}

DocumentLoader::~DocumentLoader()
{
eseidel's avatar
eseidel committed
61
62
    Cache::loader()->cancelRequests(this);
    Cache::s_docLoaderList->remove(this);
eseidel's avatar
eseidel committed
63
64
65
66
67
}

CachedImage *DocumentLoader::requestImage(const KURL &url)
{
#ifndef APPLE_COMPILE_HACK
eseidel's avatar
eseidel committed
68
69
    // TODO: Add security checks (see khtml DocLoader!)
    CachedImage *img = Cache::requestObject<CachedImage, CachedObject::Image>(this, url, 0);
eseidel's avatar
eseidel committed
70

eseidel's avatar
eseidel committed
71
72
    if(img && img->status() == CachedObject::Unknown && autoloadImages())
        Cache::loader()->load(this, img, true);
eseidel's avatar
eseidel committed
73

eseidel's avatar
eseidel committed
74
    return img;
eseidel's avatar
eseidel committed
75
#else
eseidel's avatar
eseidel committed
76
77
    // FIXME: this is just a hack to make compile...
    return NULL;
eseidel's avatar
eseidel committed
78
79
80
81
#endif
}

CachedStyleSheet *DocumentLoader::requestStyleSheet(const KURL &url, const QString &charset,
eseidel's avatar
eseidel committed
82
                                                    const char *accept, bool /* userSheet */)
eseidel's avatar
eseidel committed
83
{
eseidel's avatar
eseidel committed
84
85
86
87
    // TODO: Add security checks (see khtml DocLoader!)
    CachedStyleSheet *s = Cache::requestObject<CachedStyleSheet, CachedObject::StyleSheet>(this, url, accept);
    if(s && !charset.isEmpty())
        s->setCharset(charset);
eseidel's avatar
eseidel committed
88

eseidel's avatar
eseidel committed
89
    return s;
eseidel's avatar
eseidel committed
90
91
92
}

CachedDocument *DocumentLoader::requestDocument(const KURL &url, const QString& charset,
eseidel's avatar
eseidel committed
93
                                                const char* accept)
eseidel's avatar
eseidel committed
94
{
eseidel's avatar
eseidel committed
95
96
97
98
    // TODO: Add security checks (see khtml DocLoader!)
    CachedDocument *doc = Cache::requestObject<CachedDocument, CachedObject::TextDocument>(this, url, accept);
    if(doc && !charset.isEmpty())
        doc->setCharset(charset);
eseidel's avatar
eseidel committed
99

eseidel's avatar
eseidel committed
100
    return doc;
eseidel's avatar
eseidel committed
101
102
103
104
}

CachedScript *DocumentLoader::requestScript(const KURL &url, const QString &charset)
{
eseidel's avatar
eseidel committed
105
106
107
108
    // TODO: Add security checks (see khtml DocLoader!)
    CachedScript *script = Cache::requestObject<CachedScript, CachedObject::Script>(this, url, 0);
    if(script && !charset.isEmpty())
        script->setCharset(charset);
eseidel's avatar
eseidel committed
109

eseidel's avatar
eseidel committed
110
    return script;
eseidel's avatar
eseidel committed
111
112
113
114
}

void DocumentLoader::setCacheCreationDate(time_t date)
{
eseidel's avatar
eseidel committed
115
116
117
118
    if(date)
        m_creationDate = date;
    else
        m_creationDate = time(0); // now
eseidel's avatar
eseidel committed
119
120
121
122
}

void DocumentLoader::setExpireDate(time_t date, bool relative)
{
eseidel's avatar
eseidel committed
123
124
125
126
    if(relative)
        m_expireDate = date + m_creationDate; // Relative date
    else
        m_expireDate = date; // Absolute date
eseidel's avatar
eseidel committed
127
128

#ifdef CACHE_DEBUG
eseidel's avatar
eseidel committed
129
    kdDebug() << "[DocumentLoader] " << m_expireDate - time(0) << " seconds left until reload required.\n";
eseidel's avatar
eseidel committed
130
131
132
133
134
#endif
}

void DocumentLoader::setAutoloadImages(bool load)
{
eseidel's avatar
eseidel committed
135
136
137
138
139
140
141
    if(load == m_autoloadImages)
        return;

    m_autoloadImages = load;
    if(!m_autoloadImages)
        return;

eseidel's avatar
eseidel committed
142
#if 0
eseidel's avatar
eseidel committed
143
    for(Q3PtrDictIterator<CachedObject> it(m_docObjects); it.current(); ++it)
eseidel's avatar
eseidel committed
144
145
146
147
148
149
150
151
152
153
154
    {
        if(it.current()->type() == CachedObject::Image)
        {
            CachedImage *img = const_cast<CachedImage*>( static_cast<const CachedImage *>(it.current()));

            CachedObject::Status status = img->status();
            if(status != CachedObject::Unknown)
                continue;
            Cache::loader()->load(this, img, true);
        }
    }
eseidel's avatar
eseidel committed
155
#endif
eseidel's avatar
eseidel committed
156
157
}

eseidel's avatar
eseidel committed
158
void DocumentLoader::setShowAnimations(KDOMSettings::KAnimationAdvice showAnimations)
eseidel's avatar
eseidel committed
159
{
eseidel's avatar
eseidel committed
160
161
    if(showAnimations == m_showAnimations)
        return;
eseidel's avatar
eseidel committed
162

eseidel's avatar
eseidel committed
163
    m_showAnimations = showAnimations;
eseidel's avatar
eseidel committed
164
165

#ifndef APPLE_COMPILE_HACK
eseidel's avatar
eseidel committed
166
    for(Q3PtrDictIterator<CachedObject> it(m_docObjects); it.current(); ++it)
eseidel's avatar
eseidel committed
167
168
169
170
171
172
173
    {
        if(it.current()->type() == CachedObject::Image)
        {
            CachedImage *img = const_cast<CachedImage *>(static_cast<const CachedImage *>(it.current()));
            img->setShowAnimations( m_showAnimations );
        }
    }
eseidel's avatar
eseidel committed
174
175
176
177
178
#endif
}

void DocumentLoader::insertCachedObject(CachedObject *object) const
{
eseidel's avatar
eseidel committed
179
180
    if(m_docObjects.find(object))
        return;
eseidel's avatar
eseidel committed
181

eseidel's avatar
eseidel committed
182
183
    m_docObjects.insert(object, object);
    
eseidel's avatar
eseidel committed
184
#ifndef APPLE_CHANGES
eseidel's avatar
eseidel committed
185
186
    if(m_docObjects.count() > 3 * m_docObjects.size())
        m_docObjects.resize(cacheNextSeed(m_docObjects.size()));
eseidel's avatar
eseidel committed
187
188
189
190
191
#endif
}

void DocumentLoader::removeCachedObject(CachedObject *object) const
{
eseidel's avatar
eseidel committed
192
    m_docObjects.remove(object);
eseidel's avatar
eseidel committed
193
194
195
196
}

bool DocumentLoader::needReload(const KURL &fullUrl)
{
eseidel's avatar
eseidel committed
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
    bool reload = false;
    if(m_cachePolicy == KIO::CC_Verify)
    {
        if(!m_reloadedURLs.contains(fullUrl.url()))
        {
            CachedObject *existing = Cache::s_objectDict->find(fullUrl.url());
            if(existing && existing->isExpired())
            {
                Cache::removeCacheEntry(existing);
                m_reloadedURLs.append(fullUrl.url());
                reload = true;
            }
        }
    }
    else if((m_cachePolicy == KIO::CC_Reload) || (m_cachePolicy == KIO::CC_Refresh))
    {
        if(!m_reloadedURLs.contains(fullUrl.url()))
        {
            CachedObject *existing = Cache::s_objectDict->find(fullUrl.url());
            if(existing)
                Cache::removeCacheEntry(existing);
            
            m_reloadedURLs.append(fullUrl.url());
            reload = true;
        }
    }

    return reload;
eseidel's avatar
eseidel committed
225
226
227
228
}

bool DocumentLoader::hasPending(CachedObject::Type type) const
{
eseidel's avatar
eseidel committed
229
    return Cache::hasPending(type);
eseidel's avatar
eseidel committed
230
231
232
233
}

KURL DocumentLoader::referrer() const
{
eseidel's avatar
eseidel committed
234
235
236
237
    if(m_doc)
        return m_doc->documentKURI();
    else
        return uri;
eseidel's avatar
eseidel committed
238
239
240
241
242

}

Loader::Loader() : QObject()
#ifdef APPLE_CHANGES
eseidel's avatar
eseidel committed
243
    , _requestStarted(this, SIGNAL(requestStarted(KDOM::DocumentLoader *, KDOM::CachedObject *)))
eseidel's avatar
eseidel committed
244
245
246
247
    , _requestDone(this, SIGNAL(requestDone(KDOM::DocumentLoader *, KDOM::CachedObject *)))
    , _requestFailed(this, SIGNAL(requestFailed(KDOM::DocumentLoader *, KDOM::CachedObject *)))
#endif
{
eseidel's avatar
eseidel committed
248
249
250
    m_requestsPending.setAutoDelete(true);
    m_requestsLoading.setAutoDelete(true);
    
eseidel's avatar
eseidel committed
251
#ifndef APPLE_CHANGES
eseidel's avatar
eseidel committed
252
    connect(&m_timer, SIGNAL(timeout()), this, SLOT( servePendingRequests()));
eseidel's avatar
eseidel committed
253
254
255
256
257
#endif
}

void Loader::load(DocumentLoader *docLoader, CachedObject *object, bool incremental)
{
eseidel's avatar
eseidel committed
258
259
    Request *req = new Request(docLoader, object, incremental);
    m_requestsPending.append(req);
eseidel's avatar
eseidel committed
260

eseidel's avatar
eseidel committed
261
    emit requestStarted(req->docLoader, req->object);
eseidel's avatar
eseidel committed
262

eseidel's avatar
eseidel committed
263
    m_timer.start(0, true);
eseidel's avatar
eseidel committed
264
265
266
267
}

int Loader::numRequests(DocumentLoader *docLoader) const
{
eseidel's avatar
eseidel committed
268
269
    int res = 0;

eseidel's avatar
eseidel committed
270
    Q3PtrListIterator<Request> pIt(m_requestsPending);
eseidel's avatar
eseidel committed
271
272
273
274
275
276
    for(; pIt.current(); ++pIt)
    {
        if(pIt.current()->docLoader == docLoader)
            res++;
    }

eseidel's avatar
eseidel committed
277
    Q3PtrDictIterator<Request> lIt(m_requestsLoading);
eseidel's avatar
eseidel committed
278
279
280
281
282
283
284
    for (; lIt.current(); ++lIt)
    {
        if(lIt.current()->docLoader == docLoader)
            res++;
    }

    return res;
eseidel's avatar
eseidel committed
285
286
287
288
}

void Loader::cancelRequests(DocumentLoader *docLoader)
{
eseidel's avatar
eseidel committed
289
    Q3PtrListIterator<Request> pIt(m_requestsPending);
eseidel's avatar
eseidel committed
290
291
292
293
294
295
296
297
298
299
300
301
302
    while(pIt.current())
    {
        if(pIt.current()->docLoader == docLoader)
        {
            kdDebug() << "canceling pending request for " << pIt.current()->object->url().string() << endl;
            
            Cache::removeCacheEntry(pIt.current()->object);
            m_requestsPending.remove(pIt);
        }
        else
            ++pIt;
    }

eseidel's avatar
eseidel committed
303
    Q3PtrDictIterator<Request> lIt( m_requestsLoading );
eseidel's avatar
eseidel committed
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
    while(lIt.current())
    {
        if(lIt.current()->docLoader == docLoader)
        {
            // kdDebug( 6060 ) << "canceling loading request for " << lIt.current()->object->url().string() << endl;
            
            KIO::Job *job = static_cast<KIO::Job *>(lIt.currentKey());
            Cache::removeCacheEntry(lIt.current()->object);
            m_requestsLoading.remove(lIt.currentKey());
            job->kill();
            
            // emit requestFailed(docLoader, pIt.current()->object);
        }
        else
            ++lIt;
    }
eseidel's avatar
eseidel committed
320
321
322
323
}

KIO::Job *Loader::jobForRequest(const DOMString &url) const
{
eseidel's avatar
eseidel committed
324
    Q3PtrDictIterator<Request> it(m_requestsLoading);
eseidel's avatar
eseidel committed
325
326
327
    for (; it.current(); ++it)
    {
        CachedObject *obj = it.current()->object;
eseidel's avatar
eseidel committed
328

eseidel's avatar
eseidel committed
329
330
331
        if(obj && obj->url() == url)
            return static_cast<KIO::Job *>(it.currentKey());
    }
eseidel's avatar
eseidel committed
332

eseidel's avatar
eseidel committed
333
    return 0;
eseidel's avatar
eseidel committed
334
335
336
337
}

void Loader::slotFinished(KIO::Job *job)
{
eseidel's avatar
eseidel committed
338
339
    Request *r = m_requestsLoading.take(job);
    KIO::TransferJob *j = static_cast<KIO::TransferJob *>(job);
eseidel's avatar
eseidel committed
340

eseidel's avatar
eseidel committed
341
342
    if(!r)
        return;
eseidel's avatar
eseidel committed
343

eseidel's avatar
eseidel committed
344
345
    if(j->error() || j->isErrorPage())
    {
eseidel's avatar
eseidel committed
346
#ifdef LOADER_DEBUG
eseidel's avatar
eseidel committed
347
        kdDebug() << "Loader::slotFinished, with error. job->error() = " << j->error() << " job->isErrorPage() = " << j->isErrorPage() << endl;
eseidel's avatar
eseidel committed
348
349
#endif

eseidel's avatar
eseidel committed
350
351
352
353
354
355
356
        r->object->error(job->error(), job->errorText().ascii());
        emit requestFailed(r->docLoader, r->object);
    }
    else
    {
        r->object->data(r->buffer, true);
        emit requestDone(r->docLoader, r->object);
eseidel's avatar
eseidel committed
357

eseidel's avatar
eseidel committed
358
        time_t expireDate = j->queryMetaData(QString::fromLatin1("expire-date")).toInt();
eseidel's avatar
eseidel committed
359
360

#ifdef LOADER_DEBUG
eseidel's avatar
eseidel committed
361
        kdDebug() << "Loader::slotFinished, url = " << j->url().url() << endl;
eseidel's avatar
eseidel committed
362
363
#endif

eseidel's avatar
eseidel committed
364
365
        r->object->setExpireDate( expireDate );
    }
eseidel's avatar
eseidel committed
366

eseidel's avatar
eseidel committed
367
    r->object->finish();
eseidel's avatar
eseidel committed
368
369

#ifdef LOADER_DEBUG
eseidel's avatar
eseidel committed
370
    kdDebug() << "Loader:: JOB FINISHED " << r->object << ": " << r->object->url().string() << endl;
eseidel's avatar
eseidel committed
371
372
#endif

eseidel's avatar
eseidel committed
373
    delete r;
eseidel's avatar
eseidel committed
374

eseidel's avatar
eseidel committed
375
376
    if((m_requestsPending.count() != 0) && (m_requestsLoading.count() < KDOM_CACHE_MAX_JOB_COUNT / 2))
        m_timer.start(0, true);
eseidel's avatar
eseidel committed
377
378
379
380
}

void Loader::slotData(KIO::Job *job, const QByteArray &buffer)
{
eseidel's avatar
eseidel committed
381
382
383
384
385
386
    Request *r = m_requestsLoading[job];
    if(!r)
    {
        kdDebug() << "[Loader::slotData] got data for unknown request!" << endl;
        return;
    }
eseidel's avatar
eseidel committed
387

eseidel's avatar
eseidel committed
388
389
    if(!r->buffer.isOpen())
        r->buffer.open(IO_WriteOnly);
eseidel's avatar
eseidel committed
390

eseidel's avatar
eseidel committed
391
    r->buffer.writeBlock(buffer.data(), buffer.size());
eseidel's avatar
eseidel committed
392

eseidel's avatar
eseidel committed
393
394
    if(r->incremental)
        r->object->data(r->buffer, false);
eseidel's avatar
eseidel committed
395
396
397
398
}

void Loader::servePendingRequests()
{
eseidel's avatar
eseidel committed
399
400
401
402
    while((m_requestsPending.count() != 0) && (m_requestsLoading.count() < KDOM_CACHE_MAX_JOB_COUNT))
    {
        // get the first pending request
        Request *req = m_requestsPending.take(0);
eseidel's avatar
eseidel committed
403
404

#ifdef LOADER_DEBUG
eseidel's avatar
eseidel committed
405
        kdDebug() << "[Loader::servePendingRequests] url = " << req->object->url().string() << endl;
eseidel's avatar
eseidel committed
406
407
#endif

eseidel's avatar
eseidel committed
408
409
        KURL u(req->object->url().string());
        KIO::TransferJob* job = KIO::get(u, false, false /*no GUI*/);
eseidel's avatar
eseidel committed
410

eseidel's avatar
eseidel committed
411
        job->addMetaData(QString::fromLatin1("cache"), KIO::getCacheControlString(req->object->cachePolicy()));
eseidel's avatar
eseidel committed
412

eseidel's avatar
eseidel committed
413
414
        if(!req->object->accept().isEmpty())
            job->addMetaData(QString::fromLatin1("accept"), req->object->accept());
eseidel's avatar
eseidel committed
415

eseidel's avatar
eseidel committed
416
417
        if(!req->object->acceptLanguage().isEmpty())
            job->addMetaData(QString::fromLatin1("Languages"), req->object->acceptLanguage());
eseidel's avatar
eseidel committed
418

eseidel's avatar
eseidel committed
419
420
        if(req->docLoader)
            job->addMetaData(QString::fromLatin1("referrer"), req->docLoader->referrer().url());
eseidel's avatar
eseidel committed
421

eseidel's avatar
eseidel committed
422
423
        connect(job, SIGNAL(result(KIO::Job *)), this, SLOT(slotFinished(KIO::Job *)));
        connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)), SLOT(slotData(KIO::Job *, const QByteArray &)));
eseidel's avatar
eseidel committed
424
425

#ifndef APPLE_COMPILE_HACK
eseidel's avatar
eseidel committed
426
427
        if(req->object->schedule())
            KIO::Scheduler::scheduleJob(job);
eseidel's avatar
eseidel committed
428
429
#endif

eseidel's avatar
eseidel committed
430
431
        m_requestsLoading.insert(job, req);
    }
eseidel's avatar
eseidel committed
432
433
434
435
436
}


#ifdef APPLE_CHANGES
void Loader::requestStarted(DocumentLoader *l, CachedObject *o) {
eseidel's avatar
eseidel committed
437
438
    //_requestStarted.call(l, o);
    fprintf(stderr, "requestStarted()");
eseidel's avatar
eseidel committed
439
440
441
}

void Loader::requestDone(DocumentLoader *l, CachedObject *o) {
eseidel's avatar
eseidel committed
442
443
    //_requestDone.call(l, o);
    fprintf(stderr, "requestDone()");
eseidel's avatar
eseidel committed
444
445
446
}

void Loader::requestFailed(DocumentLoader *l, CachedObject *o) {
eseidel's avatar
eseidel committed
447
448
    //_requestFailed.call(l, o);
    fprintf(stderr, "requestFailed()");
eseidel's avatar
eseidel committed
449
450
451
452
453
454
}
#endif


void DocumentLoader::setReferrer(const KURL& u)
{
eseidel's avatar
eseidel committed
455
    uri = u;
eseidel's avatar
eseidel committed
456
457
458
}

// vim:ts=4:noet