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