Home | History | Annotate | Download | only in loader
      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 "core/loader/DocumentLoader.h"
     32 
     33 #include "core/FetchInitiatorTypeNames.h"
     34 #include "core/dom/Document.h"
     35 #include "core/dom/DocumentParser.h"
     36 #include "core/events/Event.h"
     37 #include "core/fetch/MemoryCache.h"
     38 #include "core/fetch/ResourceFetcher.h"
     39 #include "core/fetch/ResourceLoader.h"
     40 #include "core/html/HTMLFrameOwnerElement.h"
     41 #include "core/html/parser/TextResourceDecoder.h"
     42 #include "core/inspector/InspectorInstrumentation.h"
     43 #include "core/loader/FrameLoader.h"
     44 #include "core/loader/FrameLoaderClient.h"
     45 #include "core/loader/UniqueIdentifier.h"
     46 #include "core/loader/appcache/ApplicationCacheHost.h"
     47 #include "core/frame/LocalDOMWindow.h"
     48 #include "core/frame/LocalFrame.h"
     49 #include "core/frame/csp/ContentSecurityPolicy.h"
     50 #include "core/page/FrameTree.h"
     51 #include "core/page/Page.h"
     52 #include "core/frame/Settings.h"
     53 #include "platform/Logging.h"
     54 #include "platform/UserGestureIndicator.h"
     55 #include "platform/mhtml/ArchiveResourceCollection.h"
     56 #include "platform/mhtml/MHTMLArchive.h"
     57 #include "platform/plugins/PluginData.h"
     58 #include "platform/weborigin/SchemeRegistry.h"
     59 #include "platform/weborigin/SecurityPolicy.h"
     60 #include "public/platform/Platform.h"
     61 #include "public/platform/WebMimeRegistry.h"
     62 #include "public/platform/WebThreadedDataReceiver.h"
     63 #include "wtf/Assertions.h"
     64 #include "wtf/text/WTFString.h"
     65 
     66 namespace WebCore {
     67 
     68 static bool isArchiveMIMEType(const String& mimeType)
     69 {
     70     return mimeType == "multipart/related";
     71 }
     72 
     73 DocumentLoader::DocumentLoader(LocalFrame* frame, const ResourceRequest& req, const SubstituteData& substituteData)
     74     : m_frame(frame)
     75     , m_fetcher(ResourceFetcher::create(this))
     76     , m_originalRequest(req)
     77     , m_substituteData(substituteData)
     78     , m_request(req)
     79     , m_committed(false)
     80     , m_isClientRedirect(false)
     81     , m_replacesCurrentHistoryItem(false)
     82     , m_loadingMainResource(false)
     83     , m_timeOfLastDataReceived(0.0)
     84     , m_applicationCacheHost(adoptPtr(new ApplicationCacheHost(this)))
     85 {
     86 }
     87 
     88 FrameLoader* DocumentLoader::frameLoader() const
     89 {
     90     if (!m_frame)
     91         return 0;
     92     return &m_frame->loader();
     93 }
     94 
     95 ResourceLoader* DocumentLoader::mainResourceLoader() const
     96 {
     97     return m_mainResource ? m_mainResource->loader() : 0;
     98 }
     99 
    100 DocumentLoader::~DocumentLoader()
    101 {
    102     ASSERT(!m_frame || !isLoading());
    103     m_fetcher->clearDocumentLoader();
    104     clearMainResourceHandle();
    105 }
    106 
    107 unsigned long DocumentLoader::mainResourceIdentifier() const
    108 {
    109     return m_mainResource ? m_mainResource->identifier() : 0;
    110 }
    111 
    112 Document* DocumentLoader::document() const
    113 {
    114     if (m_frame && m_frame->loader().documentLoader() == this)
    115         return m_frame->document();
    116     return 0;
    117 }
    118 
    119 const ResourceRequest& DocumentLoader::originalRequest() const
    120 {
    121     return m_originalRequest;
    122 }
    123 
    124 const ResourceRequest& DocumentLoader::request() const
    125 {
    126     return m_request;
    127 }
    128 
    129 const KURL& DocumentLoader::url() const
    130 {
    131     return m_request.url();
    132 }
    133 
    134 void DocumentLoader::updateForSameDocumentNavigation(const KURL& newURL, SameDocumentNavigationSource sameDocumentNavigationSource)
    135 {
    136     KURL oldURL = m_request.url();
    137     m_originalRequest.setURL(newURL);
    138     m_request.setURL(newURL);
    139     if (sameDocumentNavigationSource == SameDocumentNavigationHistoryApi) {
    140         m_request.setHTTPMethod("GET");
    141         m_request.setHTTPBody(nullptr);
    142     }
    143     clearRedirectChain();
    144     if (m_isClientRedirect)
    145         appendRedirect(oldURL);
    146     appendRedirect(newURL);
    147 }
    148 
    149 const KURL& DocumentLoader::urlForHistory() const
    150 {
    151     return unreachableURL().isEmpty() ? url() : unreachableURL();
    152 }
    153 
    154 void DocumentLoader::setMainDocumentError(const ResourceError& error)
    155 {
    156     m_mainDocumentError = error;
    157 }
    158 
    159 void DocumentLoader::mainReceivedError(const ResourceError& error)
    160 {
    161     ASSERT(!error.isNull());
    162     ASSERT(!mainResourceLoader() || !mainResourceLoader()->defersLoading() || InspectorInstrumentation::isDebuggerPaused(m_frame));
    163     m_applicationCacheHost->failedLoadingMainResource();
    164     if (!frameLoader())
    165         return;
    166     setMainDocumentError(error);
    167     clearMainResourceLoader();
    168     frameLoader()->receivedMainResourceError(error);
    169     clearMainResourceHandle();
    170 }
    171 
    172 // Cancels the data source's pending loads.  Conceptually, a data source only loads
    173 // one document at a time, but one document may have many related resources.
    174 // stopLoading will stop all loads initiated by the data source,
    175 // but not loads initiated by child frames' data sources -- that's the WebFrame's job.
    176 void DocumentLoader::stopLoading()
    177 {
    178     RefPtr<LocalFrame> protectFrame(m_frame);
    179     RefPtr<DocumentLoader> protectLoader(this);
    180 
    181     // In some rare cases, calling FrameLoader::stopLoading could cause isLoading() to return false.
    182     // (This can happen when there's a single XMLHttpRequest currently loading and stopLoading causes it
    183     // to stop loading. Because of this, we need to save it so we don't return early.
    184     bool loading = isLoading();
    185 
    186     if (m_committed) {
    187         // Attempt to stop the frame if the document loader is loading, or if it is done loading but
    188         // still  parsing. Failure to do so can cause a world leak.
    189         Document* doc = m_frame->document();
    190 
    191         if (loading || doc->parsing())
    192             m_frame->loader().stopLoading();
    193     }
    194 
    195     if (!loading) {
    196         m_fetcher->stopFetching();
    197         return;
    198     }
    199 
    200     if (m_loadingMainResource) {
    201         // Stop the main resource loader and let it send the cancelled message.
    202         cancelMainResourceLoad(ResourceError::cancelledError(m_request.url()));
    203     } else if (m_fetcher->isFetching()) {
    204         // The main resource loader already finished loading. Set the cancelled error on the
    205         // document and let the resourceLoaders send individual cancelled messages below.
    206         setMainDocumentError(ResourceError::cancelledError(m_request.url()));
    207     } else {
    208         // If there are no resource loaders, we need to manufacture a cancelled message.
    209         // (A back/forward navigation has no resource loaders because its resources are cached.)
    210         mainReceivedError(ResourceError::cancelledError(m_request.url()));
    211     }
    212 
    213     m_fetcher->stopFetching();
    214 }
    215 
    216 void DocumentLoader::commitIfReady()
    217 {
    218     if (!m_committed) {
    219         m_committed = true;
    220         frameLoader()->commitProvisionalLoad();
    221     }
    222 }
    223 
    224 bool DocumentLoader::isLoading() const
    225 {
    226     if (document() && document()->hasActiveParser())
    227         return true;
    228 
    229     return m_loadingMainResource || m_fetcher->isFetching();
    230 }
    231 
    232 void DocumentLoader::notifyFinished(Resource* resource)
    233 {
    234     ASSERT_UNUSED(resource, m_mainResource == resource);
    235     ASSERT(m_mainResource);
    236 
    237     RefPtr<DocumentLoader> protect(this);
    238 
    239     if (!m_mainResource->errorOccurred() && !m_mainResource->wasCanceled()) {
    240         finishedLoading(m_mainResource->loadFinishTime());
    241         return;
    242     }
    243 
    244     mainReceivedError(m_mainResource->resourceError());
    245 }
    246 
    247 void DocumentLoader::finishedLoading(double finishTime)
    248 {
    249     ASSERT(!mainResourceLoader() || !mainResourceLoader()->defersLoading() || InspectorInstrumentation::isDebuggerPaused(m_frame));
    250 
    251     RefPtr<DocumentLoader> protect(this);
    252 
    253     double responseEndTime = finishTime;
    254     if (!responseEndTime)
    255         responseEndTime = m_timeOfLastDataReceived;
    256     if (!responseEndTime)
    257         responseEndTime = monotonicallyIncreasingTime();
    258     timing()->setResponseEnd(responseEndTime);
    259 
    260     commitIfReady();
    261     if (!frameLoader())
    262         return;
    263 
    264     if (!maybeCreateArchive()) {
    265         // If this is an empty document, it will not have actually been created yet. Commit dummy data so that
    266         // DocumentWriter::begin() gets called and creates the Document.
    267         if (!m_writer)
    268             commitData(0, 0);
    269     }
    270 
    271     endWriting(m_writer.get());
    272 
    273     if (!m_mainDocumentError.isNull())
    274         return;
    275     clearMainResourceLoader();
    276     if (!frameLoader()->stateMachine()->creatingInitialEmptyDocument())
    277         frameLoader()->checkLoadComplete();
    278 
    279     // If the document specified an application cache manifest, it violates the author's intent if we store it in the memory cache
    280     // and deny the appcache the chance to intercept it in the future, so remove from the memory cache.
    281     if (m_frame) {
    282         if (m_mainResource && m_frame->document()->hasAppCacheManifest())
    283             memoryCache()->remove(m_mainResource.get());
    284     }
    285     m_applicationCacheHost->finishedLoadingMainResource();
    286     clearMainResourceHandle();
    287 }
    288 
    289 bool DocumentLoader::isRedirectAfterPost(const ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
    290 {
    291     int status = redirectResponse.httpStatusCode();
    292     if (((status >= 301 && status <= 303) || status == 307)
    293         && m_originalRequest.httpMethod() == "POST")
    294         return true;
    295 
    296     return false;
    297 }
    298 
    299 bool DocumentLoader::shouldContinueForNavigationPolicy(const ResourceRequest& request)
    300 {
    301     // Don't ask if we are loading an empty URL.
    302     if (request.url().isEmpty() || m_substituteData.isValid())
    303         return true;
    304 
    305     // If we're loading content into a subframe, check against the parent's Content Security Policy
    306     // and kill the load if that check fails.
    307     // FIXME: CSP checks are broken for OOPI. For now, this policy always allows frames with a remote parent...
    308     if (m_frame->deprecatedLocalOwner() && !m_frame->deprecatedLocalOwner()->document().contentSecurityPolicy()->allowChildFrameFromSource(request.url())) {
    309         // Fire a load event, as timing attacks would otherwise reveal that the
    310         // frame was blocked. This way, it looks like every other cross-origin
    311         // page load.
    312         m_frame->document()->enforceSandboxFlags(SandboxOrigin);
    313         m_frame->owner()->dispatchLoad();
    314         return false;
    315     }
    316 
    317     NavigationPolicy policy = m_triggeringAction.policy();
    318     policy = frameLoader()->client()->decidePolicyForNavigation(request, this, policy);
    319     if (policy == NavigationPolicyCurrentTab)
    320         return true;
    321     if (policy == NavigationPolicyIgnore)
    322         return false;
    323     if (!LocalDOMWindow::allowPopUp(*m_frame) && !UserGestureIndicator::processingUserGesture())
    324         return false;
    325     frameLoader()->client()->loadURLExternally(request, policy);
    326     return false;
    327 }
    328 
    329 void DocumentLoader::redirectReceived(Resource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse)
    330 {
    331     ASSERT_UNUSED(resource, resource == m_mainResource);
    332     willSendRequest(request, redirectResponse);
    333 }
    334 
    335 void DocumentLoader::updateRequest(Resource* resource, const ResourceRequest& request)
    336 {
    337     ASSERT_UNUSED(resource, resource == m_mainResource);
    338     m_request = request;
    339 }
    340 
    341 static bool isFormSubmission(NavigationType type)
    342 {
    343     return type == NavigationTypeFormSubmitted || type == NavigationTypeFormResubmitted;
    344 }
    345 
    346 void DocumentLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
    347 {
    348     // Note that there are no asserts here as there are for the other callbacks. This is due to the
    349     // fact that this "callback" is sent when starting every load, and the state of callback
    350     // deferrals plays less of a part in this function in preventing the bad behavior deferring
    351     // callbacks is meant to prevent.
    352     ASSERT(!newRequest.isNull());
    353     if (isFormSubmission(m_triggeringAction.type()) && !m_frame->document()->contentSecurityPolicy()->allowFormAction(newRequest.url())) {
    354         cancelMainResourceLoad(ResourceError::cancelledError(newRequest.url()));
    355         return;
    356     }
    357 
    358     ASSERT(timing()->fetchStart());
    359     if (!redirectResponse.isNull()) {
    360         // If the redirecting url is not allowed to display content from the target origin,
    361         // then block the redirect.
    362         RefPtr<SecurityOrigin> redirectingOrigin = SecurityOrigin::create(redirectResponse.url());
    363         if (!redirectingOrigin->canDisplay(newRequest.url())) {
    364             FrameLoader::reportLocalLoadFailed(m_frame, newRequest.url().string());
    365             cancelMainResourceLoad(ResourceError::cancelledError(newRequest.url()));
    366             return;
    367         }
    368         timing()->addRedirect(redirectResponse.url(), newRequest.url());
    369     }
    370 
    371     // If we're fielding a redirect in response to a POST, force a load from origin, since
    372     // this is a common site technique to return to a page viewing some data that the POST
    373     // just modified.
    374     if (newRequest.cachePolicy() == UseProtocolCachePolicy && isRedirectAfterPost(newRequest, redirectResponse))
    375         newRequest.setCachePolicy(ReloadBypassingCache);
    376 
    377     // If this is a sub-frame, check for mixed content blocking against the top frame.
    378     if (m_frame->tree().parent()) {
    379         // FIXME: This does not yet work with out-of-process iframes.
    380         Frame* top = m_frame->tree().top();
    381         if (top->isLocalFrame() && !toLocalFrame(top)->loader().mixedContentChecker()->canRunInsecureContent(toLocalFrame(top)->document()->securityOrigin(), newRequest.url())) {
    382             cancelMainResourceLoad(ResourceError::cancelledError(newRequest.url()));
    383             return;
    384         }
    385     }
    386 
    387     m_request = newRequest;
    388 
    389     if (redirectResponse.isNull())
    390         return;
    391 
    392     appendRedirect(newRequest.url());
    393     frameLoader()->client()->dispatchDidReceiveServerRedirectForProvisionalLoad();
    394     if (!shouldContinueForNavigationPolicy(newRequest))
    395         cancelMainResourceLoad(ResourceError::cancelledError(m_request.url()));
    396 }
    397 
    398 static bool canShowMIMEType(const String& mimeType, Page* page)
    399 {
    400     if (blink::Platform::current()->mimeRegistry()->supportsMIMEType(mimeType) == blink::WebMimeRegistry::IsSupported)
    401         return true;
    402     PluginData* pluginData = page->pluginData();
    403     return !mimeType.isEmpty() && pluginData && pluginData->supportsMimeType(mimeType);
    404 }
    405 
    406 bool DocumentLoader::shouldContinueForResponse() const
    407 {
    408     if (m_substituteData.isValid())
    409         return true;
    410 
    411     int statusCode = m_response.httpStatusCode();
    412     if (statusCode == 204 || statusCode == 205) {
    413         // The server does not want us to replace the page contents.
    414         return false;
    415     }
    416 
    417     if (contentDispositionType(m_response.httpHeaderField("Content-Disposition")) == ContentDispositionAttachment) {
    418         // The server wants us to download instead of replacing the page contents.
    419         // Downloading is handled by the embedder, but we still get the initial
    420         // response so that we can ignore it and clean up properly.
    421         return false;
    422     }
    423 
    424     if (!canShowMIMEType(m_response.mimeType(), m_frame->page()))
    425         return false;
    426 
    427     // Prevent remote web archives from loading because they can claim to be from any domain and thus avoid cross-domain security checks.
    428     if (equalIgnoringCase("multipart/related", m_response.mimeType()) && !SchemeRegistry::shouldTreatURLSchemeAsLocal(m_request.url().protocol()))
    429         return false;
    430 
    431     return true;
    432 }
    433 
    434 void DocumentLoader::responseReceived(Resource* resource, const ResourceResponse& response)
    435 {
    436     ASSERT_UNUSED(resource, m_mainResource == resource);
    437     RefPtr<DocumentLoader> protect(this);
    438 
    439     m_applicationCacheHost->didReceiveResponseForMainResource(response);
    440 
    441     // The memory cache doesn't understand the application cache or its caching rules. So if a main resource is served
    442     // from the application cache, ensure we don't save the result for future use. All responses loaded
    443     // from appcache will have a non-zero appCacheID().
    444     if (response.appCacheID())
    445         memoryCache()->remove(m_mainResource.get());
    446 
    447     DEFINE_STATIC_LOCAL(AtomicString, xFrameOptionHeader, ("x-frame-options", AtomicString::ConstructFromLiteral));
    448     HTTPHeaderMap::const_iterator it = response.httpHeaderFields().find(xFrameOptionHeader);
    449     if (it != response.httpHeaderFields().end()) {
    450         String content = it->value;
    451         ASSERT(m_mainResource);
    452         unsigned long identifier = mainResourceIdentifier();
    453         ASSERT(identifier);
    454         if (frameLoader()->shouldInterruptLoadForXFrameOptions(content, response.url(), identifier)) {
    455             InspectorInstrumentation::continueAfterXFrameOptionsDenied(m_frame, this, identifier, response);
    456             String message = "Refused to display '" + response.url().elidedString() + "' in a frame because it set 'X-Frame-Options' to '" + content + "'.";
    457             frame()->document()->addConsoleMessageWithRequestIdentifier(SecurityMessageSource, ErrorMessageLevel, message, identifier);
    458             frame()->document()->enforceSandboxFlags(SandboxOrigin);
    459             if (FrameOwner* owner = frame()->owner())
    460                 owner->dispatchLoad();
    461 
    462             // The load event might have detached this frame. In that case, the load will already have been cancelled during detach.
    463             if (frameLoader())
    464                 cancelMainResourceLoad(ResourceError::cancelledError(m_request.url()));
    465             return;
    466         }
    467     }
    468 
    469     ASSERT(!mainResourceLoader() || !mainResourceLoader()->defersLoading());
    470 
    471     m_response = response;
    472 
    473     if (isArchiveMIMEType(m_response.mimeType()) && m_mainResource->dataBufferingPolicy() != BufferData)
    474         m_mainResource->setDataBufferingPolicy(BufferData);
    475 
    476     if (!shouldContinueForResponse()) {
    477         InspectorInstrumentation::continueWithPolicyIgnore(m_frame, this, m_mainResource->identifier(), m_response);
    478         cancelMainResourceLoad(ResourceError::cancelledError(m_request.url()));
    479         return;
    480     }
    481 
    482     if (m_response.isHTTP()) {
    483         int status = m_response.httpStatusCode();
    484         // FIXME: Fallback content only works if the parent is in the same processs.
    485         if ((status < 200 || status >= 300) && m_frame->owner()) {
    486             if (!m_frame->deprecatedLocalOwner()) {
    487                 ASSERT_NOT_REACHED();
    488             } else if (m_frame->deprecatedLocalOwner()->isObjectElement()) {
    489                 m_frame->deprecatedLocalOwner()->renderFallbackContent();
    490                 // object elements are no longer rendered after we fallback, so don't
    491                 // keep trying to process data from their load
    492                 cancelMainResourceLoad(ResourceError::cancelledError(m_request.url()));
    493             }
    494         }
    495     }
    496 }
    497 
    498 void DocumentLoader::ensureWriter(const AtomicString& mimeType, const KURL& overridingURL)
    499 {
    500     if (m_writer)
    501         return;
    502 
    503     const AtomicString& encoding = overrideEncoding().isNull() ? response().textEncodingName() : overrideEncoding();
    504     m_writer = createWriterFor(m_frame, 0, url(), mimeType, encoding, false, false);
    505     m_writer->setDocumentWasLoadedAsPartOfNavigation();
    506     // This should be set before receivedFirstData().
    507     if (!overridingURL.isEmpty())
    508         m_frame->document()->setBaseURLOverride(overridingURL);
    509 
    510     // Call receivedFirstData() exactly once per load.
    511     frameLoader()->receivedFirstData();
    512     m_frame->document()->maybeHandleHttpRefresh(m_response.httpHeaderField("Refresh"), Document::HttpRefreshFromHeader);
    513 }
    514 
    515 void DocumentLoader::commitData(const char* bytes, size_t length)
    516 {
    517     ensureWriter(m_response.mimeType());
    518     ASSERT(m_frame->document()->parsing());
    519     m_writer->addData(bytes, length);
    520 }
    521 
    522 void DocumentLoader::dataReceived(Resource* resource, const char* data, int length)
    523 {
    524     ASSERT(data);
    525     ASSERT(length);
    526     ASSERT_UNUSED(resource, resource == m_mainResource);
    527     ASSERT(!m_response.isNull());
    528     ASSERT(!mainResourceLoader() || !mainResourceLoader()->defersLoading());
    529 
    530     // Both unloading the old page and parsing the new page may execute JavaScript which destroys the datasource
    531     // by starting a new load, so retain temporarily.
    532     RefPtr<LocalFrame> protectFrame(m_frame);
    533     RefPtr<DocumentLoader> protectLoader(this);
    534 
    535     m_applicationCacheHost->mainResourceDataReceived(data, length);
    536     m_timeOfLastDataReceived = monotonicallyIncreasingTime();
    537 
    538     commitIfReady();
    539     if (!frameLoader())
    540         return;
    541     if (isArchiveMIMEType(response().mimeType()))
    542         return;
    543     commitData(data, length);
    544 
    545     // If we are sending data to MediaDocument, we should stop here
    546     // and cancel the request.
    547     if (m_frame && m_frame->document()->isMediaDocument())
    548         cancelMainResourceLoad(ResourceError::cancelledError(m_request.url()));
    549 }
    550 
    551 void DocumentLoader::clearRedirectChain()
    552 {
    553     m_redirectChain.clear();
    554 }
    555 
    556 void DocumentLoader::appendRedirect(const KURL& url)
    557 {
    558     m_redirectChain.append(url);
    559 }
    560 
    561 void DocumentLoader::detachFromFrame()
    562 {
    563     ASSERT(m_frame);
    564     RefPtr<LocalFrame> protectFrame(m_frame);
    565     RefPtr<DocumentLoader> protectLoader(this);
    566 
    567     // It never makes sense to have a document loader that is detached from its
    568     // frame have any loads active, so go ahead and kill all the loads.
    569     stopLoading();
    570 
    571     m_applicationCacheHost->setApplicationCache(0);
    572     InspectorInstrumentation::loaderDetachedFromFrame(m_frame, this);
    573     m_frame = 0;
    574 }
    575 
    576 void DocumentLoader::clearMainResourceLoader()
    577 {
    578     m_loadingMainResource = false;
    579 }
    580 
    581 void DocumentLoader::clearMainResourceHandle()
    582 {
    583     if (!m_mainResource)
    584         return;
    585     m_mainResource->removeClient(this);
    586     m_mainResource = 0;
    587 }
    588 
    589 bool DocumentLoader::maybeCreateArchive()
    590 {
    591     // Only the top-frame can load MHTML.
    592     if (m_frame->tree().parent())
    593         return false;
    594 
    595     // Give the archive machinery a crack at this document. If the MIME type is not an archive type, it will return 0.
    596     if (!isArchiveMIMEType(m_response.mimeType()))
    597         return false;
    598 
    599     ASSERT(m_mainResource);
    600     m_archive = MHTMLArchive::create(m_response.url(), m_mainResource->resourceBuffer());
    601     // Invalid MHTML.
    602     if (!m_archive || !m_archive->mainResource()) {
    603         m_archive.clear();
    604         return false;
    605     }
    606 
    607     addAllArchiveResources(m_archive.get());
    608     ArchiveResource* mainResource = m_archive->mainResource();
    609 
    610     // The origin is the MHTML file, we need to set the base URL to the document encoded in the MHTML so
    611     // relative URLs are resolved properly.
    612     ensureWriter(mainResource->mimeType(), m_archive->mainResource()->url());
    613 
    614     // The Document has now been created.
    615     document()->enforceSandboxFlags(SandboxAll);
    616 
    617     commitData(mainResource->data()->data(), mainResource->data()->size());
    618     return true;
    619 }
    620 
    621 void DocumentLoader::addAllArchiveResources(MHTMLArchive* archive)
    622 {
    623     ASSERT(archive);
    624     if (!m_archiveResourceCollection)
    625         m_archiveResourceCollection = adoptPtr(new ArchiveResourceCollection);
    626     m_archiveResourceCollection->addAllResources(archive);
    627 }
    628 
    629 void DocumentLoader::prepareSubframeArchiveLoadIfNeeded()
    630 {
    631     if (!m_frame->tree().parent() || !m_frame->tree().parent()->isLocalFrame())
    632         return;
    633 
    634     ArchiveResourceCollection* parentCollection = toLocalFrame(m_frame->tree().parent())->loader().documentLoader()->m_archiveResourceCollection.get();
    635     if (!parentCollection)
    636         return;
    637 
    638     m_archive = parentCollection->popSubframeArchive(m_frame->tree().uniqueName(), m_request.url());
    639 
    640     if (!m_archive)
    641         return;
    642     addAllArchiveResources(m_archive.get());
    643 
    644     ArchiveResource* mainResource = m_archive->mainResource();
    645     m_substituteData = SubstituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), KURL());
    646 }
    647 
    648 bool DocumentLoader::scheduleArchiveLoad(Resource* cachedResource, const ResourceRequest& request)
    649 {
    650     if (!m_archive)
    651         return false;
    652 
    653     ASSERT(m_archiveResourceCollection);
    654     ArchiveResource* archiveResource = m_archiveResourceCollection->archiveResourceForURL(request.url());
    655     if (!archiveResource) {
    656         cachedResource->error(Resource::LoadError);
    657         return true;
    658     }
    659 
    660     cachedResource->setLoading(true);
    661     cachedResource->responseReceived(archiveResource->response());
    662     SharedBuffer* data = archiveResource->data();
    663     if (data)
    664         cachedResource->appendData(data->data(), data->size());
    665     cachedResource->finish();
    666     return true;
    667 }
    668 
    669 const AtomicString& DocumentLoader::responseMIMEType() const
    670 {
    671     return m_response.mimeType();
    672 }
    673 
    674 const KURL& DocumentLoader::unreachableURL() const
    675 {
    676     return m_substituteData.failingURL();
    677 }
    678 
    679 void DocumentLoader::setDefersLoading(bool defers)
    680 {
    681     // Multiple frames may be loading the same main resource simultaneously. If deferral state changes,
    682     // each frame's DocumentLoader will try to send a setDefersLoading() to the same underlying ResourceLoader. Ensure only
    683     // the "owning" DocumentLoader does so, as setDefersLoading() is not resilient to setting the same value repeatedly.
    684     if (mainResourceLoader() && mainResourceLoader()->isLoadedBy(m_fetcher.get()))
    685         mainResourceLoader()->setDefersLoading(defers);
    686 
    687     m_fetcher->setDefersLoading(defers);
    688 }
    689 
    690 bool DocumentLoader::maybeLoadEmpty()
    691 {
    692     bool shouldLoadEmpty = !m_substituteData.isValid() && (m_request.url().isEmpty() || SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(m_request.url().protocol()));
    693     if (!shouldLoadEmpty)
    694         return false;
    695 
    696     if (m_request.url().isEmpty() && !frameLoader()->stateMachine()->creatingInitialEmptyDocument())
    697         m_request.setURL(blankURL());
    698     m_response = ResourceResponse(m_request.url(), "text/html", 0, nullAtom, String());
    699     finishedLoading(monotonicallyIncreasingTime());
    700     return true;
    701 }
    702 
    703 void DocumentLoader::startLoadingMainResource()
    704 {
    705     RefPtr<DocumentLoader> protect(this);
    706     m_mainDocumentError = ResourceError();
    707     timing()->markNavigationStart();
    708     ASSERT(!m_mainResource);
    709     ASSERT(!m_loadingMainResource);
    710     m_loadingMainResource = true;
    711 
    712     if (maybeLoadEmpty())
    713         return;
    714 
    715     ASSERT(timing()->navigationStart());
    716     ASSERT(!timing()->fetchStart());
    717     timing()->markFetchStart();
    718     willSendRequest(m_request, ResourceResponse());
    719 
    720     // willSendRequest() may lead to our LocalFrame being detached or cancelling the load via nulling the ResourceRequest.
    721     if (!m_frame || m_request.isNull())
    722         return;
    723 
    724     m_applicationCacheHost->willStartLoadingMainResource(m_request);
    725     prepareSubframeArchiveLoadIfNeeded();
    726 
    727     ResourceRequest request(m_request);
    728     DEFINE_STATIC_LOCAL(ResourceLoaderOptions, mainResourceLoadOptions,
    729         (SniffContent, DoNotBufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
    730     FetchRequest cachedResourceRequest(request, FetchInitiatorTypeNames::document, mainResourceLoadOptions);
    731     m_mainResource = m_fetcher->fetchMainResource(cachedResourceRequest, m_substituteData);
    732     if (!m_mainResource) {
    733         m_request = ResourceRequest();
    734         // If the load was aborted by clearing m_request, it's possible the ApplicationCacheHost
    735         // is now in a state where starting an empty load will be inconsistent. Replace it with
    736         // a new ApplicationCacheHost.
    737         m_applicationCacheHost = adoptPtr(new ApplicationCacheHost(this));
    738         maybeLoadEmpty();
    739         return;
    740     }
    741     m_mainResource->addClient(this);
    742 
    743     // A bunch of headers are set when the underlying ResourceLoader is created, and m_request needs to include those.
    744     if (mainResourceLoader())
    745         request = mainResourceLoader()->originalRequest();
    746     // If there was a fragment identifier on m_request, the cache will have stripped it. m_request should include
    747     // the fragment identifier, so add that back in.
    748     if (equalIgnoringFragmentIdentifier(m_request.url(), request.url()))
    749         request.setURL(m_request.url());
    750     m_request = request;
    751 }
    752 
    753 void DocumentLoader::cancelMainResourceLoad(const ResourceError& resourceError)
    754 {
    755     RefPtr<DocumentLoader> protect(this);
    756     ResourceError error = resourceError.isNull() ? ResourceError::cancelledError(m_request.url()) : resourceError;
    757 
    758     if (mainResourceLoader())
    759         mainResourceLoader()->cancel(error);
    760 
    761     mainReceivedError(error);
    762 }
    763 
    764 void DocumentLoader::attachThreadedDataReceiver(PassOwnPtr<blink::WebThreadedDataReceiver> threadedDataReceiver)
    765 {
    766     if (mainResourceLoader())
    767         mainResourceLoader()->attachThreadedDataReceiver(threadedDataReceiver);
    768 }
    769 
    770 void DocumentLoader::endWriting(DocumentWriter* writer)
    771 {
    772     ASSERT_UNUSED(writer, m_writer == writer);
    773     m_writer->end();
    774     m_writer.clear();
    775 }
    776 
    777 PassRefPtrWillBeRawPtr<DocumentWriter> DocumentLoader::createWriterFor(LocalFrame* frame, const Document* ownerDocument, const KURL& url, const AtomicString& mimeType, const AtomicString& encoding, bool userChosen, bool dispatch)
    778 {
    779     // Create a new document before clearing the frame, because it may need to
    780     // inherit an aliased security context.
    781     DocumentInit init(url, frame);
    782     init.withNewRegistrationContext();
    783 
    784     // In some rare cases, we'll re-used a LocalDOMWindow for a new Document. For example,
    785     // when a script calls window.open("..."), the browser gives JavaScript a window
    786     // synchronously but kicks off the load in the window asynchronously. Web sites
    787     // expect that modifications that they make to the window object synchronously
    788     // won't be blown away when the network load commits. To make that happen, we
    789     // "securely transition" the existing LocalDOMWindow to the Document that results from
    790     // the network load. See also SecurityContext::isSecureTransitionTo.
    791     bool shouldReuseDefaultView = frame->loader().stateMachine()->isDisplayingInitialEmptyDocument() && frame->document()->isSecureTransitionTo(url);
    792 
    793     frame->loader().clear();
    794 
    795     if (frame->document())
    796         frame->document()->prepareForDestruction();
    797 
    798     if (!shouldReuseDefaultView)
    799         frame->setDOMWindow(LocalDOMWindow::create(*frame));
    800 
    801     RefPtrWillBeRawPtr<Document> document = frame->domWindow()->installNewDocument(mimeType, init);
    802     if (ownerDocument) {
    803         document->setCookieURL(ownerDocument->cookieURL());
    804         document->setSecurityOrigin(ownerDocument->securityOrigin());
    805     }
    806 
    807     frame->loader().didBeginDocument(dispatch);
    808 
    809     return DocumentWriter::create(document.get(), mimeType, encoding, userChosen);
    810 }
    811 
    812 const AtomicString& DocumentLoader::mimeType() const
    813 {
    814     if (m_writer)
    815         return m_writer->mimeType();
    816     return m_response.mimeType();
    817 }
    818 
    819 void DocumentLoader::setUserChosenEncoding(const String& charset)
    820 {
    821     if (m_writer)
    822         m_writer->setUserChosenEncoding(charset);
    823 }
    824 
    825 // This is only called by ScriptController::executeScriptIfJavaScriptURL
    826 // and always contains the result of evaluating a javascript: url.
    827 // This is the <iframe src="javascript:'html'"> case.
    828 void DocumentLoader::replaceDocument(const String& source, Document* ownerDocument)
    829 {
    830     m_frame->loader().stopAllLoaders();
    831     m_writer = createWriterFor(m_frame, ownerDocument, m_frame->document()->url(), mimeType(), m_writer ? m_writer->encoding() : emptyAtom,  m_writer ? m_writer->encodingWasChosenByUser() : false, true);
    832     if (!source.isNull())
    833         m_writer->appendReplacingData(source);
    834     endWriting(m_writer.get());
    835 }
    836 
    837 } // namespace WebCore
    838