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