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