1/* 2 * Copyright (C) 2006, 2007, 2010, 2011 Apple Inc. All rights reserved. 3 * (C) 2007 Graham Dennis (graham.dennis@gmail.com) 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 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 "ResourceLoader.h" 32 33#include "ApplicationCacheHost.h" 34#include "AsyncFileStream.h" 35#include "AuthenticationChallenge.h" 36#include "DocumentLoader.h" 37#include "Frame.h" 38#include "FrameLoader.h" 39#include "FrameLoaderClient.h" 40#include "InspectorInstrumentation.h" 41#include "LoaderStrategy.h" 42#include "Page.h" 43#include "PlatformStrategies.h" 44#include "ProgressTracker.h" 45#include "ResourceBuffer.h" 46#include "ResourceError.h" 47#include "ResourceHandle.h" 48#include "ResourceLoadScheduler.h" 49#include "SecurityOrigin.h" 50#include "Settings.h" 51#include "SharedBuffer.h" 52#include <wtf/Ref.h> 53 54namespace WebCore { 55 56ResourceLoader::ResourceLoader(Frame* frame, ResourceLoaderOptions options) 57 : m_frame(frame) 58 , m_documentLoader(frame->loader().activeDocumentLoader()) 59 , m_identifier(0) 60 , m_reachedTerminalState(false) 61 , m_notifiedLoadComplete(false) 62 , m_cancellationStatus(NotCancelled) 63 , m_defersLoading(frame->page()->defersLoading()) 64 , m_options(options) 65{ 66} 67 68ResourceLoader::~ResourceLoader() 69{ 70 ASSERT(m_reachedTerminalState); 71} 72 73void ResourceLoader::releaseResources() 74{ 75 ASSERT(!m_reachedTerminalState); 76 77 // It's possible that when we release the handle, it will be 78 // deallocated and release the last reference to this object. 79 // We need to retain to avoid accessing the object after it 80 // has been deallocated and also to avoid reentering this method. 81 Ref<ResourceLoader> protect(*this); 82 83 m_frame = 0; 84 m_documentLoader = 0; 85 86 // We need to set reachedTerminalState to true before we release 87 // the resources to prevent a double dealloc of WebView <rdar://problem/4372628> 88 m_reachedTerminalState = true; 89 90 platformStrategies()->loaderStrategy()->resourceLoadScheduler()->remove(this); 91 m_identifier = 0; 92 93 if (m_handle) { 94 // Clear out the ResourceHandle's client so that it doesn't try to call 95 // us back after we release it, unless it has been replaced by someone else. 96 if (m_handle->client() == this) 97 m_handle->setClient(0); 98 m_handle = 0; 99 } 100 101 m_resourceData = 0; 102 m_deferredRequest = ResourceRequest(); 103} 104 105bool ResourceLoader::init(const ResourceRequest& r) 106{ 107 ASSERT(!m_handle); 108 ASSERT(m_request.isNull()); 109 ASSERT(m_deferredRequest.isNull()); 110 ASSERT(!m_documentLoader->isSubstituteLoadPending(this)); 111 112 ResourceRequest clientRequest(r); 113 114#if PLATFORM(IOS) 115 // If the documentLoader was detached while this ResourceLoader was waiting its turn 116 // in ResourceLoadScheduler queue, don't continue. 117 if (!m_documentLoader->frame()) { 118 cancel(); 119 return false; 120 } 121#endif 122 123 m_defersLoading = m_frame->page()->defersLoading(); 124 if (m_options.securityCheck() == DoSecurityCheck && !m_frame->document()->securityOrigin()->canDisplay(clientRequest.url())) { 125 FrameLoader::reportLocalLoadFailed(m_frame.get(), clientRequest.url().string()); 126 releaseResources(); 127 return false; 128 } 129 130 // https://bugs.webkit.org/show_bug.cgi?id=26391 131 // The various plug-in implementations call directly to ResourceLoader::load() instead of piping requests 132 // through FrameLoader. As a result, they miss the FrameLoader::addExtraFieldsToRequest() step which sets 133 // up the 1st party for cookies URL. Until plug-in implementations can be reigned in to pipe through that 134 // method, we need to make sure there is always a 1st party for cookies set. 135 if (clientRequest.firstPartyForCookies().isNull()) { 136 if (Document* document = m_frame->document()) 137 clientRequest.setFirstPartyForCookies(document->firstPartyForCookies()); 138 } 139 140 willSendRequest(clientRequest, ResourceResponse()); 141 142#if PLATFORM(IOS) 143 // If this ResourceLoader was stopped as a result of willSendRequest, bail out. 144 if (m_reachedTerminalState) 145 return false; 146#endif 147 148 if (clientRequest.isNull()) { 149 cancel(); 150 return false; 151 } 152 153 m_originalRequest = m_request = clientRequest; 154 return true; 155} 156 157void ResourceLoader::start() 158{ 159 ASSERT(!m_handle); 160 ASSERT(!m_request.isNull()); 161 ASSERT(m_deferredRequest.isNull()); 162 163#if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML) 164 if (m_documentLoader->scheduleArchiveLoad(this, m_request)) 165 return; 166#endif 167 168 if (m_documentLoader->applicationCacheHost()->maybeLoadResource(this, m_request, m_request.url())) 169 return; 170 171 if (m_defersLoading) { 172 m_deferredRequest = m_request; 173 return; 174 } 175 176 if (!m_reachedTerminalState) 177 m_handle = ResourceHandle::create(m_frame->loader().networkingContext(), m_request, this, m_defersLoading, m_options.sniffContent() == SniffContent); 178} 179 180void ResourceLoader::setDefersLoading(bool defers) 181{ 182 m_defersLoading = defers; 183 if (m_handle) 184 m_handle->setDefersLoading(defers); 185 if (!defers && !m_deferredRequest.isNull()) { 186 m_request = m_deferredRequest; 187 m_deferredRequest = ResourceRequest(); 188 start(); 189 } 190 191 platformStrategies()->loaderStrategy()->resourceLoadScheduler()->setDefersLoading(this, defers); 192} 193 194FrameLoader* ResourceLoader::frameLoader() const 195{ 196 if (!m_frame) 197 return 0; 198 return &m_frame->loader(); 199} 200 201void ResourceLoader::setDataBufferingPolicy(DataBufferingPolicy dataBufferingPolicy) 202{ 203 m_options.setDataBufferingPolicy(dataBufferingPolicy); 204 205 // Reset any already buffered data 206 if (dataBufferingPolicy == DoNotBufferData) 207 m_resourceData = 0; 208} 209 210void ResourceLoader::willSwitchToSubstituteResource() 211{ 212 ASSERT(!m_documentLoader->isSubstituteLoadPending(this)); 213 platformStrategies()->loaderStrategy()->resourceLoadScheduler()->remove(this); 214 if (m_handle) 215 m_handle->cancel(); 216} 217 218void ResourceLoader::addDataOrBuffer(const char* data, unsigned length, SharedBuffer* buffer, DataPayloadType dataPayloadType) 219{ 220 if (m_options.dataBufferingPolicy() == DoNotBufferData) 221 return; 222 223 if (dataPayloadType == DataPayloadWholeResource) { 224 m_resourceData = buffer ? ResourceBuffer::adoptSharedBuffer(buffer) : ResourceBuffer::create(data, length); 225 return; 226 } 227 228 if (!m_resourceData) 229 m_resourceData = buffer ? ResourceBuffer::adoptSharedBuffer(buffer) : ResourceBuffer::create(data, length); 230 else { 231 if (buffer) 232 m_resourceData->append(buffer); 233 else 234 m_resourceData->append(data, length); 235 } 236} 237 238void ResourceLoader::clearResourceData() 239{ 240 if (m_resourceData) 241 m_resourceData->clear(); 242} 243 244bool ResourceLoader::isSubresourceLoader() 245{ 246 return false; 247} 248 249void ResourceLoader::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse) 250{ 251 // Protect this in this delegate method since the additional processing can do 252 // anything including possibly derefing this; one example of this is Radar 3266216. 253 Ref<ResourceLoader> protect(*this); 254 255 ASSERT(!m_reachedTerminalState); 256 257#if PLATFORM(IOS) 258 // Ensure an identifier is always set. This ensures that this assetion is not hit: 259 // <rdar://problem/11059794> ASSERTION FAILED: !HashTranslator::equal(KeyTraits::emptyValue(), key) in WebFrameLoaderClient::canAuthenticateAgainstProtectionSpace loading the attached web archive 260 // This is not needed in WebKit2, as it doesn't use m_identifier in WebFrameLoaderClient::canAuthenticateAgainstProtectionSpace 261 if (!m_identifier) { 262 m_identifier = m_frame->page()->progress().createUniqueIdentifier(); 263 frameLoader()->notifier().assignIdentifierToInitialRequest(m_identifier, documentLoader(), request); 264 265 // If this ResourceLoader was stopped as a result of assignIdentifierToInitialRequest, bail out 266 if (m_reachedTerminalState) 267 return; 268 } 269#endif 270 271 // We need a resource identifier for all requests, even if FrameLoader is never going to see it (such as with CORS preflight requests). 272 bool createdResourceIdentifier = false; 273 if (!m_identifier) { 274 m_identifier = m_frame->page()->progress().createUniqueIdentifier(); 275 createdResourceIdentifier = true; 276 } 277 278 if (m_options.sendLoadCallbacks() == SendCallbacks) { 279 if (createdResourceIdentifier) 280 frameLoader()->notifier().assignIdentifierToInitialRequest(m_identifier, documentLoader(), request); 281 282 frameLoader()->notifier().willSendRequest(this, request, redirectResponse); 283 } 284#if ENABLE(INSPECTOR) 285 else 286 InspectorInstrumentation::willSendRequest(m_frame.get(), m_identifier, m_frame->loader().documentLoader(), request, redirectResponse); 287#endif 288 289 if (!redirectResponse.isNull()) 290 platformStrategies()->loaderStrategy()->resourceLoadScheduler()->crossOriginRedirectReceived(this, request.url()); 291 292 m_request = request; 293 294 if (!redirectResponse.isNull() && !m_documentLoader->isCommitted()) 295 frameLoader()->client().dispatchDidReceiveServerRedirectForProvisionalLoad(); 296} 297 298void ResourceLoader::didSendData(unsigned long long, unsigned long long) 299{ 300} 301 302void ResourceLoader::didReceiveResponse(const ResourceResponse& r) 303{ 304 ASSERT(!m_reachedTerminalState); 305 306 // Protect this in this delegate method since the additional processing can do 307 // anything including possibly derefing this; one example of this is Radar 3266216. 308 Ref<ResourceLoader> protect(*this); 309 310 m_response = r; 311 312 if (FormData* data = m_request.httpBody()) 313 data->removeGeneratedFilesIfNeeded(); 314 315 if (m_options.sendLoadCallbacks() == SendCallbacks) 316 frameLoader()->notifier().didReceiveResponse(this, m_response); 317} 318 319void ResourceLoader::didReceiveData(const char* data, unsigned length, long long encodedDataLength, DataPayloadType dataPayloadType) 320{ 321 // The following assertions are not quite valid here, since a subclass 322 // might override didReceiveData in a way that invalidates them. This 323 // happens with the steps listed in 3266216 324 // ASSERT(con == connection); 325 // ASSERT(!m_reachedTerminalState); 326 327 didReceiveDataOrBuffer(data, length, 0, encodedDataLength, dataPayloadType); 328} 329 330void ResourceLoader::didReceiveBuffer(PassRefPtr<SharedBuffer> buffer, long long encodedDataLength, DataPayloadType dataPayloadType) 331{ 332 didReceiveDataOrBuffer(0, 0, buffer, encodedDataLength, dataPayloadType); 333} 334 335void ResourceLoader::didReceiveDataOrBuffer(const char* data, unsigned length, PassRefPtr<SharedBuffer> prpBuffer, long long encodedDataLength, DataPayloadType dataPayloadType) 336{ 337 // This method should only get data+length *OR* a SharedBuffer. 338 ASSERT(!prpBuffer || (!data && !length)); 339 340 // Protect this in this delegate method since the additional processing can do 341 // anything including possibly derefing this; one example of this is Radar 3266216. 342 Ref<ResourceLoader> protect(*this); 343 RefPtr<SharedBuffer> buffer = prpBuffer; 344 345 addDataOrBuffer(data, length, buffer.get(), dataPayloadType); 346 347 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing. 348 // However, with today's computers and networking speeds, this won't happen in practice. 349 // Could be an issue with a giant local file. 350 if (m_options.sendLoadCallbacks() == SendCallbacks && m_frame) 351 frameLoader()->notifier().didReceiveData(this, buffer ? buffer->data() : data, buffer ? buffer->size() : length, static_cast<int>(encodedDataLength)); 352} 353 354void ResourceLoader::didFinishLoading(double finishTime) 355{ 356 didFinishLoadingOnePart(finishTime); 357 358 // If the load has been cancelled by a delegate in response to didFinishLoad(), do not release 359 // the resources a second time, they have been released by cancel. 360 if (wasCancelled()) 361 return; 362 releaseResources(); 363} 364 365void ResourceLoader::didFinishLoadingOnePart(double finishTime) 366{ 367 // If load has been cancelled after finishing (which could happen with a 368 // JavaScript that changes the window location), do nothing. 369 if (wasCancelled()) 370 return; 371 ASSERT(!m_reachedTerminalState); 372 373 if (m_notifiedLoadComplete) 374 return; 375 m_notifiedLoadComplete = true; 376 if (m_options.sendLoadCallbacks() == SendCallbacks) 377 frameLoader()->notifier().didFinishLoad(this, finishTime); 378} 379 380void ResourceLoader::didFail(const ResourceError& error) 381{ 382 if (wasCancelled()) 383 return; 384 ASSERT(!m_reachedTerminalState); 385 386 // Protect this in this delegate method since the additional processing can do 387 // anything including possibly derefing this; one example of this is Radar 3266216. 388 Ref<ResourceLoader> protect(*this); 389 390 cleanupForError(error); 391 releaseResources(); 392} 393 394void ResourceLoader::cleanupForError(const ResourceError& error) 395{ 396 if (FormData* data = m_request.httpBody()) 397 data->removeGeneratedFilesIfNeeded(); 398 399 if (m_notifiedLoadComplete) 400 return; 401 m_notifiedLoadComplete = true; 402 if (m_options.sendLoadCallbacks() == SendCallbacks && m_identifier) 403 frameLoader()->notifier().didFailToLoad(this, error); 404} 405 406void ResourceLoader::didChangePriority(ResourceLoadPriority loadPriority) 407{ 408 if (m_handle) 409 m_handle->didChangePriority(loadPriority); 410} 411 412void ResourceLoader::cancel() 413{ 414 cancel(ResourceError()); 415} 416 417void ResourceLoader::cancel(const ResourceError& error) 418{ 419 // If the load has already completed - succeeded, failed, or previously cancelled - do nothing. 420 if (m_reachedTerminalState) 421 return; 422 423 ResourceError nonNullError = error.isNull() ? cancelledError() : error; 424 425 // willCancel() and didFailToLoad() both call out to clients that might do 426 // something causing the last reference to this object to go away. 427 Ref<ResourceLoader> protect(*this); 428 429 // If we re-enter cancel() from inside willCancel(), we want to pick up from where we left 430 // off without re-running willCancel() 431 if (m_cancellationStatus == NotCancelled) { 432 m_cancellationStatus = CalledWillCancel; 433 434 willCancel(nonNullError); 435 } 436 437 // If we re-enter cancel() from inside didFailToLoad(), we want to pick up from where we 438 // left off without redoing any of this work. 439 if (m_cancellationStatus == CalledWillCancel) { 440 m_cancellationStatus = Cancelled; 441 442 if (m_handle) 443 m_handle->clearAuthentication(); 444 445 m_documentLoader->cancelPendingSubstituteLoad(this); 446 if (m_handle) { 447 m_handle->cancel(); 448 m_handle = 0; 449 } 450 cleanupForError(nonNullError); 451 } 452 453 // If cancel() completed from within the call to willCancel() or didFailToLoad(), 454 // we don't want to redo didCancel() or releasesResources(). 455 if (m_reachedTerminalState) 456 return; 457 458 didCancel(nonNullError); 459 460 if (m_cancellationStatus == FinishedCancel) 461 return; 462 m_cancellationStatus = FinishedCancel; 463 464 releaseResources(); 465} 466 467ResourceError ResourceLoader::cancelledError() 468{ 469 return frameLoader()->cancelledError(m_request); 470} 471 472ResourceError ResourceLoader::blockedError() 473{ 474 return frameLoader()->client().blockedError(m_request); 475} 476 477ResourceError ResourceLoader::cannotShowURLError() 478{ 479 return frameLoader()->client().cannotShowURLError(m_request); 480} 481 482void ResourceLoader::willSendRequest(ResourceHandle*, ResourceRequest& request, const ResourceResponse& redirectResponse) 483{ 484 if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForRedirect(this, request, redirectResponse)) 485 return; 486 willSendRequest(request, redirectResponse); 487} 488 489void ResourceLoader::didSendData(ResourceHandle*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent) 490{ 491 didSendData(bytesSent, totalBytesToBeSent); 492} 493 494void ResourceLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response) 495{ 496 if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForResponse(this, response)) 497 return; 498 didReceiveResponse(response); 499} 500 501void ResourceLoader::didReceiveData(ResourceHandle*, const char* data, unsigned length, int encodedDataLength) 502{ 503 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(m_frame.get(), identifier(), encodedDataLength); 504 didReceiveData(data, length, encodedDataLength, DataPayloadBytes); 505 InspectorInstrumentation::didReceiveResourceData(cookie); 506} 507 508void ResourceLoader::didReceiveBuffer(ResourceHandle*, PassRefPtr<SharedBuffer> buffer, int encodedDataLength) 509{ 510 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(m_frame.get(), identifier(), encodedDataLength); 511 didReceiveBuffer(buffer, encodedDataLength, DataPayloadBytes); 512 InspectorInstrumentation::didReceiveResourceData(cookie); 513} 514 515void ResourceLoader::didFinishLoading(ResourceHandle*, double finishTime) 516{ 517 didFinishLoading(finishTime); 518} 519 520void ResourceLoader::didFail(ResourceHandle*, const ResourceError& error) 521{ 522 if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForError(this, error)) 523 return; 524 didFail(error); 525} 526 527void ResourceLoader::wasBlocked(ResourceHandle*) 528{ 529 didFail(blockedError()); 530} 531 532void ResourceLoader::cannotShowURL(ResourceHandle*) 533{ 534 didFail(cannotShowURLError()); 535} 536 537bool ResourceLoader::shouldUseCredentialStorage() 538{ 539 if (m_options.allowCredentials() == DoNotAllowStoredCredentials) 540 return false; 541 542 Ref<ResourceLoader> protect(*this); 543 return frameLoader()->client().shouldUseCredentialStorage(documentLoader(), identifier()); 544} 545 546void ResourceLoader::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge) 547{ 548 ASSERT(m_handle->hasAuthenticationChallenge()); 549 550 // Protect this in this delegate method since the additional processing can do 551 // anything including possibly derefing this; one example of this is Radar 3266216. 552 Ref<ResourceLoader> protect(*this); 553 554 if (m_options.allowCredentials() == AllowStoredCredentials) { 555 if (m_options.clientCredentialPolicy() == AskClientForAllCredentials || (m_options.clientCredentialPolicy() == DoNotAskClientForCrossOriginCredentials && m_frame->document()->securityOrigin()->canRequest(originalRequest().url()))) { 556 frameLoader()->notifier().didReceiveAuthenticationChallenge(this, challenge); 557 return; 558 } 559 } 560 // Only these platforms provide a way to continue without credentials. 561 // If we can't continue with credentials, we need to cancel the load altogether. 562#if PLATFORM(COCOA) || USE(CFNETWORK) || USE(CURL) || PLATFORM(GTK) || PLATFORM(EFL) 563 challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge); 564 ASSERT(!m_handle || !m_handle->hasAuthenticationChallenge()); 565#else 566 didFail(blockedError()); 567#endif 568} 569 570void ResourceLoader::didCancelAuthenticationChallenge(const AuthenticationChallenge& challenge) 571{ 572 // Protect this in this delegate method since the additional processing can do 573 // anything including possibly derefing this; one example of this is Radar 3266216. 574 Ref<ResourceLoader> protect(*this); 575 frameLoader()->notifier().didCancelAuthenticationChallenge(this, challenge); 576} 577 578#if USE(PROTECTION_SPACE_AUTH_CALLBACK) 579 580bool ResourceLoader::canAuthenticateAgainstProtectionSpace(const ProtectionSpace& protectionSpace) 581{ 582 Ref<ResourceLoader> protect(*this); 583 return frameLoader()->client().canAuthenticateAgainstProtectionSpace(documentLoader(), identifier(), protectionSpace); 584} 585 586#endif 587 588#if PLATFORM(IOS) 589 590RetainPtr<CFDictionaryRef> ResourceLoader::connectionProperties(ResourceHandle*) 591{ 592 return frameLoader()->connectionProperties(this); 593} 594 595#endif 596 597void ResourceLoader::receivedCancellation(const AuthenticationChallenge&) 598{ 599 cancel(); 600} 601 602#if PLATFORM(MAC) 603 604void ResourceLoader::schedule(SchedulePair& pair) 605{ 606 if (m_handle) 607 m_handle->schedule(pair); 608} 609 610void ResourceLoader::unschedule(SchedulePair& pair) 611{ 612 if (m_handle) 613 m_handle->unschedule(pair); 614} 615 616#endif 617 618#if USE(QUICK_LOOK) 619void ResourceLoader::didCreateQuickLookHandle(QuickLookHandle& handle) 620{ 621 frameLoader()->client().didCreateQuickLookHandle(handle); 622} 623#endif 624 625} 626