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 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 "ResourceLoader.h" 32 33#include "ApplicationCacheHost.h" 34#include "DocumentLoader.h" 35#include "FileStreamProxy.h" 36#include "Frame.h" 37#include "FrameLoader.h" 38#include "FrameLoaderClient.h" 39#include "InspectorInstrumentation.h" 40#include "Page.h" 41#include "ProgressTracker.h" 42#include "ResourceError.h" 43#include "ResourceHandle.h" 44#include "ResourceLoadScheduler.h" 45#include "Settings.h" 46#include "SharedBuffer.h" 47 48namespace WebCore { 49 50PassRefPtr<SharedBuffer> ResourceLoader::resourceData() 51{ 52 if (m_resourceData) 53 return m_resourceData; 54 55 if (ResourceHandle::supportsBufferedData() && m_handle) 56 return m_handle->bufferedData(); 57 58 return 0; 59} 60 61ResourceLoader::ResourceLoader(Frame* frame, bool sendResourceLoadCallbacks, bool shouldContentSniff) 62 : m_frame(frame) 63 , m_documentLoader(frame->loader()->activeDocumentLoader()) 64 , m_identifier(0) 65 , m_reachedTerminalState(false) 66 , m_cancelled(false) 67 , m_calledDidFinishLoad(false) 68 , m_sendResourceLoadCallbacks(sendResourceLoadCallbacks) 69 , m_shouldContentSniff(shouldContentSniff) 70 , m_shouldBufferData(true) 71 , m_defersLoading(frame->page()->defersLoading()) 72{ 73} 74 75ResourceLoader::~ResourceLoader() 76{ 77 ASSERT(m_reachedTerminalState); 78} 79 80void ResourceLoader::releaseResources() 81{ 82 ASSERT(!m_reachedTerminalState); 83 84 // It's possible that when we release the handle, it will be 85 // deallocated and release the last reference to this object. 86 // We need to retain to avoid accessing the object after it 87 // has been deallocated and also to avoid reentering this method. 88 RefPtr<ResourceLoader> protector(this); 89 90 m_frame = 0; 91 m_documentLoader = 0; 92 93 // We need to set reachedTerminalState to true before we release 94 // the resources to prevent a double dealloc of WebView <rdar://problem/4372628> 95 m_reachedTerminalState = true; 96 97 m_identifier = 0; 98 99 resourceLoadScheduler()->remove(this); 100 101 if (m_handle) { 102 // Clear out the ResourceHandle's client so that it doesn't try to call 103 // us back after we release it, unless it has been replaced by someone else. 104 if (m_handle->client() == this) 105 m_handle->setClient(0); 106 m_handle = 0; 107 } 108 109 m_resourceData = 0; 110 m_deferredRequest = ResourceRequest(); 111} 112 113bool ResourceLoader::init(const ResourceRequest& r) 114{ 115 ASSERT(!m_handle); 116 ASSERT(m_request.isNull()); 117 ASSERT(m_deferredRequest.isNull()); 118 ASSERT(!m_documentLoader->isSubstituteLoadPending(this)); 119 120 ResourceRequest clientRequest(r); 121 122 // https://bugs.webkit.org/show_bug.cgi?id=26391 123 // The various plug-in implementations call directly to ResourceLoader::load() instead of piping requests 124 // through FrameLoader. As a result, they miss the FrameLoader::addExtraFieldsToRequest() step which sets 125 // up the 1st party for cookies URL. Until plug-in implementations can be reigned in to pipe through that 126 // method, we need to make sure there is always a 1st party for cookies set. 127 if (clientRequest.firstPartyForCookies().isNull()) { 128 if (Document* document = m_frame->document()) 129 clientRequest.setFirstPartyForCookies(document->firstPartyForCookies()); 130 } 131 132 willSendRequest(clientRequest, ResourceResponse()); 133 if (clientRequest.isNull()) { 134 didFail(frameLoader()->cancelledError(m_request)); 135 return false; 136 } 137 138 m_request = clientRequest; 139 return true; 140} 141 142void ResourceLoader::start() 143{ 144 ASSERT(!m_handle); 145 ASSERT(!m_request.isNull()); 146 ASSERT(m_deferredRequest.isNull()); 147 148#if ENABLE(WEB_ARCHIVE) 149 if (m_documentLoader->scheduleArchiveLoad(this, m_request, m_request.url())) 150 return; 151#endif 152 153#if ENABLE(OFFLINE_WEB_APPLICATIONS) 154 if (m_documentLoader->applicationCacheHost()->maybeLoadResource(this, m_request, m_request.url())) 155 return; 156#endif 157 158 if (m_defersLoading) { 159 m_deferredRequest = m_request; 160 return; 161 } 162 163 if (!m_reachedTerminalState) 164 m_handle = ResourceHandle::create(m_frame->loader()->networkingContext(), m_request, this, m_defersLoading, m_shouldContentSniff); 165} 166 167void ResourceLoader::setDefersLoading(bool defers) 168{ 169 m_defersLoading = defers; 170 if (m_handle) 171 m_handle->setDefersLoading(defers); 172 if (!defers && !m_deferredRequest.isNull()) { 173 m_request = m_deferredRequest; 174 m_deferredRequest = ResourceRequest(); 175 start(); 176 } 177} 178 179#if PLATFORM(ANDROID) 180// TODO: This needs upstreaming to WebKit. 181void ResourceLoader::pauseLoad(bool pause) 182{ 183 if (m_handle) 184 m_handle->pauseLoad(pause); 185} 186#endif 187 188FrameLoader* ResourceLoader::frameLoader() const 189{ 190 if (!m_frame) 191 return 0; 192 return m_frame->loader(); 193} 194 195void ResourceLoader::setShouldBufferData(bool shouldBufferData) 196{ 197 m_shouldBufferData = shouldBufferData; 198 199 // Reset any already buffered data 200 if (!m_shouldBufferData) 201 m_resourceData = 0; 202} 203 204 205void ResourceLoader::addData(const char* data, int length, bool allAtOnce) 206{ 207 if (!m_shouldBufferData) 208 return; 209 210 if (allAtOnce) { 211 m_resourceData = SharedBuffer::create(data, length); 212 return; 213 } 214 215 if (ResourceHandle::supportsBufferedData()) { 216 // Buffer data only if the connection has handed us the data because is has stopped buffering it. 217 if (m_resourceData) 218 m_resourceData->append(data, length); 219 } else { 220 if (!m_resourceData) 221 m_resourceData = SharedBuffer::create(data, length); 222 else 223 m_resourceData->append(data, length); 224 } 225} 226 227void ResourceLoader::clearResourceData() 228{ 229 if (m_resourceData) 230 m_resourceData->clear(); 231} 232 233void ResourceLoader::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse) 234{ 235 // Protect this in this delegate method since the additional processing can do 236 // anything including possibly derefing this; one example of this is Radar 3266216. 237 RefPtr<ResourceLoader> protector(this); 238 239 ASSERT(!m_reachedTerminalState); 240 241 if (m_sendResourceLoadCallbacks) { 242 if (!m_identifier) { 243 m_identifier = m_frame->page()->progress()->createUniqueIdentifier(); 244 frameLoader()->notifier()->assignIdentifierToInitialRequest(m_identifier, documentLoader(), request); 245 } 246 247 frameLoader()->notifier()->willSendRequest(this, request, redirectResponse); 248 } 249 250 if (!redirectResponse.isNull()) 251 resourceLoadScheduler()->crossOriginRedirectReceived(this, request.url()); 252 m_request = request; 253} 254 255void ResourceLoader::didSendData(unsigned long long, unsigned long long) 256{ 257} 258 259void ResourceLoader::didReceiveResponse(const ResourceResponse& r) 260{ 261 ASSERT(!m_reachedTerminalState); 262 263 // Protect this in this delegate method since the additional processing can do 264 // anything including possibly derefing this; one example of this is Radar 3266216. 265 RefPtr<ResourceLoader> protector(this); 266 267 m_response = r; 268 269 if (FormData* data = m_request.httpBody()) 270 data->removeGeneratedFilesIfNeeded(); 271 272 if (m_sendResourceLoadCallbacks) 273 frameLoader()->notifier()->didReceiveResponse(this, m_response); 274} 275 276void ResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce) 277{ 278 // The following assertions are not quite valid here, since a subclass 279 // might override didReceiveData in a way that invalidates them. This 280 // happens with the steps listed in 3266216 281 // ASSERT(con == connection); 282 // ASSERT(!m_reachedTerminalState); 283 284 // Protect this in this delegate method since the additional processing can do 285 // anything including possibly derefing this; one example of this is Radar 3266216. 286 RefPtr<ResourceLoader> protector(this); 287 288 addData(data, length, allAtOnce); 289 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing. 290 // However, with today's computers and networking speeds, this won't happen in practice. 291 // Could be an issue with a giant local file. 292 if (m_sendResourceLoadCallbacks && m_frame) 293 frameLoader()->notifier()->didReceiveData(this, data, length, static_cast<int>(encodedDataLength)); 294} 295 296void ResourceLoader::willStopBufferingData(const char* data, int length) 297{ 298 if (!m_shouldBufferData) 299 return; 300 301 ASSERT(!m_resourceData); 302 m_resourceData = SharedBuffer::create(data, length); 303} 304 305void ResourceLoader::didFinishLoading(double finishTime) 306{ 307 // If load has been cancelled after finishing (which could happen with a 308 // JavaScript that changes the window location), do nothing. 309 if (m_cancelled) 310 return; 311 ASSERT(!m_reachedTerminalState); 312 313 didFinishLoadingOnePart(finishTime); 314 releaseResources(); 315} 316 317void ResourceLoader::didFinishLoadingOnePart(double finishTime) 318{ 319 if (m_cancelled) 320 return; 321 ASSERT(!m_reachedTerminalState); 322 323 if (m_calledDidFinishLoad) 324 return; 325 m_calledDidFinishLoad = true; 326 if (m_sendResourceLoadCallbacks) 327 frameLoader()->notifier()->didFinishLoad(this, finishTime); 328} 329 330void ResourceLoader::didFail(const ResourceError& error) 331{ 332 if (m_cancelled) 333 return; 334 ASSERT(!m_reachedTerminalState); 335 336 // Protect this in this delegate method since the additional processing can do 337 // anything including possibly derefing this; one example of this is Radar 3266216. 338 RefPtr<ResourceLoader> protector(this); 339 340 if (FormData* data = m_request.httpBody()) 341 data->removeGeneratedFilesIfNeeded(); 342 343 if (m_sendResourceLoadCallbacks && !m_calledDidFinishLoad) 344 frameLoader()->notifier()->didFailToLoad(this, error); 345 346 releaseResources(); 347} 348 349void ResourceLoader::didCancel(const ResourceError& error) 350{ 351 ASSERT(!m_cancelled); 352 ASSERT(!m_reachedTerminalState); 353 354 if (FormData* data = m_request.httpBody()) 355 data->removeGeneratedFilesIfNeeded(); 356 357 // This flag prevents bad behavior when loads that finish cause the 358 // load itself to be cancelled (which could happen with a javascript that 359 // changes the window location). This is used to prevent both the body 360 // of this method and the body of connectionDidFinishLoading: running 361 // for a single delegate. Canceling wins. 362 m_cancelled = true; 363 364 if (m_handle) 365 m_handle->clearAuthentication(); 366 367 m_documentLoader->cancelPendingSubstituteLoad(this); 368 if (m_handle) { 369 m_handle->cancel(); 370 m_handle = 0; 371 } 372 if (m_sendResourceLoadCallbacks && m_identifier && !m_calledDidFinishLoad) 373 frameLoader()->notifier()->didFailToLoad(this, error); 374 375 releaseResources(); 376} 377 378void ResourceLoader::cancel() 379{ 380 cancel(ResourceError()); 381} 382 383void ResourceLoader::cancel(const ResourceError& error) 384{ 385 if (m_reachedTerminalState) 386 return; 387 if (!error.isNull()) 388 didCancel(error); 389 else 390 didCancel(cancelledError()); 391} 392 393const ResourceResponse& ResourceLoader::response() const 394{ 395 return m_response; 396} 397 398ResourceError ResourceLoader::cancelledError() 399{ 400 return frameLoader()->cancelledError(m_request); 401} 402 403ResourceError ResourceLoader::blockedError() 404{ 405 return frameLoader()->blockedError(m_request); 406} 407 408ResourceError ResourceLoader::cannotShowURLError() 409{ 410 return frameLoader()->cannotShowURLError(m_request); 411} 412 413void ResourceLoader::willSendRequest(ResourceHandle*, ResourceRequest& request, const ResourceResponse& redirectResponse) 414{ 415#if ENABLE(OFFLINE_WEB_APPLICATIONS) 416 if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForRedirect(this, request, redirectResponse)) 417 return; 418#endif 419 willSendRequest(request, redirectResponse); 420} 421 422void ResourceLoader::didSendData(ResourceHandle*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent) 423{ 424 didSendData(bytesSent, totalBytesToBeSent); 425} 426 427void ResourceLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response) 428{ 429#if ENABLE(OFFLINE_WEB_APPLICATIONS) 430 if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForResponse(this, response)) 431 return; 432#endif 433 didReceiveResponse(response); 434} 435 436void ResourceLoader::didReceiveData(ResourceHandle*, const char* data, int length, int encodedDataLength) 437{ 438 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(m_frame.get(), identifier()); 439 didReceiveData(data, length, encodedDataLength, false); 440 InspectorInstrumentation::didReceiveResourceData(cookie); 441} 442 443void ResourceLoader::didFinishLoading(ResourceHandle*, double finishTime) 444{ 445 didFinishLoading(finishTime); 446} 447 448void ResourceLoader::didFail(ResourceHandle*, const ResourceError& error) 449{ 450#if ENABLE(OFFLINE_WEB_APPLICATIONS) 451 if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForError(this, error)) 452 return; 453#endif 454 didFail(error); 455} 456 457void ResourceLoader::wasBlocked(ResourceHandle*) 458{ 459 didFail(blockedError()); 460} 461 462void ResourceLoader::cannotShowURL(ResourceHandle*) 463{ 464 didFail(cannotShowURLError()); 465} 466 467bool ResourceLoader::shouldUseCredentialStorage() 468{ 469 RefPtr<ResourceLoader> protector(this); 470 return frameLoader()->shouldUseCredentialStorage(this); 471} 472 473void ResourceLoader::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge) 474{ 475 // Protect this in this delegate method since the additional processing can do 476 // anything including possibly derefing this; one example of this is Radar 3266216. 477 RefPtr<ResourceLoader> protector(this); 478 frameLoader()->notifier()->didReceiveAuthenticationChallenge(this, challenge); 479} 480 481void ResourceLoader::didCancelAuthenticationChallenge(const AuthenticationChallenge& challenge) 482{ 483 // Protect this in this delegate method since the additional processing can do 484 // anything including possibly derefing this; one example of this is Radar 3266216. 485 RefPtr<ResourceLoader> protector(this); 486 frameLoader()->notifier()->didCancelAuthenticationChallenge(this, challenge); 487} 488 489#if USE(PROTECTION_SPACE_AUTH_CALLBACK) 490bool ResourceLoader::canAuthenticateAgainstProtectionSpace(const ProtectionSpace& protectionSpace) 491{ 492 RefPtr<ResourceLoader> protector(this); 493 return frameLoader()->canAuthenticateAgainstProtectionSpace(this, protectionSpace); 494} 495#endif 496 497void ResourceLoader::receivedCancellation(const AuthenticationChallenge&) 498{ 499 cancel(); 500} 501 502void ResourceLoader::willCacheResponse(ResourceHandle*, CacheStoragePolicy& policy) 503{ 504 // <rdar://problem/7249553> - There are reports of crashes with this method being called 505 // with a null m_frame->settings(), which can only happen if the frame doesn't have a page. 506 // Sadly we have no reproducible cases of this. 507 // We think that any frame without a page shouldn't have any loads happening in it, yet 508 // there is at least one code path where that is not true. 509 ASSERT(m_frame->settings()); 510 511 // When in private browsing mode, prevent caching to disk 512 if (policy == StorageAllowed && m_frame->settings() && m_frame->settings()->privateBrowsingEnabled()) 513 policy = StorageAllowedInMemoryOnly; 514} 515 516#if ENABLE(BLOB) 517AsyncFileStream* ResourceLoader::createAsyncFileStream(FileStreamClient* client) 518{ 519 // It is OK to simply return a pointer since FileStreamProxy::create adds an extra ref. 520 return FileStreamProxy::create(m_frame->document()->scriptExecutionContext(), client).get(); 521} 522#endif 523 524} 525