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