|
1 /* |
|
2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. |
|
3 * |
|
4 * Redistribution and use in source and binary forms, with or without |
|
5 * modification, are permitted provided that the following conditions |
|
6 * are met: |
|
7 * |
|
8 * 1. Redistributions of source code must retain the above copyright |
|
9 * notice, this list of conditions and the following disclaimer. |
|
10 * 2. Redistributions in binary form must reproduce the above copyright |
|
11 * notice, this list of conditions and the following disclaimer in the |
|
12 * documentation and/or other materials provided with the distribution. |
|
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
|
14 * its contributors may be used to endorse or promote products derived |
|
15 * from this software without specific prior written permission. |
|
16 * |
|
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
|
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
|
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
27 */ |
|
28 |
|
29 #include "config.h" |
|
30 #include "DocumentLoader.h" |
|
31 |
|
32 #include "ApplicationCacheHost.h" |
|
33 #include "ArchiveFactory.h" |
|
34 #include "ArchiveResourceCollection.h" |
|
35 #include "CachedPage.h" |
|
36 #include "DocLoader.h" |
|
37 #include "Document.h" |
|
38 #include "DocumentParser.h" |
|
39 #include "Event.h" |
|
40 #include "Frame.h" |
|
41 #include "FrameLoader.h" |
|
42 #include "FrameTree.h" |
|
43 #include "HistoryItem.h" |
|
44 #include "Logging.h" |
|
45 #include "MainResourceLoader.h" |
|
46 #include "Page.h" |
|
47 #include "PlatformString.h" |
|
48 #include "Settings.h" |
|
49 #include "SharedBuffer.h" |
|
50 |
|
51 #include <wtf/Assertions.h> |
|
52 #include <wtf/unicode/Unicode.h> |
|
53 |
|
54 namespace WebCore { |
|
55 |
|
56 static void cancelAll(const ResourceLoaderSet& loaders) |
|
57 { |
|
58 const ResourceLoaderSet copy = loaders; |
|
59 ResourceLoaderSet::const_iterator end = copy.end(); |
|
60 for (ResourceLoaderSet::const_iterator it = copy.begin(); it != end; ++it) |
|
61 (*it)->cancel(); |
|
62 } |
|
63 |
|
64 static void setAllDefersLoading(const ResourceLoaderSet& loaders, bool defers) |
|
65 { |
|
66 const ResourceLoaderSet copy = loaders; |
|
67 ResourceLoaderSet::const_iterator end = copy.end(); |
|
68 for (ResourceLoaderSet::const_iterator it = copy.begin(); it != end; ++it) |
|
69 (*it)->setDefersLoading(defers); |
|
70 } |
|
71 |
|
72 DocumentLoader::DocumentLoader(const ResourceRequest& req, const SubstituteData& substituteData) |
|
73 : m_deferMainResourceDataLoad(true) |
|
74 , m_frame(0) |
|
75 , m_originalRequest(req) |
|
76 , m_substituteData(substituteData) |
|
77 , m_originalRequestCopy(req) |
|
78 , m_request(req) |
|
79 , m_committed(false) |
|
80 , m_isStopping(false) |
|
81 , m_loading(false) |
|
82 , m_gotFirstByte(false) |
|
83 , m_primaryLoadComplete(false) |
|
84 , m_isClientRedirect(false) |
|
85 , m_stopRecordingResponses(false) |
|
86 , m_substituteResourceDeliveryTimer(this, &DocumentLoader::substituteResourceDeliveryTimerFired) |
|
87 , m_didCreateGlobalHistoryEntry(false) |
|
88 #if ENABLE(OFFLINE_WEB_APPLICATIONS) |
|
89 , m_applicationCacheHost(new ApplicationCacheHost(this)) |
|
90 #endif |
|
91 { |
|
92 } |
|
93 |
|
94 FrameLoader* DocumentLoader::frameLoader() const |
|
95 { |
|
96 if (!m_frame) |
|
97 return 0; |
|
98 return m_frame->loader(); |
|
99 } |
|
100 |
|
101 DocumentLoader::~DocumentLoader() |
|
102 { |
|
103 ASSERT(!m_frame || frameLoader()->activeDocumentLoader() != this || !frameLoader()->isLoading()); |
|
104 } |
|
105 |
|
106 PassRefPtr<SharedBuffer> DocumentLoader::mainResourceData() const |
|
107 { |
|
108 if (m_mainResourceData) |
|
109 return m_mainResourceData; |
|
110 if (m_mainResourceLoader) |
|
111 return m_mainResourceLoader->resourceData(); |
|
112 return 0; |
|
113 } |
|
114 |
|
115 const ResourceRequest& DocumentLoader::originalRequest() const |
|
116 { |
|
117 return m_originalRequest; |
|
118 } |
|
119 |
|
120 const ResourceRequest& DocumentLoader::originalRequestCopy() const |
|
121 { |
|
122 return m_originalRequestCopy; |
|
123 } |
|
124 |
|
125 const ResourceRequest& DocumentLoader::request() const |
|
126 { |
|
127 return m_request; |
|
128 } |
|
129 |
|
130 ResourceRequest& DocumentLoader::request() |
|
131 { |
|
132 return m_request; |
|
133 } |
|
134 |
|
135 const KURL& DocumentLoader::url() const |
|
136 { |
|
137 return request().url(); |
|
138 } |
|
139 |
|
140 void DocumentLoader::replaceRequestURLForSameDocumentNavigation(const KURL& url) |
|
141 { |
|
142 m_originalRequestCopy.setURL(url); |
|
143 m_request.setURL(url); |
|
144 } |
|
145 |
|
146 void DocumentLoader::setRequest(const ResourceRequest& req) |
|
147 { |
|
148 // Replacing an unreachable URL with alternate content looks like a server-side |
|
149 // redirect at this point, but we can replace a committed dataSource. |
|
150 bool handlingUnreachableURL = false; |
|
151 |
|
152 handlingUnreachableURL = m_substituteData.isValid() && !m_substituteData.failingURL().isEmpty(); |
|
153 |
|
154 if (handlingUnreachableURL) |
|
155 m_committed = false; |
|
156 |
|
157 // We should never be getting a redirect callback after the data |
|
158 // source is committed, except in the unreachable URL case. It |
|
159 // would be a WebFoundation bug if it sent a redirect callback after commit. |
|
160 ASSERT(!m_committed); |
|
161 |
|
162 KURL oldURL = m_request.url(); |
|
163 m_request = req; |
|
164 |
|
165 // Only send webView:didReceiveServerRedirectForProvisionalLoadForFrame: if URL changed. |
|
166 // Also, don't send it when replacing unreachable URLs with alternate content. |
|
167 if (!handlingUnreachableURL && oldURL != req.url()) |
|
168 frameLoader()->didReceiveServerRedirectForProvisionalLoadForFrame(); |
|
169 } |
|
170 |
|
171 void DocumentLoader::setMainDocumentError(const ResourceError& error) |
|
172 { |
|
173 m_mainDocumentError = error; |
|
174 frameLoader()->setMainDocumentError(this, error); |
|
175 } |
|
176 |
|
177 void DocumentLoader::clearErrors() |
|
178 { |
|
179 m_mainDocumentError = ResourceError(); |
|
180 } |
|
181 |
|
182 void DocumentLoader::mainReceivedError(const ResourceError& error, bool isComplete) |
|
183 { |
|
184 ASSERT(!error.isNull()); |
|
185 |
|
186 #if ENABLE(OFFLINE_WEB_APPLICATIONS) |
|
187 m_applicationCacheHost->failedLoadingMainResource(); |
|
188 #endif |
|
189 |
|
190 if (!frameLoader()) |
|
191 return; |
|
192 setMainDocumentError(error); |
|
193 if (isComplete) |
|
194 frameLoader()->mainReceivedCompleteError(this, error); |
|
195 } |
|
196 |
|
197 // Cancels the data source's pending loads. Conceptually, a data source only loads |
|
198 // one document at a time, but one document may have many related resources. |
|
199 // stopLoading will stop all loads initiated by the data source, |
|
200 // but not loads initiated by child frames' data sources -- that's the WebFrame's job. |
|
201 void DocumentLoader::stopLoading(DatabasePolicy databasePolicy) |
|
202 { |
|
203 // In some rare cases, calling FrameLoader::stopLoading could set m_loading to false. |
|
204 // (This can happen when there's a single XMLHttpRequest currently loading and stopLoading causes it |
|
205 // to stop loading. Because of this, we need to save it so we don't return early. |
|
206 bool loading = m_loading; |
|
207 |
|
208 if (m_committed) { |
|
209 // Attempt to stop the frame if the document loader is loading, or if it is done loading but |
|
210 // still parsing. Failure to do so can cause a world leak. |
|
211 Document* doc = m_frame->document(); |
|
212 |
|
213 if (loading || doc->parsing()) |
|
214 m_frame->loader()->stopLoading(UnloadEventPolicyNone, databasePolicy); |
|
215 } |
|
216 |
|
217 // Always cancel multipart loaders |
|
218 cancelAll(m_multipartSubresourceLoaders); |
|
219 |
|
220 if (!loading) |
|
221 return; |
|
222 |
|
223 RefPtr<Frame> protectFrame(m_frame); |
|
224 RefPtr<DocumentLoader> protectLoader(this); |
|
225 |
|
226 m_isStopping = true; |
|
227 |
|
228 FrameLoader* frameLoader = DocumentLoader::frameLoader(); |
|
229 |
|
230 if (m_mainResourceLoader) |
|
231 // Stop the main resource loader and let it send the cancelled message. |
|
232 m_mainResourceLoader->cancel(); |
|
233 else if (!m_subresourceLoaders.isEmpty()) |
|
234 // The main resource loader already finished loading. Set the cancelled error on the |
|
235 // document and let the subresourceLoaders send individual cancelled messages below. |
|
236 setMainDocumentError(frameLoader->cancelledError(m_request)); |
|
237 else |
|
238 // If there are no resource loaders, we need to manufacture a cancelled message. |
|
239 // (A back/forward navigation has no resource loaders because its resources are cached.) |
|
240 mainReceivedError(frameLoader->cancelledError(m_request), true); |
|
241 |
|
242 stopLoadingSubresources(); |
|
243 stopLoadingPlugIns(); |
|
244 |
|
245 m_isStopping = false; |
|
246 } |
|
247 |
|
248 void DocumentLoader::setupForReplace() |
|
249 { |
|
250 frameLoader()->setupForReplace(); |
|
251 m_committed = false; |
|
252 } |
|
253 |
|
254 void DocumentLoader::commitIfReady() |
|
255 { |
|
256 if (m_gotFirstByte && !m_committed) { |
|
257 m_committed = true; |
|
258 frameLoader()->commitProvisionalLoad(); |
|
259 } |
|
260 } |
|
261 |
|
262 void DocumentLoader::finishedLoading() |
|
263 { |
|
264 m_gotFirstByte = true; |
|
265 commitIfReady(); |
|
266 if (FrameLoader* loader = frameLoader()) { |
|
267 loader->finishedLoadingDocument(this); |
|
268 loader->writer()->end(); |
|
269 } |
|
270 } |
|
271 |
|
272 void DocumentLoader::commitLoad(const char* data, int length) |
|
273 { |
|
274 // Both unloading the old page and parsing the new page may execute JavaScript which destroys the datasource |
|
275 // by starting a new load, so retain temporarily. |
|
276 RefPtr<DocumentLoader> protect(this); |
|
277 |
|
278 commitIfReady(); |
|
279 if (FrameLoader* frameLoader = DocumentLoader::frameLoader()) |
|
280 frameLoader->committedLoad(this, data, length); |
|
281 } |
|
282 |
|
283 bool DocumentLoader::doesProgressiveLoad(const String& MIMEType) const |
|
284 { |
|
285 return !frameLoader()->isReplacing() || MIMEType == "text/html"; |
|
286 } |
|
287 |
|
288 void DocumentLoader::receivedData(const char* data, int length) |
|
289 { |
|
290 m_gotFirstByte = true; |
|
291 if (doesProgressiveLoad(m_response.mimeType())) |
|
292 commitLoad(data, length); |
|
293 } |
|
294 |
|
295 void DocumentLoader::setupForReplaceByMIMEType(const String& newMIMEType) |
|
296 { |
|
297 if (!m_gotFirstByte) |
|
298 return; |
|
299 |
|
300 String oldMIMEType = m_response.mimeType(); |
|
301 |
|
302 if (!doesProgressiveLoad(oldMIMEType)) { |
|
303 frameLoader()->revertToProvisional(this); |
|
304 setupForReplace(); |
|
305 RefPtr<SharedBuffer> resourceData = mainResourceData(); |
|
306 commitLoad(resourceData->data(), resourceData->size()); |
|
307 } |
|
308 |
|
309 frameLoader()->finishedLoadingDocument(this); |
|
310 m_frame->loader()->writer()->end(); |
|
311 |
|
312 frameLoader()->setReplacing(); |
|
313 m_gotFirstByte = false; |
|
314 |
|
315 if (doesProgressiveLoad(newMIMEType)) { |
|
316 frameLoader()->revertToProvisional(this); |
|
317 setupForReplace(); |
|
318 } |
|
319 |
|
320 stopLoadingSubresources(); |
|
321 stopLoadingPlugIns(); |
|
322 clearArchiveResources(); |
|
323 } |
|
324 |
|
325 void DocumentLoader::updateLoading() |
|
326 { |
|
327 if (!m_frame) { |
|
328 setLoading(false); |
|
329 return; |
|
330 } |
|
331 ASSERT(this == frameLoader()->activeDocumentLoader()); |
|
332 setLoading(frameLoader()->isLoading()); |
|
333 } |
|
334 |
|
335 void DocumentLoader::setFrame(Frame* frame) |
|
336 { |
|
337 if (m_frame == frame) |
|
338 return; |
|
339 ASSERT(frame && !m_frame); |
|
340 m_frame = frame; |
|
341 attachToFrame(); |
|
342 } |
|
343 |
|
344 void DocumentLoader::attachToFrame() |
|
345 { |
|
346 ASSERT(m_frame); |
|
347 } |
|
348 |
|
349 void DocumentLoader::detachFromFrame() |
|
350 { |
|
351 ASSERT(m_frame); |
|
352 #if ENABLE(OFFLINE_WEB_APPLICATIONS) |
|
353 m_applicationCacheHost->setDOMApplicationCache(0); |
|
354 #endif |
|
355 m_frame = 0; |
|
356 } |
|
357 |
|
358 void DocumentLoader::prepareForLoadStart() |
|
359 { |
|
360 ASSERT(!m_isStopping); |
|
361 setPrimaryLoadComplete(false); |
|
362 ASSERT(frameLoader()); |
|
363 clearErrors(); |
|
364 |
|
365 setLoading(true); |
|
366 |
|
367 frameLoader()->prepareForLoadStart(); |
|
368 } |
|
369 |
|
370 void DocumentLoader::setPrimaryLoadComplete(bool flag) |
|
371 { |
|
372 m_primaryLoadComplete = flag; |
|
373 if (flag) { |
|
374 if (m_mainResourceLoader) { |
|
375 m_mainResourceData = m_mainResourceLoader->resourceData(); |
|
376 m_mainResourceLoader = 0; |
|
377 } |
|
378 |
|
379 if (this == frameLoader()->activeDocumentLoader()) |
|
380 updateLoading(); |
|
381 } |
|
382 } |
|
383 |
|
384 bool DocumentLoader::isLoadingInAPISense() const |
|
385 { |
|
386 // Once a frame has loaded, we no longer need to consider subresources, |
|
387 // but we still need to consider subframes. |
|
388 if (frameLoader()->state() != FrameStateComplete) { |
|
389 if (!m_primaryLoadComplete && isLoading()) |
|
390 return true; |
|
391 if (!m_subresourceLoaders.isEmpty()) |
|
392 return true; |
|
393 Document* doc = m_frame->document(); |
|
394 if (doc->docLoader()->requestCount()) |
|
395 return true; |
|
396 if (DocumentParser* parser = doc->parser()) |
|
397 if (parser->processingData()) |
|
398 return true; |
|
399 } |
|
400 return frameLoader()->subframeIsLoading(); |
|
401 } |
|
402 |
|
403 void DocumentLoader::addAllArchiveResources(Archive* archive) |
|
404 { |
|
405 if (!m_archiveResourceCollection) |
|
406 m_archiveResourceCollection.set(new ArchiveResourceCollection); |
|
407 |
|
408 ASSERT(archive); |
|
409 if (!archive) |
|
410 return; |
|
411 |
|
412 m_archiveResourceCollection->addAllResources(archive); |
|
413 } |
|
414 |
|
415 // FIXME: Adding a resource directly to a DocumentLoader/ArchiveResourceCollection seems like bad design, but is API some apps rely on. |
|
416 // Can we change the design in a manner that will let us deprecate that API without reducing functionality of those apps? |
|
417 void DocumentLoader::addArchiveResource(PassRefPtr<ArchiveResource> resource) |
|
418 { |
|
419 if (!m_archiveResourceCollection) |
|
420 m_archiveResourceCollection.set(new ArchiveResourceCollection); |
|
421 |
|
422 ASSERT(resource); |
|
423 if (!resource) |
|
424 return; |
|
425 |
|
426 m_archiveResourceCollection->addResource(resource); |
|
427 } |
|
428 |
|
429 ArchiveResource* DocumentLoader::archiveResourceForURL(const KURL& url) const |
|
430 { |
|
431 if (!m_archiveResourceCollection) |
|
432 return 0; |
|
433 |
|
434 ArchiveResource* resource = m_archiveResourceCollection->archiveResourceForURL(url); |
|
435 |
|
436 return resource && !resource->shouldIgnoreWhenUnarchiving() ? resource : 0; |
|
437 } |
|
438 |
|
439 PassRefPtr<Archive> DocumentLoader::popArchiveForSubframe(const String& frameName) |
|
440 { |
|
441 return m_archiveResourceCollection ? m_archiveResourceCollection->popSubframeArchive(frameName) : 0; |
|
442 } |
|
443 |
|
444 void DocumentLoader::clearArchiveResources() |
|
445 { |
|
446 m_archiveResourceCollection.clear(); |
|
447 m_substituteResourceDeliveryTimer.stop(); |
|
448 } |
|
449 |
|
450 void DocumentLoader::setParsedArchiveData(PassRefPtr<SharedBuffer> data) |
|
451 { |
|
452 m_parsedArchiveData = data; |
|
453 } |
|
454 |
|
455 SharedBuffer* DocumentLoader::parsedArchiveData() const |
|
456 { |
|
457 return m_parsedArchiveData.get(); |
|
458 } |
|
459 |
|
460 PassRefPtr<ArchiveResource> DocumentLoader::mainResource() const |
|
461 { |
|
462 const ResourceResponse& r = response(); |
|
463 RefPtr<SharedBuffer> mainResourceBuffer = mainResourceData(); |
|
464 if (!mainResourceBuffer) |
|
465 mainResourceBuffer = SharedBuffer::create(); |
|
466 |
|
467 return ArchiveResource::create(mainResourceBuffer, r.url(), r.mimeType(), r.textEncodingName(), frame()->tree()->name()); |
|
468 } |
|
469 |
|
470 PassRefPtr<ArchiveResource> DocumentLoader::subresource(const KURL& url) const |
|
471 { |
|
472 if (!isCommitted()) |
|
473 return 0; |
|
474 |
|
475 CachedResource* resource = m_frame->document()->docLoader()->cachedResource(url); |
|
476 if (!resource || !resource->isLoaded()) |
|
477 return archiveResourceForURL(url); |
|
478 |
|
479 // FIXME: This has the side effect of making the resource non-purgeable. |
|
480 // It would be better if it didn't have this permanent effect. |
|
481 if (!resource->makePurgeable(false)) |
|
482 return 0; |
|
483 |
|
484 RefPtr<SharedBuffer> data = resource->data(); |
|
485 if (!data) |
|
486 return 0; |
|
487 |
|
488 return ArchiveResource::create(data.release(), url, resource->response()); |
|
489 } |
|
490 |
|
491 void DocumentLoader::getSubresources(Vector<PassRefPtr<ArchiveResource> >& subresources) const |
|
492 { |
|
493 if (!isCommitted()) |
|
494 return; |
|
495 |
|
496 Document* document = m_frame->document(); |
|
497 |
|
498 const DocLoader::DocumentResourceMap& allResources = document->docLoader()->allCachedResources(); |
|
499 DocLoader::DocumentResourceMap::const_iterator end = allResources.end(); |
|
500 for (DocLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) { |
|
501 RefPtr<ArchiveResource> subresource = this->subresource(KURL(ParsedURLString, it->second->url())); |
|
502 if (subresource) |
|
503 subresources.append(subresource.release()); |
|
504 } |
|
505 |
|
506 return; |
|
507 } |
|
508 |
|
509 void DocumentLoader::deliverSubstituteResourcesAfterDelay() |
|
510 { |
|
511 if (m_pendingSubstituteResources.isEmpty()) |
|
512 return; |
|
513 ASSERT(m_frame && m_frame->page()); |
|
514 if (m_frame->page()->defersLoading()) |
|
515 return; |
|
516 if (!m_substituteResourceDeliveryTimer.isActive()) |
|
517 m_substituteResourceDeliveryTimer.startOneShot(0); |
|
518 } |
|
519 |
|
520 void DocumentLoader::substituteResourceDeliveryTimerFired(Timer<DocumentLoader>*) |
|
521 { |
|
522 if (m_pendingSubstituteResources.isEmpty()) |
|
523 return; |
|
524 ASSERT(m_frame && m_frame->page()); |
|
525 if (m_frame->page()->defersLoading()) |
|
526 return; |
|
527 |
|
528 SubstituteResourceMap copy; |
|
529 copy.swap(m_pendingSubstituteResources); |
|
530 |
|
531 SubstituteResourceMap::const_iterator end = copy.end(); |
|
532 for (SubstituteResourceMap::const_iterator it = copy.begin(); it != end; ++it) { |
|
533 RefPtr<ResourceLoader> loader = it->first; |
|
534 SubstituteResource* resource = it->second.get(); |
|
535 |
|
536 if (resource) { |
|
537 SharedBuffer* data = resource->data(); |
|
538 |
|
539 loader->didReceiveResponse(resource->response()); |
|
540 loader->didReceiveData(data->data(), data->size(), data->size(), true); |
|
541 loader->didFinishLoading(); |
|
542 } else { |
|
543 // A null resource means that we should fail the load. |
|
544 // FIXME: Maybe we should use another error here - something like "not in cache". |
|
545 loader->didFail(loader->cannotShowURLError()); |
|
546 } |
|
547 } |
|
548 } |
|
549 |
|
550 #ifndef NDEBUG |
|
551 bool DocumentLoader::isSubstituteLoadPending(ResourceLoader* loader) const |
|
552 { |
|
553 return m_pendingSubstituteResources.contains(loader); |
|
554 } |
|
555 #endif |
|
556 |
|
557 void DocumentLoader::cancelPendingSubstituteLoad(ResourceLoader* loader) |
|
558 { |
|
559 if (m_pendingSubstituteResources.isEmpty()) |
|
560 return; |
|
561 m_pendingSubstituteResources.remove(loader); |
|
562 if (m_pendingSubstituteResources.isEmpty()) |
|
563 m_substituteResourceDeliveryTimer.stop(); |
|
564 } |
|
565 |
|
566 bool DocumentLoader::scheduleArchiveLoad(ResourceLoader* loader, const ResourceRequest& request, const KURL& originalURL) |
|
567 { |
|
568 ArchiveResource* resource = 0; |
|
569 |
|
570 if (request.url() == originalURL) |
|
571 resource = archiveResourceForURL(originalURL); |
|
572 |
|
573 if (!resource) { |
|
574 // WebArchiveDebugMode means we fail loads instead of trying to fetch them from the network if they're not in the archive. |
|
575 bool shouldFailLoad = m_frame->settings()->webArchiveDebugModeEnabled() && ArchiveFactory::isArchiveMimeType(responseMIMEType()); |
|
576 |
|
577 if (!shouldFailLoad) |
|
578 return false; |
|
579 } |
|
580 |
|
581 m_pendingSubstituteResources.set(loader, resource); |
|
582 deliverSubstituteResourcesAfterDelay(); |
|
583 |
|
584 return true; |
|
585 } |
|
586 |
|
587 void DocumentLoader::addResponse(const ResourceResponse& r) |
|
588 { |
|
589 if (!m_stopRecordingResponses) |
|
590 m_responses.append(r); |
|
591 } |
|
592 |
|
593 void DocumentLoader::stopRecordingResponses() |
|
594 { |
|
595 m_stopRecordingResponses = true; |
|
596 } |
|
597 |
|
598 void DocumentLoader::setTitle(const String& title) |
|
599 { |
|
600 if (title.isEmpty()) |
|
601 return; |
|
602 |
|
603 if (m_pageTitle != title) { |
|
604 frameLoader()->willChangeTitle(this); |
|
605 m_pageTitle = title; |
|
606 frameLoader()->didChangeTitle(this); |
|
607 } |
|
608 } |
|
609 |
|
610 void DocumentLoader::setIconURL(const String& iconURL) |
|
611 { |
|
612 if (iconURL.isEmpty()) |
|
613 return; |
|
614 |
|
615 if (m_pageIconURL != iconURL) { |
|
616 m_pageIconURL = iconURL; |
|
617 frameLoader()->didChangeIcons(this); |
|
618 } |
|
619 } |
|
620 |
|
621 KURL DocumentLoader::urlForHistory() const |
|
622 { |
|
623 // Return the URL to be used for history and B/F list. |
|
624 // Returns nil for WebDataProtocol URLs that aren't alternates |
|
625 // for unreachable URLs, because these can't be stored in history. |
|
626 if (m_substituteData.isValid()) |
|
627 return unreachableURL(); |
|
628 |
|
629 return m_originalRequestCopy.url(); |
|
630 } |
|
631 |
|
632 bool DocumentLoader::urlForHistoryReflectsFailure() const |
|
633 { |
|
634 return m_substituteData.isValid() || m_response.httpStatusCode() >= 400; |
|
635 } |
|
636 |
|
637 const KURL& DocumentLoader::originalURL() const |
|
638 { |
|
639 return m_originalRequestCopy.url(); |
|
640 } |
|
641 |
|
642 const KURL& DocumentLoader::requestURL() const |
|
643 { |
|
644 return request().url(); |
|
645 } |
|
646 |
|
647 const KURL& DocumentLoader::responseURL() const |
|
648 { |
|
649 return m_response.url(); |
|
650 } |
|
651 |
|
652 const String& DocumentLoader::responseMIMEType() const |
|
653 { |
|
654 return m_response.mimeType(); |
|
655 } |
|
656 |
|
657 const KURL& DocumentLoader::unreachableURL() const |
|
658 { |
|
659 return m_substituteData.failingURL(); |
|
660 } |
|
661 |
|
662 void DocumentLoader::setDefersLoading(bool defers) |
|
663 { |
|
664 if (m_mainResourceLoader) |
|
665 m_mainResourceLoader->setDefersLoading(defers); |
|
666 setAllDefersLoading(m_subresourceLoaders, defers); |
|
667 setAllDefersLoading(m_plugInStreamLoaders, defers); |
|
668 if (!defers) |
|
669 deliverSubstituteResourcesAfterDelay(); |
|
670 } |
|
671 |
|
672 void DocumentLoader::stopLoadingPlugIns() |
|
673 { |
|
674 cancelAll(m_plugInStreamLoaders); |
|
675 } |
|
676 |
|
677 void DocumentLoader::stopLoadingSubresources() |
|
678 { |
|
679 cancelAll(m_subresourceLoaders); |
|
680 } |
|
681 |
|
682 void DocumentLoader::addSubresourceLoader(ResourceLoader* loader) |
|
683 { |
|
684 m_subresourceLoaders.add(loader); |
|
685 setLoading(true); |
|
686 } |
|
687 |
|
688 void DocumentLoader::removeSubresourceLoader(ResourceLoader* loader) |
|
689 { |
|
690 m_subresourceLoaders.remove(loader); |
|
691 updateLoading(); |
|
692 if (Frame* frame = m_frame) |
|
693 frame->loader()->checkLoadComplete(); |
|
694 } |
|
695 |
|
696 void DocumentLoader::addPlugInStreamLoader(ResourceLoader* loader) |
|
697 { |
|
698 m_plugInStreamLoaders.add(loader); |
|
699 setLoading(true); |
|
700 } |
|
701 |
|
702 void DocumentLoader::removePlugInStreamLoader(ResourceLoader* loader) |
|
703 { |
|
704 m_plugInStreamLoaders.remove(loader); |
|
705 updateLoading(); |
|
706 } |
|
707 |
|
708 bool DocumentLoader::isLoadingMainResource() const |
|
709 { |
|
710 return !!m_mainResourceLoader; |
|
711 } |
|
712 |
|
713 bool DocumentLoader::isLoadingSubresources() const |
|
714 { |
|
715 return !m_subresourceLoaders.isEmpty(); |
|
716 } |
|
717 |
|
718 bool DocumentLoader::isLoadingPlugIns() const |
|
719 { |
|
720 return !m_plugInStreamLoaders.isEmpty(); |
|
721 } |
|
722 |
|
723 bool DocumentLoader::isLoadingMultipartContent() const |
|
724 { |
|
725 return m_mainResourceLoader && m_mainResourceLoader->isLoadingMultipartContent(); |
|
726 } |
|
727 |
|
728 bool DocumentLoader::startLoadingMainResource(unsigned long identifier) |
|
729 { |
|
730 ASSERT(!m_mainResourceLoader); |
|
731 m_mainResourceLoader = MainResourceLoader::create(m_frame); |
|
732 m_mainResourceLoader->setIdentifier(identifier); |
|
733 |
|
734 // FIXME: Is there any way the extra fields could have not been added by now? |
|
735 // If not, it would be great to remove this line of code. |
|
736 frameLoader()->addExtraFieldsToMainResourceRequest(m_request); |
|
737 |
|
738 if (!m_mainResourceLoader->load(m_request, m_substituteData)) { |
|
739 // FIXME: If this should really be caught, we should just ASSERT this doesn't happen; |
|
740 // should it be caught by other parts of WebKit or other parts of the app? |
|
741 LOG_ERROR("could not create WebResourceHandle for URL %s -- should be caught by policy handler level", m_request.url().string().ascii().data()); |
|
742 m_mainResourceLoader = 0; |
|
743 return false; |
|
744 } |
|
745 |
|
746 return true; |
|
747 } |
|
748 |
|
749 void DocumentLoader::cancelMainResourceLoad(const ResourceError& error) |
|
750 { |
|
751 m_mainResourceLoader->cancel(error); |
|
752 } |
|
753 |
|
754 void DocumentLoader::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader) |
|
755 { |
|
756 m_multipartSubresourceLoaders.add(loader); |
|
757 m_subresourceLoaders.remove(loader); |
|
758 updateLoading(); |
|
759 if (Frame* frame = m_frame) |
|
760 frame->loader()->checkLoadComplete(); |
|
761 } |
|
762 |
|
763 void DocumentLoader::iconLoadDecisionAvailable() |
|
764 { |
|
765 if (m_frame) |
|
766 m_frame->loader()->iconLoadDecisionAvailable(); |
|
767 } |
|
768 |
|
769 } |