Unreviewed, rolling out r137333, r137344, r137364, and
[WebKit-https.git] / Source / WebCore / loader / DocumentLoader.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2011 Google Inc. All rights reserved.
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 "DocumentLoader.h"
32
33 #include "ApplicationCacheHost.h"
34 #include "ArchiveResourceCollection.h"
35 #include "CachedPage.h"
36 #include "CachedResourceLoader.h"
37 #include "DOMWindow.h"
38 #include "Document.h"
39 #include "DocumentParser.h"
40 #include "DocumentWriter.h"
41 #include "Event.h"
42 #include "Frame.h"
43 #include "FrameLoader.h"
44 #include "FrameLoaderClient.h"
45 #include "FrameTree.h"
46 #include "HistoryItem.h"
47 #include "InspectorInstrumentation.h"
48 #include "Logging.h"
49 #include "MainResourceLoader.h"
50 #include "Page.h"
51 #include "ResourceBuffer.h"
52 #include "SchemeRegistry.h"
53 #include "Settings.h"
54 #include "TextResourceDecoder.h"
55 #include "WebCoreMemoryInstrumentation.h"
56 #include <wtf/Assertions.h>
57 #include <wtf/MemoryInstrumentationHashMap.h>
58 #include <wtf/MemoryInstrumentationHashSet.h>
59 #include <wtf/MemoryInstrumentationVector.h>
60 #include <wtf/text/CString.h>
61 #include <wtf/text/WTFString.h>
62 #include <wtf/unicode/Unicode.h>
63
64 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
65 #include "ArchiveFactory.h"
66 #endif
67
68 namespace WebCore {
69
70 static void cancelAll(const ResourceLoaderSet& loaders)
71 {
72     Vector<RefPtr<ResourceLoader> > loadersCopy;
73     copyToVector(loaders, loadersCopy);
74     size_t size = loadersCopy.size();
75     for (size_t i = 0; i < size; ++i)
76         loadersCopy[i]->cancel();
77 }
78
79 static void setAllDefersLoading(const ResourceLoaderSet& loaders, bool defers)
80 {
81     Vector<RefPtr<ResourceLoader> > loadersCopy;
82     copyToVector(loaders, loadersCopy);
83     size_t size = loadersCopy.size();
84     for (size_t i = 0; i < size; ++i)
85         loadersCopy[i]->setDefersLoading(defers);
86 }
87
88 DocumentLoader::DocumentLoader(const ResourceRequest& req, const SubstituteData& substituteData)
89     : m_deferMainResourceDataLoad(true)
90     , m_frame(0)
91     , m_cachedResourceLoader(CachedResourceLoader::create(this))
92     , m_writer(m_frame)
93     , m_originalRequest(req)
94     , m_substituteData(substituteData)
95     , m_originalRequestCopy(req)
96     , m_request(req)
97     , m_committed(false)
98     , m_isStopping(false)
99     , m_gotFirstByte(false)
100     , m_isClientRedirect(false)
101     , m_loadingEmptyDocument(false)
102     , m_wasOnloadHandled(false)
103     , m_stopRecordingResponses(false)
104     , m_substituteResourceDeliveryTimer(this, &DocumentLoader::substituteResourceDeliveryTimerFired)
105     , m_didCreateGlobalHistoryEntry(false)
106     , m_applicationCacheHost(adoptPtr(new ApplicationCacheHost(this)))
107 {
108 }
109
110 FrameLoader* DocumentLoader::frameLoader() const
111 {
112     if (!m_frame)
113         return 0;
114     return m_frame->loader();
115 }
116
117 DocumentLoader::~DocumentLoader()
118 {
119     ASSERT(!m_frame || frameLoader()->activeDocumentLoader() != this || !isLoading());
120     if (m_iconLoadDecisionCallback)
121         m_iconLoadDecisionCallback->invalidate();
122     if (m_iconDataCallback)
123         m_iconDataCallback->invalidate();
124     m_cachedResourceLoader->clearDocumentLoader();
125 }
126
127 PassRefPtr<ResourceBuffer> DocumentLoader::mainResourceData() const
128 {
129     if (m_mainResourceData)
130         return m_mainResourceData;
131     if (m_mainResourceLoader)
132         return m_mainResourceLoader->resourceData();
133     return 0;
134 }
135
136 const ResourceRequest& DocumentLoader::originalRequest() const
137 {
138     return m_originalRequest;
139 }
140
141 const ResourceRequest& DocumentLoader::originalRequestCopy() const
142 {
143     return m_originalRequestCopy;
144 }
145
146 const ResourceRequest& DocumentLoader::request() const
147 {
148     return m_request;
149 }
150
151 ResourceRequest& DocumentLoader::request()
152 {
153     return m_request;
154 }
155
156 const KURL& DocumentLoader::url() const
157 {
158     return request().url();
159 }
160
161 void DocumentLoader::replaceRequestURLForSameDocumentNavigation(const KURL& url)
162 {
163     m_originalRequestCopy.setURL(url);
164     m_request.setURL(url);
165 }
166
167 void DocumentLoader::setRequest(const ResourceRequest& req)
168 {
169     // Replacing an unreachable URL with alternate content looks like a server-side
170     // redirect at this point, but we can replace a committed dataSource.
171     bool handlingUnreachableURL = false;
172
173     handlingUnreachableURL = m_substituteData.isValid() && !m_substituteData.failingURL().isEmpty();
174
175     if (handlingUnreachableURL)
176         m_committed = false;
177
178     // We should never be getting a redirect callback after the data
179     // source is committed, except in the unreachable URL case. It 
180     // would be a WebFoundation bug if it sent a redirect callback after commit.
181     ASSERT(!m_committed);
182
183     KURL oldURL = m_request.url();
184     m_request = req;
185
186     // Only dispatchDidReceiveServerRedirectForProvisionalLoad() if URL changed (and is non-null).
187     // Also, don't send it when replacing unreachable URLs with alternate content.
188     if (!handlingUnreachableURL && !req.url().isNull() && oldURL != req.url())
189         frameLoader()->client()->dispatchDidReceiveServerRedirectForProvisionalLoad();
190 }
191
192 void DocumentLoader::setMainDocumentError(const ResourceError& error)
193 {
194     m_mainDocumentError = error;    
195     frameLoader()->client()->setMainDocumentError(this, error);
196 }
197
198 void DocumentLoader::mainReceivedError(const ResourceError& error)
199 {
200     ASSERT(!error.isNull());
201
202     m_applicationCacheHost->failedLoadingMainResource();
203
204     if (!frameLoader())
205         return;
206     setMainDocumentError(error);
207     clearMainResourceLoader();
208     frameLoader()->receivedMainResourceError(error);
209 }
210
211 // Cancels the data source's pending loads.  Conceptually, a data source only loads
212 // one document at a time, but one document may have many related resources. 
213 // stopLoading will stop all loads initiated by the data source, 
214 // but not loads initiated by child frames' data sources -- that's the WebFrame's job.
215 void DocumentLoader::stopLoading()
216 {
217     // In some rare cases, calling FrameLoader::stopLoading could cause isLoading() to return false.
218     // (This can happen when there's a single XMLHttpRequest currently loading and stopLoading causes it
219     // to stop loading. Because of this, we need to save it so we don't return early.
220     bool loading = isLoading();
221     
222     if (m_committed) {
223         // Attempt to stop the frame if the document loader is loading, or if it is done loading but
224         // still  parsing. Failure to do so can cause a world leak.
225         Document* doc = m_frame->document();
226         
227         if (loading || doc->parsing())
228             m_frame->loader()->stopLoading(UnloadEventPolicyNone);
229     }
230
231     // Always cancel multipart loaders
232     cancelAll(m_multipartSubresourceLoaders);
233
234     // Appcache uses ResourceHandle directly, DocumentLoader doesn't count these loads.
235     m_applicationCacheHost->stopLoadingInFrame(m_frame);
236     
237 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
238     clearArchiveResources();
239 #endif
240
241     if (!loading) {
242         // If something above restarted loading we might run into mysterious crashes like 
243         // https://bugs.webkit.org/show_bug.cgi?id=62764 and <rdar://problem/9328684>
244         ASSERT(!isLoading());
245         return;
246     }
247
248     // We might run in to infinite recursion if we're stopping loading as the result of 
249     // detaching from the frame, so break out of that recursion here.
250     // See <rdar://problem/9673866> for more details.
251     if (m_isStopping)
252         return;
253     
254     RefPtr<Frame> protectFrame(m_frame);
255     RefPtr<DocumentLoader> protectLoader(this);
256
257     m_isStopping = true;
258
259     FrameLoader* frameLoader = DocumentLoader::frameLoader();
260     
261     if (m_mainResourceLoader)
262         // Stop the main resource loader and let it send the cancelled message.
263         m_mainResourceLoader->cancel();
264     else if (!m_subresourceLoaders.isEmpty())
265         // The main resource loader already finished loading. Set the cancelled error on the 
266         // document and let the subresourceLoaders send individual cancelled messages below.
267         setMainDocumentError(frameLoader->cancelledError(m_request));
268     else
269         // If there are no resource loaders, we need to manufacture a cancelled message.
270         // (A back/forward navigation has no resource loaders because its resources are cached.)
271         mainReceivedError(frameLoader->cancelledError(m_request));
272     
273     stopLoadingSubresources();
274     stopLoadingPlugIns();
275     
276     m_isStopping = false;
277 }
278
279 void DocumentLoader::commitIfReady()
280 {
281     if (!m_committed) {
282         m_committed = true;
283         frameLoader()->commitProvisionalLoad();
284     }
285 }
286
287 void DocumentLoader::finishedLoading()
288 {
289     commitIfReady();
290     if (!frameLoader())
291         return;
292
293     if (!maybeCreateArchive()) {
294         // If this is an empty document, it will not have actually been created yet. Commit dummy data so that
295         // DocumentWriter::begin() gets called and creates the Document.
296         if (!m_gotFirstByte)
297             commitData(0, 0);
298         frameLoader()->client()->finishedLoading(this);
299     }
300
301     m_writer.end();
302     if (!m_mainDocumentError.isNull())
303         return;
304     clearMainResourceLoader();
305     if (!frameLoader()->stateMachine()->creatingInitialEmptyDocument())
306         frameLoader()->checkLoadComplete();
307 }
308
309 void DocumentLoader::commitLoad(const char* data, int length)
310 {
311     // Both unloading the old page and parsing the new page may execute JavaScript which destroys the datasource
312     // by starting a new load, so retain temporarily.
313     RefPtr<Frame> protectFrame(m_frame);
314     RefPtr<DocumentLoader> protectLoader(this);
315
316     commitIfReady();
317     FrameLoader* frameLoader = DocumentLoader::frameLoader();
318     if (!frameLoader)
319         return;
320 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
321     if (ArchiveFactory::isArchiveMimeType(response().mimeType()))
322         return;
323 #endif
324     frameLoader->client()->committedLoad(this, data, length);
325 }
326
327 void DocumentLoader::commitData(const char* bytes, size_t length)
328 {
329     if (!m_gotFirstByte) {
330         m_gotFirstByte = true;
331         m_writer.begin(documentURL(), false);
332         m_writer.setDocumentWasLoadedAsPartOfNavigation();
333
334         if (frameLoader()->stateMachine()->creatingInitialEmptyDocument())
335             return;
336         
337 #if ENABLE(MHTML)
338         // The origin is the MHTML file, we need to set the base URL to the document encoded in the MHTML so
339         // relative URLs are resolved properly.
340         if (m_archive && m_archive->type() == Archive::MHTML)
341             m_frame->document()->setBaseURLOverride(m_archive->mainResource()->url());
342 #endif
343
344         // Call receivedFirstData() exactly once per load. We should only reach this point multiple times
345         // for multipart loads, and FrameLoader::isReplacing() will be true after the first time.
346         if (!isMultipartReplacingLoad())
347             frameLoader()->receivedFirstData();
348
349         bool userChosen = true;
350         String encoding = overrideEncoding();
351         if (encoding.isNull()) {
352             userChosen = false;
353             encoding = response().textEncodingName();
354 #if ENABLE(WEB_ARCHIVE)
355             if (m_archive && m_archive->type() == Archive::WebArchive)
356                 encoding = m_archive->mainResource()->textEncoding();
357 #endif
358         }
359         m_writer.setEncoding(encoding, userChosen);
360     }
361     ASSERT(m_frame->document()->parsing());
362     m_writer.addData(bytes, length);
363 }
364
365 void DocumentLoader::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
366 {
367     MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Loader);
368     info.addMember(m_frame);
369     info.addMember(m_mainResourceLoader);
370     info.addMember(m_subresourceLoaders);
371     info.addMember(m_multipartSubresourceLoaders);
372     info.addMember(m_plugInStreamLoaders);
373     info.addMember(m_substituteData);
374     info.addMember(m_pageTitle.string());
375     info.addMember(m_overrideEncoding);
376     info.addMember(m_responses);
377     info.addMember(m_originalRequest);
378     info.addMember(m_originalRequestCopy);
379     info.addMember(m_request);
380     info.addMember(m_response);
381     info.addMember(m_lastCheckedRequest);
382     info.addMember(m_responses);
383     info.addMember(m_pendingSubstituteResources);
384     info.addMember(m_resourcesClientKnowsAbout);
385     info.addMember(m_resourcesLoadedFromMemoryCacheForClientNotification);
386     info.addMember(m_clientRedirectSourceForHistory);
387     info.addMember(m_mainResourceData);
388 }
389
390 void DocumentLoader::receivedData(const char* data, int length)
391 {
392     if (!isMultipartReplacingLoad())
393         commitLoad(data, length);
394 }
395
396 void DocumentLoader::setupForReplace()
397 {
398     if (!mainResourceData())
399         return;
400     
401     maybeFinishLoadingMultipartContent();
402     maybeCreateArchive();
403     m_writer.end();
404     frameLoader()->setReplacing();
405     m_gotFirstByte = false;
406     
407     stopLoadingSubresources();
408     stopLoadingPlugIns();
409 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
410     clearArchiveResources();
411 #endif
412 }
413
414 void DocumentLoader::checkLoadComplete()
415 {
416     if (!m_frame || isLoading())
417         return;
418     ASSERT(this == frameLoader()->activeDocumentLoader());
419     m_frame->document()->domWindow()->finishedLoading();
420 }
421
422 void DocumentLoader::setFrame(Frame* frame)
423 {
424     if (m_frame == frame)
425         return;
426     ASSERT(frame && !m_frame);
427     m_frame = frame;
428     m_writer.setFrame(frame);
429     attachToFrame();
430 }
431
432 void DocumentLoader::attachToFrame()
433 {
434     ASSERT(m_frame);
435 }
436
437 void DocumentLoader::detachFromFrame()
438 {
439     ASSERT(m_frame);
440     RefPtr<Frame> protectFrame(m_frame);
441     RefPtr<DocumentLoader> protectLoader(this);
442
443     // It never makes sense to have a document loader that is detached from its
444     // frame have any loads active, so go ahead and kill all the loads.
445     stopLoading();
446
447     m_applicationCacheHost->setDOMApplicationCache(0);
448     InspectorInstrumentation::loaderDetachedFromFrame(m_frame, this);
449     m_frame = 0;
450 }
451
452 void DocumentLoader::clearMainResourceLoader()
453 {
454     if (m_mainResourceLoader) {
455         m_mainResourceData = m_mainResourceLoader->resourceData();
456         m_mainResourceLoader = 0;
457     }
458     m_loadingEmptyDocument = false;
459
460     if (this == frameLoader()->activeDocumentLoader())
461         checkLoadComplete();
462 }
463
464 bool DocumentLoader::isLoadingInAPISense() const
465 {
466     // Once a frame has loaded, we no longer need to consider subresources,
467     // but we still need to consider subframes.
468     if (frameLoader()->state() != FrameStateComplete) {
469         if (m_frame->settings()->needsIsLoadingInAPISenseQuirk() && !m_subresourceLoaders.isEmpty())
470             return true;
471     
472         Document* doc = m_frame->document();
473         if ((isLoadingMainResource() || !m_frame->document()->loadEventFinished()) && isLoading())
474             return true;
475         if (m_cachedResourceLoader->requestCount())
476             return true;
477         if (DocumentParser* parser = doc->parser())
478             if (parser->processingData())
479                 return true;
480     }
481     return frameLoader()->subframeIsLoading();
482 }
483
484 bool DocumentLoader::maybeCreateArchive()
485 {
486 #if !ENABLE(WEB_ARCHIVE) && !ENABLE(MHTML)
487     return false;
488 #else
489     
490     // Give the archive machinery a crack at this document. If the MIME type is not an archive type, it will return 0.
491     RefPtr<ResourceBuffer> mainResourceBuffer = mainResourceData();
492     m_archive = ArchiveFactory::create(m_response.url(), mainResourceBuffer ? mainResourceBuffer->sharedBuffer() : 0, m_response.mimeType());
493     if (!m_archive)
494         return false;
495     
496     addAllArchiveResources(m_archive.get());
497     ArchiveResource* mainResource = m_archive->mainResource();
498     m_parsedArchiveData = mainResource->data();
499     m_writer.setMIMEType(mainResource->mimeType());
500     
501     ASSERT(m_frame->document());
502     commitData(mainResource->data()->data(), mainResource->data()->size());
503     return true;
504 #endif // !ENABLE(WEB_ARCHIVE) && !ENABLE(MHTML)
505 }
506
507 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
508 void DocumentLoader::setArchive(PassRefPtr<Archive> archive)
509 {
510     m_archive = archive;
511     addAllArchiveResources(m_archive.get());
512 }
513
514 void DocumentLoader::addAllArchiveResources(Archive* archive)
515 {
516     if (!m_archiveResourceCollection)
517         m_archiveResourceCollection = adoptPtr(new ArchiveResourceCollection);
518         
519     ASSERT(archive);
520     if (!archive)
521         return;
522         
523     m_archiveResourceCollection->addAllResources(archive);
524 }
525
526 // FIXME: Adding a resource directly to a DocumentLoader/ArchiveResourceCollection seems like bad design, but is API some apps rely on.
527 // Can we change the design in a manner that will let us deprecate that API without reducing functionality of those apps?
528 void DocumentLoader::addArchiveResource(PassRefPtr<ArchiveResource> resource)
529 {
530     if (!m_archiveResourceCollection)
531         m_archiveResourceCollection = adoptPtr(new ArchiveResourceCollection);
532         
533     ASSERT(resource);
534     if (!resource)
535         return;
536         
537     m_archiveResourceCollection->addResource(resource);
538 }
539
540 PassRefPtr<Archive> DocumentLoader::popArchiveForSubframe(const String& frameName, const KURL& url)
541 {
542     return m_archiveResourceCollection ? m_archiveResourceCollection->popSubframeArchive(frameName, url) : PassRefPtr<Archive>(0);
543 }
544
545 void DocumentLoader::clearArchiveResources()
546 {
547     m_archiveResourceCollection.clear();
548     m_substituteResourceDeliveryTimer.stop();
549 }
550
551 SharedBuffer* DocumentLoader::parsedArchiveData() const
552 {
553     return m_parsedArchiveData.get();
554 }
555 #endif // ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
556
557 ArchiveResource* DocumentLoader::archiveResourceForURL(const KURL& url) const
558 {
559     if (!m_archiveResourceCollection)
560         return 0;
561         
562     ArchiveResource* resource = m_archiveResourceCollection->archiveResourceForURL(url);
563
564     return resource && !resource->shouldIgnoreWhenUnarchiving() ? resource : 0;
565 }
566
567 PassRefPtr<ArchiveResource> DocumentLoader::mainResource() const
568 {
569     const ResourceResponse& r = response();
570     
571     RefPtr<ResourceBuffer> mainResourceBuffer = mainResourceData();
572     RefPtr<SharedBuffer> data = mainResourceBuffer ? mainResourceBuffer->sharedBuffer() : 0;
573     if (!data)
574         data = SharedBuffer::create();
575         
576     return ArchiveResource::create(data, r.url(), r.mimeType(), r.textEncodingName(), frame()->tree()->uniqueName());
577 }
578
579 PassRefPtr<ArchiveResource> DocumentLoader::subresource(const KURL& url) const
580 {
581     if (!isCommitted())
582         return 0;
583     
584     CachedResource* resource = m_cachedResourceLoader->cachedResource(url);
585     if (!resource || !resource->isLoaded())
586         return archiveResourceForURL(url);
587
588     // FIXME: This has the side effect of making the resource non-purgeable.
589     // It would be better if it didn't have this permanent effect.
590     if (!resource->makePurgeable(false))
591         return 0;
592
593     ResourceBuffer* data = resource->resourceBuffer();
594     if (!data)
595         return 0;
596
597     return ArchiveResource::create(data->sharedBuffer(), url, resource->response());
598 }
599
600 void DocumentLoader::getSubresources(Vector<PassRefPtr<ArchiveResource> >& subresources) const
601 {
602     if (!isCommitted())
603         return;
604
605     const CachedResourceLoader::DocumentResourceMap& allResources = m_cachedResourceLoader->allCachedResources();
606     CachedResourceLoader::DocumentResourceMap::const_iterator end = allResources.end();
607     for (CachedResourceLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) {
608         RefPtr<ArchiveResource> subresource = this->subresource(KURL(ParsedURLString, it->value->url()));
609         if (subresource)
610             subresources.append(subresource.release());
611     }
612
613     return;
614 }
615
616 void DocumentLoader::deliverSubstituteResourcesAfterDelay()
617 {
618     if (m_pendingSubstituteResources.isEmpty())
619         return;
620     ASSERT(m_frame && m_frame->page());
621     if (m_frame->page()->defersLoading())
622         return;
623     if (!m_substituteResourceDeliveryTimer.isActive())
624         m_substituteResourceDeliveryTimer.startOneShot(0);
625 }
626
627 void DocumentLoader::substituteResourceDeliveryTimerFired(Timer<DocumentLoader>*)
628 {
629     if (m_pendingSubstituteResources.isEmpty())
630         return;
631     ASSERT(m_frame && m_frame->page());
632     if (m_frame->page()->defersLoading())
633         return;
634
635     SubstituteResourceMap copy;
636     copy.swap(m_pendingSubstituteResources);
637
638     SubstituteResourceMap::const_iterator end = copy.end();
639     for (SubstituteResourceMap::const_iterator it = copy.begin(); it != end; ++it) {
640         RefPtr<ResourceLoader> loader = it->key;
641         SubstituteResource* resource = it->value.get();
642         
643         if (resource) {
644             SharedBuffer* data = resource->data();
645         
646             loader->didReceiveResponse(resource->response());
647
648             // Calling ResourceLoader::didReceiveResponse can end up cancelling the load,
649             // so we need to check if the loader has reached its terminal state.
650             if (loader->reachedTerminalState())
651                 return;
652
653             loader->didReceiveData(data->data(), data->size(), data->size(), true);
654
655             // Calling ResourceLoader::didReceiveData can end up cancelling the load,
656             // so we need to check if the loader has reached its terminal state.
657             if (loader->reachedTerminalState())
658                 return;
659
660             loader->didFinishLoading(0);
661         } else {
662             // A null resource means that we should fail the load.
663             // FIXME: Maybe we should use another error here - something like "not in cache".
664             loader->didFail(loader->cannotShowURLError());
665         }
666     }
667 }
668
669 #ifndef NDEBUG
670 bool DocumentLoader::isSubstituteLoadPending(ResourceLoader* loader) const
671 {
672     return m_pendingSubstituteResources.contains(loader);
673 }
674 #endif
675
676 void DocumentLoader::cancelPendingSubstituteLoad(ResourceLoader* loader)
677 {
678     if (m_pendingSubstituteResources.isEmpty())
679         return;
680     m_pendingSubstituteResources.remove(loader);
681     if (m_pendingSubstituteResources.isEmpty())
682         m_substituteResourceDeliveryTimer.stop();
683 }
684
685 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
686 bool DocumentLoader::scheduleArchiveLoad(ResourceLoader* loader, const ResourceRequest& request, const KURL& originalURL)
687 {
688     if (request.url() == originalURL) {
689         if (ArchiveResource* resource = archiveResourceForURL(originalURL)) {
690             m_pendingSubstituteResources.set(loader, resource);
691             deliverSubstituteResourcesAfterDelay();
692             return true;
693         }
694     }
695
696     if (!m_archive)
697         return false;
698
699     switch (m_archive->type()) {
700 #if ENABLE(WEB_ARCHIVE)
701     case Archive::WebArchive:
702         // WebArchiveDebugMode means we fail loads instead of trying to fetch them from the network if they're not in the archive.
703         return m_frame->settings() && m_frame->settings()->webArchiveDebugModeEnabled() && ArchiveFactory::isArchiveMimeType(responseMIMEType());
704 #endif
705 #if ENABLE(MHTML)
706     case Archive::MHTML:
707         return true; // Always fail the load for resources not included in the MHTML.
708 #endif
709     default:
710         return false;
711     }
712 }
713 #endif // ENABLE(WEB_ARCHIVE)
714
715 void DocumentLoader::addResponse(const ResourceResponse& r)
716 {
717     if (!m_stopRecordingResponses)
718         m_responses.append(r);
719 }
720
721 void DocumentLoader::stopRecordingResponses()
722 {
723     m_stopRecordingResponses = true;
724     m_responses.shrinkToFit();
725 }
726
727 void DocumentLoader::setTitle(const StringWithDirection& title)
728 {
729     if (m_pageTitle == title)
730         return;
731
732     frameLoader()->willChangeTitle(this);
733     m_pageTitle = title;
734     frameLoader()->didChangeTitle(this);
735 }
736
737 KURL DocumentLoader::urlForHistory() const
738 {
739     // Return the URL to be used for history and B/F list.
740     // Returns nil for WebDataProtocol URLs that aren't alternates 
741     // for unreachable URLs, because these can't be stored in history.
742     if (m_substituteData.isValid())
743         return unreachableURL();
744
745     return m_originalRequestCopy.url();
746 }
747
748 bool DocumentLoader::urlForHistoryReflectsFailure() const
749 {
750     return m_substituteData.isValid() || m_response.httpStatusCode() >= 400;
751 }
752
753 const KURL& DocumentLoader::originalURL() const
754 {
755     return m_originalRequestCopy.url();
756 }
757
758 const KURL& DocumentLoader::requestURL() const
759 {
760     return request().url();
761 }
762
763 const KURL& DocumentLoader::responseURL() const
764 {
765     return m_response.url();
766 }
767
768 KURL DocumentLoader::documentURL() const
769 {
770     KURL url = substituteData().responseURL();
771 #if ENABLE(WEB_ARCHIVE)
772     if (url.isEmpty() && m_archive && m_archive->type() == Archive::WebArchive)
773         url = m_archive->mainResource()->url();
774 #endif
775     if (url.isEmpty())
776         url = requestURL();
777     if (url.isEmpty())
778         url = responseURL();
779     return url;
780 }
781
782 const String& DocumentLoader::responseMIMEType() const
783 {
784     return m_response.mimeType();
785 }
786
787 const KURL& DocumentLoader::unreachableURL() const
788 {
789     return m_substituteData.failingURL();
790 }
791
792 void DocumentLoader::setDefersLoading(bool defers)
793 {
794     if (m_mainResourceLoader)
795         m_mainResourceLoader->setDefersLoading(defers);
796     setAllDefersLoading(m_subresourceLoaders, defers);
797     setAllDefersLoading(m_plugInStreamLoaders, defers);
798     if (!defers)
799         deliverSubstituteResourcesAfterDelay();
800 }
801
802 void DocumentLoader::stopLoadingPlugIns()
803 {
804     cancelAll(m_plugInStreamLoaders);
805 }
806
807 void DocumentLoader::stopLoadingSubresources()
808 {
809     cancelAll(m_subresourceLoaders);
810 }
811
812 void DocumentLoader::addSubresourceLoader(ResourceLoader* loader)
813 {
814     m_subresourceLoaders.add(loader);
815 }
816
817 void DocumentLoader::removeSubresourceLoader(ResourceLoader* loader)
818 {
819     m_subresourceLoaders.remove(loader);
820     checkLoadComplete();
821     if (Frame* frame = m_frame)
822         frame->loader()->checkLoadComplete();
823 }
824
825 void DocumentLoader::addPlugInStreamLoader(ResourceLoader* loader)
826 {
827     m_plugInStreamLoaders.add(loader);
828 }
829
830 void DocumentLoader::removePlugInStreamLoader(ResourceLoader* loader)
831 {
832     m_plugInStreamLoaders.remove(loader);
833     checkLoadComplete();
834 }
835
836 bool DocumentLoader::isLoadingMainResource() const
837 {
838     return !!m_mainResourceLoader || m_loadingEmptyDocument;
839 }
840
841 bool DocumentLoader::isLoadingMultipartContent() const
842 {
843     return m_mainResourceLoader && m_mainResourceLoader->isLoadingMultipartContent();
844 }
845
846 bool DocumentLoader::isMultipartReplacingLoad() const
847 {
848     return isLoadingMultipartContent() && frameLoader()->isReplacing();
849 }
850
851 bool DocumentLoader::maybeLoadEmpty()
852 {
853     bool shouldLoadEmpty = !m_substituteData.isValid() && (m_request.url().isEmpty() || SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(m_request.url().protocol()));
854     if (!shouldLoadEmpty && !frameLoader()->client()->representationExistsForURLScheme(m_request.url().protocol()))
855         return false;
856
857     m_loadingEmptyDocument = true;
858     if (m_request.url().isEmpty() && !frameLoader()->stateMachine()->creatingInitialEmptyDocument())
859         m_request.setURL(blankURL());
860     String mimeType = shouldLoadEmpty ? "text/html" : frameLoader()->client()->generatedMIMETypeForURLScheme(m_request.url().protocol());
861     setResponse(ResourceResponse(m_request.url(), mimeType, 0, String(), String()));
862     finishedLoading();
863     return true;
864 }
865
866 void DocumentLoader::startLoadingMainResource()
867 {
868     m_mainDocumentError = ResourceError();
869     timing()->markNavigationStart();
870     ASSERT(!m_mainResourceLoader);
871
872     if (maybeLoadEmpty())
873         return;
874
875     m_mainResourceLoader = MainResourceLoader::create(this);
876
877     // FIXME: Is there any way the extra fields could have not been added by now?
878     // If not, it would be great to remove this line of code.
879     frameLoader()->addExtraFieldsToMainResourceRequest(m_request);
880     m_mainResourceLoader->load(m_request, m_substituteData);
881
882     if (m_request.isNull()) {
883         m_mainResourceLoader = 0;
884         maybeLoadEmpty();
885     }
886 }
887
888 void DocumentLoader::cancelMainResourceLoad(const ResourceError& error)
889 {
890     m_mainResourceLoader->cancel(error);
891 }
892
893 void DocumentLoader::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader)
894 {
895     m_multipartSubresourceLoaders.add(loader);
896     m_subresourceLoaders.remove(loader);
897     checkLoadComplete();
898     if (Frame* frame = m_frame)
899         frame->loader()->checkLoadComplete();    
900 }
901
902 void DocumentLoader::maybeFinishLoadingMultipartContent()
903 {
904     if (!frameLoader()->isReplacing())
905         return;
906
907     frameLoader()->setupForReplace();
908     m_committed = false;
909     RefPtr<ResourceBuffer> resourceData = mainResourceData();
910     commitLoad(resourceData->data(), resourceData->size());
911 }
912
913 void DocumentLoader::iconLoadDecisionAvailable()
914 {
915     if (m_frame)
916         m_frame->loader()->icon()->loadDecisionReceived(iconDatabase().synchronousLoadDecisionForIconURL(frameLoader()->icon()->url(), this));
917 }
918
919 static void iconLoadDecisionCallback(IconLoadDecision decision, void* context)
920 {
921     static_cast<DocumentLoader*>(context)->continueIconLoadWithDecision(decision);
922 }
923
924 void DocumentLoader::getIconLoadDecisionForIconURL(const String& urlString)
925 {
926     if (m_iconLoadDecisionCallback)
927         m_iconLoadDecisionCallback->invalidate();
928     m_iconLoadDecisionCallback = IconLoadDecisionCallback::create(this, iconLoadDecisionCallback);
929     iconDatabase().loadDecisionForIconURL(urlString, m_iconLoadDecisionCallback);
930 }
931
932 void DocumentLoader::continueIconLoadWithDecision(IconLoadDecision decision)
933 {
934     ASSERT(m_iconLoadDecisionCallback);
935     m_iconLoadDecisionCallback = 0;
936     if (m_frame)
937         m_frame->loader()->icon()->continueLoadWithDecision(decision);
938 }
939
940 static void iconDataCallback(SharedBuffer*, void*)
941 {
942     // FIXME: Implement this once we know what parts of WebCore actually need the icon data returned.
943 }
944
945 void DocumentLoader::getIconDataForIconURL(const String& urlString)
946 {   
947     if (m_iconDataCallback)
948         m_iconDataCallback->invalidate();
949     m_iconDataCallback = IconDataCallback::create(this, iconDataCallback);
950     iconDatabase().iconDataForIconURL(urlString, m_iconDataCallback);
951 }
952
953 void DocumentLoader::handledOnloadEvents()
954 {
955     m_wasOnloadHandled = true;
956     applicationCacheHost()->stopDeferringEvents();
957 }
958
959 } // namespace WebCore