WebCore/loader/DocumentLoader.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 }