Reviewed by Oliver.
[webkit/qt.git] / WebCore / loader / ResourceLoader.cpp
blobea96e34678c2a06b7588bfcba8ee23fcd278a994
1 /*
2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * 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 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "config.h"
31 #include "ResourceLoader.h"
33 #include "DocumentLoader.h"
34 #include "Frame.h"
35 #include "FrameLoader.h"
36 #include "Page.h"
37 #include "ProgressTracker.h"
38 #include "ResourceHandle.h"
39 #include "ResourceError.h"
40 #include "Settings.h"
41 #include "SharedBuffer.h"
43 namespace WebCore {
45 PassRefPtr<SharedBuffer> ResourceLoader::resourceData()
47 if (m_resourceData)
48 return m_resourceData;
50 if (ResourceHandle::supportsBufferedData() && m_handle)
51 return m_handle->bufferedData();
53 return 0;
56 ResourceLoader::ResourceLoader(Frame* frame, bool sendResourceLoadCallbacks, bool shouldContentSniff)
57 : m_reachedTerminalState(false)
58 , m_cancelled(false)
59 , m_calledDidFinishLoad(false)
60 , m_sendResourceLoadCallbacks(sendResourceLoadCallbacks)
61 , m_shouldContentSniff(shouldContentSniff)
62 , m_shouldBufferData(true)
63 , m_frame(frame)
64 , m_documentLoader(frame->loader()->activeDocumentLoader())
65 , m_identifier(0)
66 , m_defersLoading(frame->page()->defersLoading())
70 ResourceLoader::~ResourceLoader()
72 ASSERT(m_reachedTerminalState);
75 void ResourceLoader::releaseResources()
77 ASSERT(!m_reachedTerminalState);
79 // It's possible that when we release the handle, it will be
80 // deallocated and release the last reference to this object.
81 // We need to retain to avoid accessing the object after it
82 // has been deallocated and also to avoid reentering this method.
83 RefPtr<ResourceLoader> protector(this);
85 m_frame = 0;
86 m_documentLoader = 0;
88 // We need to set reachedTerminalState to true before we release
89 // the resources to prevent a double dealloc of WebView <rdar://problem/4372628>
90 m_reachedTerminalState = true;
92 m_identifier = 0;
94 if (m_handle) {
95 // Clear out the ResourceHandle's client so that it doesn't try to call
96 // us back after we release it.
97 m_handle->setClient(0);
98 m_handle = 0;
101 m_resourceData = 0;
102 m_deferredRequest = ResourceRequest();
105 bool ResourceLoader::load(const ResourceRequest& r)
107 ASSERT(!m_handle);
108 ASSERT(m_deferredRequest.isNull());
109 ASSERT(!frameLoader()->isArchiveLoadPending(this));
111 m_originalURL = r.url();
113 ResourceRequest clientRequest(r);
114 willSendRequest(clientRequest, ResourceResponse());
115 if (clientRequest.isNull()) {
116 didFail(frameLoader()->cancelledError(r));
117 return false;
120 if (frameLoader()->willUseArchive(this, clientRequest, m_originalURL))
121 return true;
123 if (m_defersLoading) {
124 m_deferredRequest = clientRequest;
125 return true;
128 m_handle = ResourceHandle::create(clientRequest, this, m_frame.get(), m_defersLoading, m_shouldContentSniff, true);
130 return true;
133 void ResourceLoader::setDefersLoading(bool defers)
135 m_defersLoading = defers;
136 if (m_handle)
137 m_handle->setDefersLoading(defers);
138 if (!defers && !m_deferredRequest.isNull()) {
139 ResourceRequest request(m_deferredRequest);
140 m_deferredRequest = ResourceRequest();
141 load(request);
145 FrameLoader* ResourceLoader::frameLoader() const
147 if (!m_frame)
148 return 0;
149 return m_frame->loader();
152 void ResourceLoader::setShouldBufferData(bool shouldBufferData)
154 m_shouldBufferData = shouldBufferData;
156 // Reset any already buffered data
157 if (!m_shouldBufferData)
158 m_resourceData = 0;
162 void ResourceLoader::addData(const char* data, int length, bool allAtOnce)
164 if (!m_shouldBufferData)
165 return;
167 if (allAtOnce) {
168 m_resourceData = new SharedBuffer(data, length);
169 return;
172 if (ResourceHandle::supportsBufferedData()) {
173 // Buffer data only if the connection has handed us the data because is has stopped buffering it.
174 if (m_resourceData)
175 m_resourceData->append(data, length);
176 } else {
177 if (!m_resourceData)
178 m_resourceData = new SharedBuffer(data, length);
179 else
180 m_resourceData->append(data, length);
184 void ResourceLoader::clearResourceData()
186 if (m_resourceData)
187 m_resourceData->clear();
190 void ResourceLoader::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
192 // Protect this in this delegate method since the additional processing can do
193 // anything including possibly derefing this; one example of this is Radar 3266216.
194 RefPtr<ResourceLoader> protector(this);
196 ASSERT(!m_reachedTerminalState);
198 if (m_sendResourceLoadCallbacks) {
199 if (!m_identifier) {
200 m_identifier = m_frame->page()->progress()->createUniqueIdentifier();
201 frameLoader()->assignIdentifierToInitialRequest(m_identifier, request);
204 frameLoader()->willSendRequest(this, request, redirectResponse);
207 m_request = request;
210 void ResourceLoader::didReceiveResponse(const ResourceResponse& r)
212 ASSERT(!m_reachedTerminalState);
214 // Protect this in this delegate method since the additional processing can do
215 // anything including possibly derefing this; one example of this is Radar 3266216.
216 RefPtr<ResourceLoader> protector(this);
218 m_response = r;
220 if (m_sendResourceLoadCallbacks)
221 frameLoader()->didReceiveResponse(this, m_response);
224 void ResourceLoader::didReceiveData(const char* data, int length, long long lengthReceived, bool allAtOnce)
226 // The following assertions are not quite valid here, since a subclass
227 // might override didReceiveData in a way that invalidates them. This
228 // happens with the steps listed in 3266216
229 // ASSERT(con == connection);
230 // ASSERT(!m_reachedTerminalState);
232 // Protect this in this delegate method since the additional processing can do
233 // anything including possibly derefing this; one example of this is Radar 3266216.
234 RefPtr<ResourceLoader> protector(this);
236 addData(data, length, allAtOnce);
237 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
238 // However, with today's computers and networking speeds, this won't happen in practice.
239 // Could be an issue with a giant local file.
240 if (m_sendResourceLoadCallbacks && m_frame)
241 frameLoader()->didReceiveData(this, data, length, static_cast<int>(lengthReceived));
244 void ResourceLoader::willStopBufferingData(const char* data, int length)
246 if (!m_shouldBufferData)
247 return;
249 ASSERT(!m_resourceData);
250 m_resourceData = new SharedBuffer(data, length);
253 void ResourceLoader::didFinishLoading()
255 // If load has been cancelled after finishing (which could happen with a
256 // JavaScript that changes the window location), do nothing.
257 if (m_cancelled)
258 return;
259 ASSERT(!m_reachedTerminalState);
261 didFinishLoadingOnePart();
262 releaseResources();
265 void ResourceLoader::didFinishLoadingOnePart()
267 if (m_cancelled)
268 return;
269 ASSERT(!m_reachedTerminalState);
271 if (m_calledDidFinishLoad)
272 return;
273 m_calledDidFinishLoad = true;
274 if (m_sendResourceLoadCallbacks)
275 frameLoader()->didFinishLoad(this);
278 void ResourceLoader::didFail(const ResourceError& error)
280 if (m_cancelled)
281 return;
282 ASSERT(!m_reachedTerminalState);
284 // Protect this in this delegate method since the additional processing can do
285 // anything including possibly derefing this; one example of this is Radar 3266216.
286 RefPtr<ResourceLoader> protector(this);
288 if (m_sendResourceLoadCallbacks && !m_calledDidFinishLoad)
289 frameLoader()->didFailToLoad(this, error);
291 releaseResources();
294 void ResourceLoader::wasBlocked()
296 didFail(blockedError());
299 void ResourceLoader::didCancel(const ResourceError& error)
301 ASSERT(!m_cancelled);
302 ASSERT(!m_reachedTerminalState);
304 // This flag prevents bad behavior when loads that finish cause the
305 // load itself to be cancelled (which could happen with a javascript that
306 // changes the window location). This is used to prevent both the body
307 // of this method and the body of connectionDidFinishLoading: running
308 // for a single delegate. Cancelling wins.
309 m_cancelled = true;
311 if (m_handle)
312 m_handle->clearAuthentication();
314 frameLoader()->cancelPendingArchiveLoad(this);
315 if (m_handle) {
316 m_handle->cancel();
317 m_handle = 0;
319 if (m_sendResourceLoadCallbacks && !m_calledDidFinishLoad)
320 frameLoader()->didFailToLoad(this, error);
322 releaseResources();
325 void ResourceLoader::cancel()
327 cancel(ResourceError());
330 void ResourceLoader::cancel(const ResourceError& error)
332 if (m_reachedTerminalState)
333 return;
334 if (!error.isNull())
335 didCancel(error);
336 else
337 didCancel(cancelledError());
340 const ResourceResponse& ResourceLoader::response() const
342 return m_response;
345 ResourceError ResourceLoader::cancelledError()
347 return frameLoader()->cancelledError(m_request);
350 ResourceError ResourceLoader::blockedError()
352 return frameLoader()->blockedError(m_request);
355 void ResourceLoader::willSendRequest(ResourceHandle*, ResourceRequest& request, const ResourceResponse& redirectResponse)
357 willSendRequest(request, redirectResponse);
360 void ResourceLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
362 didReceiveResponse(response);
365 void ResourceLoader::didReceiveData(ResourceHandle*, const char* data, int length, int lengthReceived)
367 didReceiveData(data, length, lengthReceived, false);
370 void ResourceLoader::didFinishLoading(ResourceHandle*)
372 didFinishLoading();
375 void ResourceLoader::didFail(ResourceHandle*, const ResourceError& error)
377 didFail(error);
380 void ResourceLoader::wasBlocked(ResourceHandle*)
382 wasBlocked();
385 void ResourceLoader::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
387 // Protect this in this delegate method since the additional processing can do
388 // anything including possibly derefing this; one example of this is Radar 3266216.
389 RefPtr<ResourceLoader> protector(this);
390 frameLoader()->didReceiveAuthenticationChallenge(this, challenge);
393 void ResourceLoader::didCancelAuthenticationChallenge(const AuthenticationChallenge& challenge)
395 // Protect this in this delegate method since the additional processing can do
396 // anything including possibly derefing this; one example of this is Radar 3266216.
397 RefPtr<ResourceLoader> protector(this);
398 frameLoader()->didCancelAuthenticationChallenge(this, challenge);
401 void ResourceLoader::receivedCancellation(const AuthenticationChallenge&)
403 cancel();
406 void ResourceLoader::willCacheResponse(ResourceHandle*, CacheStoragePolicy& policy)
408 // When in private browsing mode, prevent caching to disk
409 if (policy == StorageAllowed && m_frame->settings()->privateBrowsingEnabled())
410 policy = StorageAllowedInMemoryOnly;