1 /* 2 * Copyright (C) 2006, 2007, 2010, 2011 Apple Inc. All rights reserved. 3 * (C) 2007 Graham Dennis (graham.dennis (at) 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 48 namespace WebCore { 49 50 PassRefPtr<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 61 ResourceLoader::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 75 ResourceLoader::~ResourceLoader() 76 { 77 ASSERT(m_reachedTerminalState); 78 } 79 80 void 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 113 bool 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 142 void 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 167 void 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. 181 void ResourceLoader::pauseLoad(bool pause) 182 { 183 if (m_handle) 184 m_handle->pauseLoad(pause); 185 } 186 #endif 187 188 FrameLoader* ResourceLoader::frameLoader() const 189 { 190 if (!m_frame) 191 return 0; 192 return m_frame->loader(); 193 } 194 195 void 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 205 void 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 227 void ResourceLoader::clearResourceData() 228 { 229 if (m_resourceData) 230 m_resourceData->clear(); 231 } 232 233 void 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 255 void ResourceLoader::didSendData(unsigned long long, unsigned long long) 256 { 257 } 258 259 void 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 276 void 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 296 void 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 305 void 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 317 void 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 330 void 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 349 void 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 378 void ResourceLoader::cancel() 379 { 380 cancel(ResourceError()); 381 } 382 383 void 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 393 const ResourceResponse& ResourceLoader::response() const 394 { 395 return m_response; 396 } 397 398 ResourceError ResourceLoader::cancelledError() 399 { 400 return frameLoader()->cancelledError(m_request); 401 } 402 403 ResourceError ResourceLoader::blockedError() 404 { 405 return frameLoader()->blockedError(m_request); 406 } 407 408 ResourceError ResourceLoader::cannotShowURLError() 409 { 410 return frameLoader()->cannotShowURLError(m_request); 411 } 412 413 void 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 422 void ResourceLoader::didSendData(ResourceHandle*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent) 423 { 424 didSendData(bytesSent, totalBytesToBeSent); 425 } 426 427 void 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 436 void 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 443 void ResourceLoader::didFinishLoading(ResourceHandle*, double finishTime) 444 { 445 didFinishLoading(finishTime); 446 } 447 448 void 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 457 void ResourceLoader::wasBlocked(ResourceHandle*) 458 { 459 didFail(blockedError()); 460 } 461 462 void ResourceLoader::cannotShowURL(ResourceHandle*) 463 { 464 didFail(cannotShowURLError()); 465 } 466 467 bool ResourceLoader::shouldUseCredentialStorage() 468 { 469 RefPtr<ResourceLoader> protector(this); 470 return frameLoader()->shouldUseCredentialStorage(this); 471 } 472 473 void 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 481 void 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) 490 bool ResourceLoader::canAuthenticateAgainstProtectionSpace(const ProtectionSpace& protectionSpace) 491 { 492 RefPtr<ResourceLoader> protector(this); 493 return frameLoader()->canAuthenticateAgainstProtectionSpace(this, protectionSpace); 494 } 495 #endif 496 497 void ResourceLoader::receivedCancellation(const AuthenticationChallenge&) 498 { 499 cancel(); 500 } 501 502 void 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) 517 AsyncFileStream* 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