1 /*
2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
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.
17 *
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.
28 */
29
30 #include "config.h"
31 #include "ResourceLoader.h"
32
33 #include "ApplicationCacheHost.h"
34 #include "DocumentLoader.h"
35 #include "Frame.h"
36 #include "FrameLoader.h"
37 #include "Page.h"
38 #include "ProgressTracker.h"
39 #include "ResourceHandle.h"
40 #include "ResourceError.h"
41 #include "Settings.h"
42 #include "SharedBuffer.h"
43
44 namespace WebCore {
45
resourceData()46 PassRefPtr<SharedBuffer> ResourceLoader::resourceData()
47 {
48 if (m_resourceData)
49 return m_resourceData;
50
51 if (ResourceHandle::supportsBufferedData() && m_handle)
52 return m_handle->bufferedData();
53
54 return 0;
55 }
56
ResourceLoader(Frame * frame,bool sendResourceLoadCallbacks,bool shouldContentSniff)57 ResourceLoader::ResourceLoader(Frame* frame, bool sendResourceLoadCallbacks, bool shouldContentSniff)
58 : m_frame(frame)
59 , m_documentLoader(frame->loader()->activeDocumentLoader())
60 , m_identifier(0)
61 , m_reachedTerminalState(false)
62 , m_cancelled(false)
63 , m_calledDidFinishLoad(false)
64 , m_sendResourceLoadCallbacks(sendResourceLoadCallbacks)
65 , m_shouldContentSniff(shouldContentSniff)
66 , m_shouldBufferData(true)
67 , m_defersLoading(frame->page()->defersLoading())
68 {
69 }
70
~ResourceLoader()71 ResourceLoader::~ResourceLoader()
72 {
73 ASSERT(m_reachedTerminalState);
74 }
75
releaseResources()76 void ResourceLoader::releaseResources()
77 {
78 ASSERT(!m_reachedTerminalState);
79
80 // It's possible that when we release the handle, it will be
81 // deallocated and release the last reference to this object.
82 // We need to retain to avoid accessing the object after it
83 // has been deallocated and also to avoid reentering this method.
84 RefPtr<ResourceLoader> protector(this);
85
86 m_frame = 0;
87 m_documentLoader = 0;
88
89 // We need to set reachedTerminalState to true before we release
90 // the resources to prevent a double dealloc of WebView <rdar://problem/4372628>
91 m_reachedTerminalState = true;
92
93 m_identifier = 0;
94
95 if (m_handle) {
96 // Clear out the ResourceHandle's client so that it doesn't try to call
97 // us back after we release it.
98 m_handle->setClient(0);
99 m_handle = 0;
100 }
101
102 m_resourceData = 0;
103 m_deferredRequest = ResourceRequest();
104 }
105
load(const ResourceRequest & r)106 bool ResourceLoader::load(const ResourceRequest& r)
107 {
108 ASSERT(!m_handle);
109 ASSERT(m_deferredRequest.isNull());
110 ASSERT(!m_documentLoader->isSubstituteLoadPending(this));
111
112 ResourceRequest clientRequest(r);
113 willSendRequest(clientRequest, ResourceResponse());
114 if (clientRequest.isNull()) {
115 didFail(frameLoader()->cancelledError(r));
116 return false;
117 }
118
119 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
120 if (m_documentLoader->scheduleArchiveLoad(this, clientRequest, r.url()))
121 return true;
122 #endif
123
124 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
125 if (m_documentLoader->applicationCacheHost()->maybeLoadResource(this, clientRequest, r.url()))
126 return true;
127 #endif
128
129 if (m_defersLoading) {
130 m_deferredRequest = clientRequest;
131 return true;
132 }
133
134 m_handle = ResourceHandle::create(clientRequest, this, m_frame.get(), m_defersLoading, m_shouldContentSniff, true);
135
136 return true;
137 }
138
setDefersLoading(bool defers)139 void ResourceLoader::setDefersLoading(bool defers)
140 {
141 m_defersLoading = defers;
142 if (m_handle)
143 m_handle->setDefersLoading(defers);
144 if (!defers && !m_deferredRequest.isNull()) {
145 ResourceRequest request(m_deferredRequest);
146 m_deferredRequest = ResourceRequest();
147 load(request);
148 }
149 }
150
frameLoader() const151 FrameLoader* ResourceLoader::frameLoader() const
152 {
153 if (!m_frame)
154 return 0;
155 return m_frame->loader();
156 }
157
setShouldBufferData(bool shouldBufferData)158 void ResourceLoader::setShouldBufferData(bool shouldBufferData)
159 {
160 m_shouldBufferData = shouldBufferData;
161
162 // Reset any already buffered data
163 if (!m_shouldBufferData)
164 m_resourceData = 0;
165 }
166
167
addData(const char * data,int length,bool allAtOnce)168 void ResourceLoader::addData(const char* data, int length, bool allAtOnce)
169 {
170 if (!m_shouldBufferData)
171 return;
172
173 if (allAtOnce) {
174 m_resourceData = SharedBuffer::create(data, length);
175 return;
176 }
177
178 if (ResourceHandle::supportsBufferedData()) {
179 // Buffer data only if the connection has handed us the data because is has stopped buffering it.
180 if (m_resourceData)
181 m_resourceData->append(data, length);
182 } else {
183 if (!m_resourceData)
184 m_resourceData = SharedBuffer::create(data, length);
185 else
186 m_resourceData->append(data, length);
187 }
188 }
189
clearResourceData()190 void ResourceLoader::clearResourceData()
191 {
192 if (m_resourceData)
193 m_resourceData->clear();
194 }
195
willSendRequest(ResourceRequest & request,const ResourceResponse & redirectResponse)196 void ResourceLoader::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
197 {
198 // Protect this in this delegate method since the additional processing can do
199 // anything including possibly derefing this; one example of this is Radar 3266216.
200 RefPtr<ResourceLoader> protector(this);
201
202 ASSERT(!m_reachedTerminalState);
203
204 if (m_sendResourceLoadCallbacks) {
205 if (!m_identifier) {
206 m_identifier = m_frame->page()->progress()->createUniqueIdentifier();
207 frameLoader()->assignIdentifierToInitialRequest(m_identifier, request);
208 }
209
210 frameLoader()->willSendRequest(this, request, redirectResponse);
211 }
212
213 m_request = request;
214 }
215
didSendData(unsigned long long,unsigned long long)216 void ResourceLoader::didSendData(unsigned long long, unsigned long long)
217 {
218 }
219
didReceiveResponse(const ResourceResponse & r)220 void ResourceLoader::didReceiveResponse(const ResourceResponse& r)
221 {
222 ASSERT(!m_reachedTerminalState);
223
224 // Protect this in this delegate method since the additional processing can do
225 // anything including possibly derefing this; one example of this is Radar 3266216.
226 RefPtr<ResourceLoader> protector(this);
227
228 m_response = r;
229
230 if (FormData* data = m_request.httpBody())
231 data->removeGeneratedFilesIfNeeded();
232
233 if (m_sendResourceLoadCallbacks)
234 frameLoader()->didReceiveResponse(this, m_response);
235 }
236
didReceiveData(const char * data,int length,long long lengthReceived,bool allAtOnce)237 void ResourceLoader::didReceiveData(const char* data, int length, long long lengthReceived, bool allAtOnce)
238 {
239 // The following assertions are not quite valid here, since a subclass
240 // might override didReceiveData in a way that invalidates them. This
241 // happens with the steps listed in 3266216
242 // ASSERT(con == connection);
243 // ASSERT(!m_reachedTerminalState);
244
245 // Protect this in this delegate method since the additional processing can do
246 // anything including possibly derefing this; one example of this is Radar 3266216.
247 RefPtr<ResourceLoader> protector(this);
248
249 addData(data, length, allAtOnce);
250 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
251 // However, with today's computers and networking speeds, this won't happen in practice.
252 // Could be an issue with a giant local file.
253 if (m_sendResourceLoadCallbacks && m_frame)
254 frameLoader()->didReceiveData(this, data, length, static_cast<int>(lengthReceived));
255 }
256
willStopBufferingData(const char * data,int length)257 void ResourceLoader::willStopBufferingData(const char* data, int length)
258 {
259 if (!m_shouldBufferData)
260 return;
261
262 ASSERT(!m_resourceData);
263 m_resourceData = SharedBuffer::create(data, length);
264 }
265
didFinishLoading()266 void ResourceLoader::didFinishLoading()
267 {
268 // If load has been cancelled after finishing (which could happen with a
269 // JavaScript that changes the window location), do nothing.
270 if (m_cancelled)
271 return;
272 ASSERT(!m_reachedTerminalState);
273
274 didFinishLoadingOnePart();
275 releaseResources();
276 }
277
didFinishLoadingOnePart()278 void ResourceLoader::didFinishLoadingOnePart()
279 {
280 if (m_cancelled)
281 return;
282 ASSERT(!m_reachedTerminalState);
283
284 if (m_calledDidFinishLoad)
285 return;
286 m_calledDidFinishLoad = true;
287 if (m_sendResourceLoadCallbacks)
288 frameLoader()->didFinishLoad(this);
289 }
290
didFail(const ResourceError & error)291 void ResourceLoader::didFail(const ResourceError& error)
292 {
293 if (m_cancelled)
294 return;
295 ASSERT(!m_reachedTerminalState);
296
297 // Protect this in this delegate method since the additional processing can do
298 // anything including possibly derefing this; one example of this is Radar 3266216.
299 RefPtr<ResourceLoader> protector(this);
300
301 if (FormData* data = m_request.httpBody())
302 data->removeGeneratedFilesIfNeeded();
303
304 if (m_sendResourceLoadCallbacks && !m_calledDidFinishLoad)
305 frameLoader()->didFailToLoad(this, error);
306
307 releaseResources();
308 }
309
didCancel(const ResourceError & error)310 void ResourceLoader::didCancel(const ResourceError& error)
311 {
312 ASSERT(!m_cancelled);
313 ASSERT(!m_reachedTerminalState);
314
315 if (FormData* data = m_request.httpBody())
316 data->removeGeneratedFilesIfNeeded();
317
318 // This flag prevents bad behavior when loads that finish cause the
319 // load itself to be cancelled (which could happen with a javascript that
320 // changes the window location). This is used to prevent both the body
321 // of this method and the body of connectionDidFinishLoading: running
322 // for a single delegate. Cancelling wins.
323 m_cancelled = true;
324
325 if (m_handle)
326 m_handle->clearAuthentication();
327
328 m_documentLoader->cancelPendingSubstituteLoad(this);
329 if (m_handle) {
330 m_handle->cancel();
331 m_handle = 0;
332 }
333 if (m_sendResourceLoadCallbacks && !m_calledDidFinishLoad)
334 frameLoader()->didFailToLoad(this, error);
335
336 releaseResources();
337 }
338
cancel()339 void ResourceLoader::cancel()
340 {
341 cancel(ResourceError());
342 }
343
cancel(const ResourceError & error)344 void ResourceLoader::cancel(const ResourceError& error)
345 {
346 if (m_reachedTerminalState)
347 return;
348 if (!error.isNull())
349 didCancel(error);
350 else
351 didCancel(cancelledError());
352 }
353
response() const354 const ResourceResponse& ResourceLoader::response() const
355 {
356 return m_response;
357 }
358
cancelledError()359 ResourceError ResourceLoader::cancelledError()
360 {
361 return frameLoader()->cancelledError(m_request);
362 }
363
blockedError()364 ResourceError ResourceLoader::blockedError()
365 {
366 return frameLoader()->blockedError(m_request);
367 }
368
cannotShowURLError()369 ResourceError ResourceLoader::cannotShowURLError()
370 {
371 return frameLoader()->cannotShowURLError(m_request);
372 }
373
willSendRequest(ResourceHandle *,ResourceRequest & request,const ResourceResponse & redirectResponse)374 void ResourceLoader::willSendRequest(ResourceHandle*, ResourceRequest& request, const ResourceResponse& redirectResponse)
375 {
376 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
377 if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForRedirect(this, request, redirectResponse))
378 return;
379 #endif
380 willSendRequest(request, redirectResponse);
381 }
382
didSendData(ResourceHandle *,unsigned long long bytesSent,unsigned long long totalBytesToBeSent)383 void ResourceLoader::didSendData(ResourceHandle*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
384 {
385 didSendData(bytesSent, totalBytesToBeSent);
386 }
387
didReceiveResponse(ResourceHandle *,const ResourceResponse & response)388 void ResourceLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
389 {
390 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
391 if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForResponse(this, response))
392 return;
393 #endif
394 didReceiveResponse(response);
395 }
396
didReceiveData(ResourceHandle *,const char * data,int length,int lengthReceived)397 void ResourceLoader::didReceiveData(ResourceHandle*, const char* data, int length, int lengthReceived)
398 {
399 didReceiveData(data, length, lengthReceived, false);
400 }
401
didFinishLoading(ResourceHandle *)402 void ResourceLoader::didFinishLoading(ResourceHandle*)
403 {
404 didFinishLoading();
405 }
406
didFail(ResourceHandle *,const ResourceError & error)407 void ResourceLoader::didFail(ResourceHandle*, const ResourceError& error)
408 {
409 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
410 if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForError(this, error))
411 return;
412 #endif
413 didFail(error);
414 }
415
wasBlocked(ResourceHandle *)416 void ResourceLoader::wasBlocked(ResourceHandle*)
417 {
418 didFail(blockedError());
419 }
420
cannotShowURL(ResourceHandle *)421 void ResourceLoader::cannotShowURL(ResourceHandle*)
422 {
423 didFail(cannotShowURLError());
424 }
425
shouldUseCredentialStorage()426 bool ResourceLoader::shouldUseCredentialStorage()
427 {
428 RefPtr<ResourceLoader> protector(this);
429 return frameLoader()->shouldUseCredentialStorage(this);
430 }
431
didReceiveAuthenticationChallenge(const AuthenticationChallenge & challenge)432 void ResourceLoader::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
433 {
434 // Protect this in this delegate method since the additional processing can do
435 // anything including possibly derefing this; one example of this is Radar 3266216.
436 RefPtr<ResourceLoader> protector(this);
437 frameLoader()->didReceiveAuthenticationChallenge(this, challenge);
438 }
439
didCancelAuthenticationChallenge(const AuthenticationChallenge & challenge)440 void ResourceLoader::didCancelAuthenticationChallenge(const AuthenticationChallenge& challenge)
441 {
442 // Protect this in this delegate method since the additional processing can do
443 // anything including possibly derefing this; one example of this is Radar 3266216.
444 RefPtr<ResourceLoader> protector(this);
445 frameLoader()->didCancelAuthenticationChallenge(this, challenge);
446 }
447
receivedCancellation(const AuthenticationChallenge &)448 void ResourceLoader::receivedCancellation(const AuthenticationChallenge&)
449 {
450 cancel();
451 }
452
willCacheResponse(ResourceHandle *,CacheStoragePolicy & policy)453 void ResourceLoader::willCacheResponse(ResourceHandle*, CacheStoragePolicy& policy)
454 {
455 // When in private browsing mode, prevent caching to disk
456 if (policy == StorageAllowed && m_frame->settings()->privateBrowsingEnabled())
457 policy = StorageAllowedInMemoryOnly;
458 }
459
460 }
461