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