2006-10-07 Anders Carlsson <acarlsson@apple.com>
[WebKit-https.git] / WebCore / loader / loader.cpp
1 /*
2     This file is part of the KDE libraries
3
4     Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
5     Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
6     Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
7     Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
8     Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
9
10     This library is free software; you can redistribute it and/or
11     modify it under the terms of the GNU Library General Public
12     License as published by the Free Software Foundation; either
13     version 2 of the License, or (at your option) any later version.
14
15     This library is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18     Library General Public License for more details.
19
20     You should have received a copy of the GNU Library General Public License
21     along with this library; see the file COPYING.LIB.  If not, write to
22     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23     Boston, MA 02111-1307, USA.
24
25     This class provides all functionality needed for loading images, style sheets and html
26     pages from the web. It has a memory cache for these objects.
27 */
28
29 #include "config.h"
30 #include "loader.h"
31
32 #include "Cache.h"
33 #include "CachedImage.h"
34 #include "CachedResource.h"
35 #include "DeprecatedStringList.h"
36 #include "DocLoader.h"
37 #include "Frame.h"
38 #include "HTMLDocument.h"
39 #include "LoaderFunctions.h"
40 #include "Request.h"
41 #include "ResourceLoader.h"
42 #include <wtf/Assertions.h>
43 #include <wtf/Vector.h>
44
45 namespace WebCore {
46
47 Loader::Loader()
48 {
49     m_requestsPending.setAutoDelete(true);
50 }
51
52 Loader::~Loader()
53 {
54     deleteAllValues(m_requestsLoading);
55 }
56
57 void Loader::load(DocLoader* dl, CachedResource* object, bool incremental)
58 {
59     Request* req = new Request(dl, object, incremental);
60     m_requestsPending.append(req);
61     servePendingRequests();
62 }
63
64 void Loader::servePendingRequests()
65 {
66     if (m_requestsPending.count() == 0)
67         return;
68
69     // get the first pending request
70     Request* req = m_requestsPending.take(0);
71
72     KURL u(req->cachedObject()->url().deprecatedString());
73     RefPtr<ResourceLoader> loader = ResourceLoader::create(this, "GET", u);
74
75     if (!req->cachedObject()->accept().isEmpty())
76         loader->addMetaData("accept", req->cachedObject()->accept());
77     if (req->docLoader())  {
78         KURL r = req->docLoader()->doc()->URL();
79         if (r.protocol().startsWith("http") && r.path().isEmpty())
80             r.setPath("/");
81         loader->addMetaData("referrer", r.url());
82         DeprecatedString domain = r.host();
83         if (req->docLoader()->doc()->isHTMLDocument())
84             domain = static_cast<HTMLDocument*>(req->docLoader()->doc())->domain().deprecatedString();
85     }
86
87     if (loader->start(req->docLoader()))
88         m_requestsLoading.add(loader.get(), req);
89 }
90
91 void Loader::receivedAllData(ResourceLoader* job, PlatformData allData)
92 {
93     RequestMap::iterator i = m_requestsLoading.find(job);
94     if (i == m_requestsLoading.end())
95         return;
96
97     Request* req = i->second;
98     m_requestsLoading.remove(i);
99
100     CachedResource* object = req->cachedObject();
101     DocLoader* docLoader = req->docLoader();
102
103     if (job->error() || job->isErrorPage()) {
104         docLoader->setLoadInProgress(true);
105         object->error();
106         docLoader->setLoadInProgress(false);
107         Cache::remove(object);
108     } else {
109         docLoader->setLoadInProgress(true);
110         object->data(req->buffer(), true);
111 #if PLATFORM(MAC)
112         object->setAllData(allData);
113 #endif
114         docLoader->setLoadInProgress(false);
115         object->finish();
116     }
117
118     delete req;
119
120     servePendingRequests();
121 }
122
123 void Loader::receivedResponse(ResourceLoader* job, PlatformResponse response)
124 {
125 #ifdef __APPLE__
126     Request* req = m_requestsLoading.get(job);
127     ASSERT(req);
128     ASSERT(response);
129     req->cachedObject()->setResponse(response);
130     req->cachedObject()->setExpireDate(CacheObjectExpiresTime(req->docLoader(), response), false);
131     
132     DeprecatedString chs = job->queryMetaData("charset").deprecatedString();
133     if (!chs.isNull())
134         req->cachedObject()->setCharset(chs);
135     
136     if (req->isMultipart()) {
137         ASSERT(req->cachedObject()->isImage());
138         static_cast<CachedImage*>(req->cachedObject())->clear();
139         if (req->docLoader()->frame())
140             req->docLoader()->frame()->checkCompleted();
141     } else if (ResponseIsMultipart(response)) {
142         req->setIsMultipart(true);
143         if (!req->cachedObject()->isImage())
144             job->cancel();
145     }
146 #endif
147 }
148
149 void Loader::receivedData(ResourceLoader* job, const char* data, int size)
150 {
151     Request* request = m_requestsLoading.get(job);
152     if (!request)
153         return;
154
155     CachedResource* object = request->cachedObject();    
156     Vector<char>& buffer = object->bufferData(data, size, request);
157
158     // Set the data.
159     if (request->isMultipart())
160         // The loader delivers the data in a multipart section all at once, send eof.
161         object->data(buffer, true);
162     else if (request->isIncremental())
163         object->data(buffer, false);
164 }
165
166 int Loader::numRequests(DocLoader* dl) const
167 {
168     // FIXME: Maybe we should keep a collection of requests by DocLoader, so we can do this instantly.
169
170     int res = 0;
171
172     DeprecatedPtrListIterator<Request> pIt(m_requestsPending);
173     for (; pIt.current(); ++pIt) {
174         if (pIt.current()->docLoader() == dl)
175             res++;
176     }
177
178     RequestMap::const_iterator end = m_requestsLoading.end();
179     for (RequestMap::const_iterator i = m_requestsLoading.begin(); !(i == end); ++i) {
180         Request* r = i->second;
181         res += (r->docLoader() == dl && !r->isMultipart());
182     }
183
184     DeprecatedPtrListIterator<Request> bdIt(m_requestsBackgroundDecoding);
185     for (; bdIt.current(); ++bdIt)
186         if (bdIt.current()->docLoader() == dl)
187             res++;
188
189     if (dl->loadInProgress())
190         res++;
191
192     return res;
193 }
194
195 void Loader::cancelRequests(DocLoader* dl)
196 {
197     DeprecatedPtrListIterator<Request> pIt(m_requestsPending);
198     while (pIt.current()) {
199         if (pIt.current()->docLoader() == dl) {
200             Cache::remove(pIt.current()->cachedObject());
201             m_requestsPending.remove(pIt);
202         } else
203             ++pIt;
204     }
205
206     Vector<ResourceLoader*, 256> jobsToCancel;
207
208     RequestMap::iterator end = m_requestsLoading.end();
209     for (RequestMap::iterator i = m_requestsLoading.begin(); i != end; ++i) {
210         Request* r = i->second;
211         if (r->docLoader() == dl)
212             jobsToCancel.append(i->first);
213     }
214
215     for (unsigned i = 0; i < jobsToCancel.size(); ++i) {
216         ResourceLoader* job = jobsToCancel[i];
217         Request* r = m_requestsLoading.get(job);
218         m_requestsLoading.remove(job);
219         Cache::remove(r->cachedObject());
220         job->kill();
221     }
222
223     DeprecatedPtrListIterator<Request> bdIt(m_requestsBackgroundDecoding);
224     while (bdIt.current()) {
225         if (bdIt.current()->docLoader() == dl) {
226             Cache::remove(bdIt.current()->cachedObject());
227             m_requestsBackgroundDecoding.remove(bdIt);
228         } else
229             ++bdIt;
230     }
231 }
232
233 void Loader::removeBackgroundDecodingRequest(Request* r)
234 {
235     if (m_requestsBackgroundDecoding.containsRef(r))
236         m_requestsBackgroundDecoding.remove(r);
237 }
238
239 ResourceLoader* Loader::jobForRequest(const String& URL) const
240 {
241     RequestMap::const_iterator end = m_requestsLoading.end();
242     for (RequestMap::const_iterator i = m_requestsLoading.begin(); i != end; ++i) {
243         CachedResource* obj = i->second->cachedObject();
244         if (obj && obj->url() == URL)
245             return i->first;
246     }
247     return 0;
248 }
249
250 } //namespace WebCore