1 /* 2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "config.h" 30 #include "DocumentLoader.h" 31 32 #include "ApplicationCacheHost.h" 33 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size 34 #include "ArchiveFactory.h" 35 #include "ArchiveResourceCollection.h" 36 #else 37 #include "SubstituteResource.h" 38 #endif 39 #include "CachedPage.h" 40 #include "DocLoader.h" 41 #include "Document.h" 42 #include "Event.h" 43 #include "Frame.h" 44 #include "FrameLoader.h" 45 #include "FrameTree.h" 46 #include "HistoryItem.h" 47 #include "Logging.h" 48 #include "MainResourceLoader.h" 49 #include "Page.h" 50 #include "PlatformString.h" 51 #include "Settings.h" 52 #include "SharedBuffer.h" 53 #include "XMLTokenizer.h" 54 55 #include <wtf/Assertions.h> 56 #include <wtf/unicode/Unicode.h> 57 58 namespace WebCore { 59 60 static void cancelAll(const ResourceLoaderSet& loaders) 61 { 62 const ResourceLoaderSet copy = loaders; 63 ResourceLoaderSet::const_iterator end = copy.end(); 64 for (ResourceLoaderSet::const_iterator it = copy.begin(); it != end; ++it) 65 (*it)->cancel(); 66 } 67 68 static void setAllDefersLoading(const ResourceLoaderSet& loaders, bool defers) 69 { 70 const ResourceLoaderSet copy = loaders; 71 ResourceLoaderSet::const_iterator end = copy.end(); 72 for (ResourceLoaderSet::const_iterator it = copy.begin(); it != end; ++it) 73 (*it)->setDefersLoading(defers); 74 } 75 76 DocumentLoader::DocumentLoader(const ResourceRequest& req, const SubstituteData& substituteData) 77 : m_deferMainResourceDataLoad(true) 78 , m_frame(0) 79 , m_originalRequest(req) 80 , m_substituteData(substituteData) 81 , m_originalRequestCopy(req) 82 , m_request(req) 83 , m_committed(false) 84 , m_isStopping(false) 85 , m_loading(false) 86 , m_gotFirstByte(false) 87 , m_primaryLoadComplete(false) 88 , m_isClientRedirect(false) 89 , m_stopRecordingResponses(false) 90 , m_substituteResourceDeliveryTimer(this, &DocumentLoader::substituteResourceDeliveryTimerFired) 91 , m_didCreateGlobalHistoryEntry(false) 92 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 93 , m_applicationCacheHost(new ApplicationCacheHost(this)) 94 #endif 95 { 96 } 97 98 FrameLoader* DocumentLoader::frameLoader() const 99 { 100 if (!m_frame) 101 return 0; 102 return m_frame->loader(); 103 } 104 105 DocumentLoader::~DocumentLoader() 106 { 107 ASSERT(!m_frame || frameLoader()->activeDocumentLoader() != this || !frameLoader()->isLoading()); 108 } 109 110 PassRefPtr<SharedBuffer> DocumentLoader::mainResourceData() const 111 { 112 if (m_mainResourceData) 113 return m_mainResourceData; 114 if (m_mainResourceLoader) 115 return m_mainResourceLoader->resourceData(); 116 return 0; 117 } 118 119 const ResourceRequest& DocumentLoader::originalRequest() const 120 { 121 return m_originalRequest; 122 } 123 124 const ResourceRequest& DocumentLoader::originalRequestCopy() const 125 { 126 return m_originalRequestCopy; 127 } 128 129 const ResourceRequest& DocumentLoader::request() const 130 { 131 return m_request; 132 } 133 134 ResourceRequest& DocumentLoader::request() 135 { 136 return m_request; 137 } 138 139 const KURL& DocumentLoader::url() const 140 { 141 return request().url(); 142 } 143 144 void DocumentLoader::replaceRequestURLForSameDocumentNavigation(const KURL& url) 145 { 146 m_originalRequestCopy.setURL(url); 147 m_request.setURL(url); 148 } 149 150 void DocumentLoader::setRequest(const ResourceRequest& req) 151 { 152 // Replacing an unreachable URL with alternate content looks like a server-side 153 // redirect at this point, but we can replace a committed dataSource. 154 bool handlingUnreachableURL = false; 155 156 handlingUnreachableURL = m_substituteData.isValid() && !m_substituteData.failingURL().isEmpty(); 157 158 if (handlingUnreachableURL) 159 m_committed = false; 160 161 // We should never be getting a redirect callback after the data 162 // source is committed, except in the unreachable URL case. It 163 // would be a WebFoundation bug if it sent a redirect callback after commit. 164 ASSERT(!m_committed); 165 166 KURL oldURL = m_request.url(); 167 m_request = req; 168 169 // Only send webView:didReceiveServerRedirectForProvisionalLoadForFrame: if URL changed. 170 // Also, don't send it when replacing unreachable URLs with alternate content. 171 if (!handlingUnreachableURL && oldURL != req.url()) 172 frameLoader()->didReceiveServerRedirectForProvisionalLoadForFrame(); 173 } 174 175 void DocumentLoader::setMainDocumentError(const ResourceError& error) 176 { 177 m_mainDocumentError = error; 178 frameLoader()->setMainDocumentError(this, error); 179 } 180 181 void DocumentLoader::clearErrors() 182 { 183 m_mainDocumentError = ResourceError(); 184 } 185 186 void DocumentLoader::mainReceivedError(const ResourceError& error, bool isComplete) 187 { 188 ASSERT(!error.isNull()); 189 190 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 191 m_applicationCacheHost->failedLoadingMainResource(); 192 #endif 193 194 if (!frameLoader()) 195 return; 196 setMainDocumentError(error); 197 if (isComplete) 198 frameLoader()->mainReceivedCompleteError(this, error); 199 } 200 201 // Cancels the data source's pending loads. Conceptually, a data source only loads 202 // one document at a time, but one document may have many related resources. 203 // stopLoading will stop all loads initiated by the data source, 204 // but not loads initiated by child frames' data sources -- that's the WebFrame's job. 205 void DocumentLoader::stopLoading(DatabasePolicy databasePolicy) 206 { 207 // In some rare cases, calling FrameLoader::stopLoading could set m_loading to false. 208 // (This can happen when there's a single XMLHttpRequest currently loading and stopLoading causes it 209 // to stop loading. Because of this, we need to save it so we don't return early. 210 bool loading = m_loading; 211 212 if (m_committed) { 213 // Attempt to stop the frame if the document loader is loading, or if it is done loading but 214 // still parsing. Failure to do so can cause a world leak. 215 Document* doc = m_frame->document(); 216 217 if (loading || doc->parsing()) 218 m_frame->loader()->stopLoading(UnloadEventPolicyNone, databasePolicy); 219 } 220 221 // Always cancel multipart loaders 222 cancelAll(m_multipartSubresourceLoaders); 223 224 if (!loading) 225 return; 226 227 RefPtr<Frame> protectFrame(m_frame); 228 RefPtr<DocumentLoader> protectLoader(this); 229 230 m_isStopping = true; 231 232 FrameLoader* frameLoader = DocumentLoader::frameLoader(); 233 234 if (m_mainResourceLoader) 235 // Stop the main resource loader and let it send the cancelled message. 236 m_mainResourceLoader->cancel(); 237 else if (!m_subresourceLoaders.isEmpty()) 238 // The main resource loader already finished loading. Set the cancelled error on the 239 // document and let the subresourceLoaders send individual cancelled messages below. 240 setMainDocumentError(frameLoader->cancelledError(m_request)); 241 else 242 // If there are no resource loaders, we need to manufacture a cancelled message. 243 // (A back/forward navigation has no resource loaders because its resources are cached.) 244 mainReceivedError(frameLoader->cancelledError(m_request), true); 245 246 stopLoadingSubresources(); 247 stopLoadingPlugIns(); 248 249 m_isStopping = false; 250 } 251 252 void DocumentLoader::setupForReplace() 253 { 254 frameLoader()->setupForReplace(); 255 m_committed = false; 256 } 257 258 void DocumentLoader::commitIfReady() 259 { 260 if (m_gotFirstByte && !m_committed) { 261 m_committed = true; 262 frameLoader()->commitProvisionalLoad(0); 263 } 264 } 265 266 void DocumentLoader::finishedLoading() 267 { 268 m_gotFirstByte = true; 269 commitIfReady(); 270 if (FrameLoader* loader = frameLoader()) { 271 loader->finishedLoadingDocument(this); 272 loader->end(); 273 } 274 } 275 276 void DocumentLoader::commitLoad(const char* data, int length) 277 { 278 // Both unloading the old page and parsing the new page may execute JavaScript which destroys the datasource 279 // by starting a new load, so retain temporarily. 280 RefPtr<DocumentLoader> protect(this); 281 282 commitIfReady(); 283 if (FrameLoader* frameLoader = DocumentLoader::frameLoader()) 284 frameLoader->committedLoad(this, data, length); 285 } 286 287 bool DocumentLoader::doesProgressiveLoad(const String& MIMEType) const 288 { 289 return !frameLoader()->isReplacing() || MIMEType == "text/html"; 290 } 291 292 void DocumentLoader::receivedData(const char* data, int length) 293 { 294 m_gotFirstByte = true; 295 if (doesProgressiveLoad(m_response.mimeType())) 296 commitLoad(data, length); 297 } 298 299 void DocumentLoader::setupForReplaceByMIMEType(const String& newMIMEType) 300 { 301 if (!m_gotFirstByte) 302 return; 303 304 String oldMIMEType = m_response.mimeType(); 305 306 if (!doesProgressiveLoad(oldMIMEType)) { 307 frameLoader()->revertToProvisional(this); 308 setupForReplace(); 309 RefPtr<SharedBuffer> resourceData = mainResourceData(); 310 commitLoad(resourceData->data(), resourceData->size()); 311 } 312 313 frameLoader()->finishedLoadingDocument(this); 314 m_frame->loader()->end(); 315 316 frameLoader()->setReplacing(); 317 m_gotFirstByte = false; 318 319 if (doesProgressiveLoad(newMIMEType)) { 320 frameLoader()->revertToProvisional(this); 321 setupForReplace(); 322 } 323 324 stopLoadingSubresources(); 325 stopLoadingPlugIns(); 326 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size 327 clearArchiveResources(); 328 #endif 329 } 330 331 void DocumentLoader::updateLoading() 332 { 333 if (!m_frame) { 334 setLoading(false); 335 return; 336 } 337 ASSERT(this == frameLoader()->activeDocumentLoader()); 338 setLoading(frameLoader()->isLoading()); 339 } 340 341 void DocumentLoader::setFrame(Frame* frame) 342 { 343 if (m_frame == frame) 344 return; 345 ASSERT(frame && !m_frame); 346 m_frame = frame; 347 attachToFrame(); 348 } 349 350 void DocumentLoader::attachToFrame() 351 { 352 ASSERT(m_frame); 353 } 354 355 void DocumentLoader::detachFromFrame() 356 { 357 ASSERT(m_frame); 358 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 359 m_applicationCacheHost->setDOMApplicationCache(0); 360 #endif 361 m_frame = 0; 362 } 363 364 void DocumentLoader::prepareForLoadStart() 365 { 366 ASSERT(!m_isStopping); 367 setPrimaryLoadComplete(false); 368 ASSERT(frameLoader()); 369 clearErrors(); 370 371 setLoading(true); 372 373 frameLoader()->prepareForLoadStart(); 374 } 375 376 void DocumentLoader::setPrimaryLoadComplete(bool flag) 377 { 378 m_primaryLoadComplete = flag; 379 if (flag) { 380 if (m_mainResourceLoader) { 381 m_mainResourceData = m_mainResourceLoader->resourceData(); 382 m_mainResourceLoader = 0; 383 } 384 385 if (this == frameLoader()->activeDocumentLoader()) 386 updateLoading(); 387 } 388 } 389 390 bool DocumentLoader::isLoadingInAPISense() const 391 { 392 // Once a frame has loaded, we no longer need to consider subresources, 393 // but we still need to consider subframes. 394 if (frameLoader()->state() != FrameStateComplete) { 395 if (!m_primaryLoadComplete && isLoading()) 396 return true; 397 if (!m_subresourceLoaders.isEmpty()) 398 return true; 399 Document* doc = m_frame->document(); 400 if (doc->docLoader()->requestCount()) 401 return true; 402 if (Tokenizer* tok = doc->tokenizer()) 403 if (tok->processingData()) 404 return true; 405 } 406 return frameLoader()->subframeIsLoading(); 407 } 408 409 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size 410 void DocumentLoader::addAllArchiveResources(Archive* archive) 411 { 412 if (!m_archiveResourceCollection) 413 m_archiveResourceCollection.set(new ArchiveResourceCollection); 414 415 ASSERT(archive); 416 if (!archive) 417 return; 418 419 m_archiveResourceCollection->addAllResources(archive); 420 } 421 422 // FIXME: Adding a resource directly to a DocumentLoader/ArchiveResourceCollection seems like bad design, but is API some apps rely on. 423 // Can we change the design in a manner that will let us deprecate that API without reducing functionality of those apps? 424 void DocumentLoader::addArchiveResource(PassRefPtr<ArchiveResource> resource) 425 { 426 if (!m_archiveResourceCollection) 427 m_archiveResourceCollection.set(new ArchiveResourceCollection); 428 429 ASSERT(resource); 430 if (!resource) 431 return; 432 433 m_archiveResourceCollection->addResource(resource); 434 } 435 436 ArchiveResource* DocumentLoader::archiveResourceForURL(const KURL& url) const 437 { 438 if (!m_archiveResourceCollection) 439 return 0; 440 441 ArchiveResource* resource = m_archiveResourceCollection->archiveResourceForURL(url); 442 443 return resource && !resource->shouldIgnoreWhenUnarchiving() ? resource : 0; 444 } 445 446 PassRefPtr<Archive> DocumentLoader::popArchiveForSubframe(const String& frameName) 447 { 448 return m_archiveResourceCollection ? m_archiveResourceCollection->popSubframeArchive(frameName) : 0; 449 } 450 451 void DocumentLoader::clearArchiveResources() 452 { 453 m_archiveResourceCollection.clear(); 454 m_substituteResourceDeliveryTimer.stop(); 455 } 456 457 void DocumentLoader::setParsedArchiveData(PassRefPtr<SharedBuffer> data) 458 { 459 m_parsedArchiveData = data; 460 } 461 462 SharedBuffer* DocumentLoader::parsedArchiveData() const 463 { 464 return m_parsedArchiveData.get(); 465 } 466 467 PassRefPtr<ArchiveResource> DocumentLoader::mainResource() const 468 { 469 const ResourceResponse& r = response(); 470 RefPtr<SharedBuffer> mainResourceBuffer = mainResourceData(); 471 if (!mainResourceBuffer) 472 mainResourceBuffer = SharedBuffer::create(); 473 474 return ArchiveResource::create(mainResourceBuffer, r.url(), r.mimeType(), r.textEncodingName(), frame()->tree()->name()); 475 } 476 477 PassRefPtr<ArchiveResource> DocumentLoader::subresource(const KURL& url) const 478 { 479 if (!isCommitted()) 480 return 0; 481 482 CachedResource* resource = m_frame->document()->docLoader()->cachedResource(url); 483 if (!resource || !resource->isLoaded()) 484 return archiveResourceForURL(url); 485 486 // FIXME: This has the side effect of making the resource non-purgeable. 487 // It would be better if it didn't have this permanent effect. 488 if (!resource->makePurgeable(false)) 489 return 0; 490 491 RefPtr<SharedBuffer> data = resource->data(); 492 if (!data) 493 return 0; 494 495 return ArchiveResource::create(data.release(), url, resource->response()); 496 } 497 498 void DocumentLoader::getSubresources(Vector<PassRefPtr<ArchiveResource> >& subresources) const 499 { 500 if (!isCommitted()) 501 return; 502 503 Document* document = m_frame->document(); 504 505 const DocLoader::DocumentResourceMap& allResources = document->docLoader()->allCachedResources(); 506 DocLoader::DocumentResourceMap::const_iterator end = allResources.end(); 507 for (DocLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) { 508 RefPtr<ArchiveResource> subresource = this->subresource(KURL(ParsedURLString, it->second->url())); 509 if (subresource) 510 subresources.append(subresource.release()); 511 } 512 513 return; 514 } 515 #endif 516 517 void DocumentLoader::deliverSubstituteResourcesAfterDelay() 518 { 519 if (m_pendingSubstituteResources.isEmpty()) 520 return; 521 ASSERT(m_frame && m_frame->page()); 522 if (m_frame->page()->defersLoading()) 523 return; 524 if (!m_substituteResourceDeliveryTimer.isActive()) 525 m_substituteResourceDeliveryTimer.startOneShot(0); 526 } 527 528 void DocumentLoader::substituteResourceDeliveryTimerFired(Timer<DocumentLoader>*) 529 { 530 if (m_pendingSubstituteResources.isEmpty()) 531 return; 532 ASSERT(m_frame && m_frame->page()); 533 if (m_frame->page()->defersLoading()) 534 return; 535 536 SubstituteResourceMap copy; 537 copy.swap(m_pendingSubstituteResources); 538 539 SubstituteResourceMap::const_iterator end = copy.end(); 540 for (SubstituteResourceMap::const_iterator it = copy.begin(); it != end; ++it) { 541 RefPtr<ResourceLoader> loader = it->first; 542 SubstituteResource* resource = it->second.get(); 543 544 if (resource) { 545 SharedBuffer* data = resource->data(); 546 547 loader->didReceiveResponse(resource->response()); 548 loader->didReceiveData(data->data(), data->size(), data->size(), true); 549 loader->didFinishLoading(); 550 } else { 551 // A null resource means that we should fail the load. 552 // FIXME: Maybe we should use another error here - something like "not in cache". 553 loader->didFail(loader->cannotShowURLError()); 554 } 555 } 556 } 557 558 #ifndef NDEBUG 559 bool DocumentLoader::isSubstituteLoadPending(ResourceLoader* loader) const 560 { 561 return m_pendingSubstituteResources.contains(loader); 562 } 563 #endif 564 565 void DocumentLoader::cancelPendingSubstituteLoad(ResourceLoader* loader) 566 { 567 if (m_pendingSubstituteResources.isEmpty()) 568 return; 569 m_pendingSubstituteResources.remove(loader); 570 if (m_pendingSubstituteResources.isEmpty()) 571 m_substituteResourceDeliveryTimer.stop(); 572 } 573 574 #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size 575 bool DocumentLoader::scheduleArchiveLoad(ResourceLoader* loader, const ResourceRequest& request, const KURL& originalURL) 576 { 577 ArchiveResource* resource = 0; 578 579 if (request.url() == originalURL) 580 resource = archiveResourceForURL(originalURL); 581 582 if (!resource) { 583 // WebArchiveDebugMode means we fail loads instead of trying to fetch them from the network if they're not in the archive. 584 bool shouldFailLoad = m_frame->settings()->webArchiveDebugModeEnabled() && ArchiveFactory::isArchiveMimeType(responseMIMEType()); 585 586 if (!shouldFailLoad) 587 return false; 588 } 589 590 m_pendingSubstituteResources.set(loader, resource); 591 deliverSubstituteResourcesAfterDelay(); 592 593 return true; 594 } 595 #endif 596 597 void DocumentLoader::addResponse(const ResourceResponse& r) 598 { 599 if (!m_stopRecordingResponses) 600 m_responses.append(r); 601 } 602 603 void DocumentLoader::stopRecordingResponses() 604 { 605 m_stopRecordingResponses = true; 606 } 607 608 void DocumentLoader::setTitle(const String& title) 609 { 610 if (title.isEmpty()) 611 return; 612 613 if (m_pageTitle != title) { 614 frameLoader()->willChangeTitle(this); 615 m_pageTitle = title; 616 frameLoader()->didChangeTitle(this); 617 } 618 } 619 620 KURL DocumentLoader::urlForHistory() const 621 { 622 // Return the URL to be used for history and B/F list. 623 // Returns nil for WebDataProtocol URLs that aren't alternates 624 // for unreachable URLs, because these can't be stored in history. 625 if (m_substituteData.isValid()) 626 return unreachableURL(); 627 628 return m_originalRequestCopy.url(); 629 } 630 631 bool DocumentLoader::urlForHistoryReflectsFailure() const 632 { 633 return m_substituteData.isValid() || m_response.httpStatusCode() >= 400; 634 } 635 636 const KURL& DocumentLoader::originalURL() const 637 { 638 return m_originalRequestCopy.url(); 639 } 640 641 const KURL& DocumentLoader::requestURL() const 642 { 643 return request().url(); 644 } 645 646 const KURL& DocumentLoader::responseURL() const 647 { 648 return m_response.url(); 649 } 650 651 const String& DocumentLoader::responseMIMEType() const 652 { 653 return m_response.mimeType(); 654 } 655 656 const KURL& DocumentLoader::unreachableURL() const 657 { 658 return m_substituteData.failingURL(); 659 } 660 661 void DocumentLoader::setDefersLoading(bool defers) 662 { 663 if (m_mainResourceLoader) 664 m_mainResourceLoader->setDefersLoading(defers); 665 setAllDefersLoading(m_subresourceLoaders, defers); 666 setAllDefersLoading(m_plugInStreamLoaders, defers); 667 if (!defers) 668 deliverSubstituteResourcesAfterDelay(); 669 } 670 671 void DocumentLoader::stopLoadingPlugIns() 672 { 673 cancelAll(m_plugInStreamLoaders); 674 } 675 676 void DocumentLoader::stopLoadingSubresources() 677 { 678 cancelAll(m_subresourceLoaders); 679 } 680 681 void DocumentLoader::addSubresourceLoader(ResourceLoader* loader) 682 { 683 m_subresourceLoaders.add(loader); 684 setLoading(true); 685 } 686 687 void DocumentLoader::removeSubresourceLoader(ResourceLoader* loader) 688 { 689 m_subresourceLoaders.remove(loader); 690 updateLoading(); 691 if (Frame* frame = m_frame) 692 frame->loader()->checkLoadComplete(); 693 } 694 695 void DocumentLoader::addPlugInStreamLoader(ResourceLoader* loader) 696 { 697 m_plugInStreamLoaders.add(loader); 698 setLoading(true); 699 } 700 701 void DocumentLoader::removePlugInStreamLoader(ResourceLoader* loader) 702 { 703 m_plugInStreamLoaders.remove(loader); 704 updateLoading(); 705 } 706 707 bool DocumentLoader::isLoadingMainResource() const 708 { 709 return !!m_mainResourceLoader; 710 } 711 712 bool DocumentLoader::isLoadingSubresources() const 713 { 714 return !m_subresourceLoaders.isEmpty(); 715 } 716 717 bool DocumentLoader::isLoadingPlugIns() const 718 { 719 return !m_plugInStreamLoaders.isEmpty(); 720 } 721 722 bool DocumentLoader::isLoadingMultipartContent() const 723 { 724 return m_mainResourceLoader && m_mainResourceLoader->isLoadingMultipartContent(); 725 } 726 727 bool DocumentLoader::startLoadingMainResource(unsigned long identifier) 728 { 729 ASSERT(!m_mainResourceLoader); 730 m_mainResourceLoader = MainResourceLoader::create(m_frame); 731 m_mainResourceLoader->setIdentifier(identifier); 732 733 // FIXME: Is there any way the extra fields could have not been added by now? 734 // If not, it would be great to remove this line of code. 735 frameLoader()->addExtraFieldsToMainResourceRequest(m_request); 736 737 if (!m_mainResourceLoader->load(m_request, m_substituteData)) { 738 // FIXME: If this should really be caught, we should just ASSERT this doesn't happen; 739 // should it be caught by other parts of WebKit or other parts of the app? 740 LOG_ERROR("could not create WebResourceHandle for URL %s -- should be caught by policy handler level", m_request.url().string().ascii().data()); 741 m_mainResourceLoader = 0; 742 return false; 743 } 744 745 return true; 746 } 747 748 void DocumentLoader::cancelMainResourceLoad(const ResourceError& error) 749 { 750 m_mainResourceLoader->cancel(error); 751 } 752 753 void DocumentLoader::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader) 754 { 755 m_multipartSubresourceLoaders.add(loader); 756 m_subresourceLoaders.remove(loader); 757 updateLoading(); 758 if (Frame* frame = m_frame) 759 frame->loader()->checkLoadComplete(); 760 } 761 762 void DocumentLoader::iconLoadDecisionAvailable() 763 { 764 if (m_frame) 765 m_frame->loader()->iconLoadDecisionAvailable(); 766 } 767 768 } 769