Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010, 2011, 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2010, 2011, 2012 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 */ | 29 */ |
| 30 | 30 |
| 31 #include "web/AssociatedURLLoader.h" | 31 #include "web/AssociatedURLLoader.h" |
| 32 | 32 |
| 33 #include "core/dom/ContextLifecycleObserver.h" | |
| 33 #include "core/fetch/CrossOriginAccessControl.h" | 34 #include "core/fetch/CrossOriginAccessControl.h" |
| 34 #include "core/fetch/FetchUtils.h" | 35 #include "core/fetch/FetchUtils.h" |
| 35 #include "core/loader/DocumentThreadableLoader.h" | 36 #include "core/loader/DocumentThreadableLoader.h" |
| 36 #include "core/loader/DocumentThreadableLoaderClient.h" | 37 #include "core/loader/DocumentThreadableLoaderClient.h" |
| 37 #include "platform/Timer.h" | 38 #include "platform/Timer.h" |
| 38 #include "platform/exported/WrappedResourceRequest.h" | 39 #include "platform/exported/WrappedResourceRequest.h" |
| 39 #include "platform/exported/WrappedResourceResponse.h" | 40 #include "platform/exported/WrappedResourceResponse.h" |
| 40 #include "platform/network/HTTPParsers.h" | 41 #include "platform/network/HTTPParsers.h" |
| 41 #include "platform/network/ResourceError.h" | 42 #include "platform/network/ResourceError.h" |
| 42 #include "public/platform/WebHTTPHeaderVisitor.h" | 43 #include "public/platform/WebHTTPHeaderVisitor.h" |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 240 return; | 241 return; |
| 241 | 242 |
| 242 m_client->didReceiveCachedMetadata(m_loader, data, dataLength); | 243 m_client->didReceiveCachedMetadata(m_loader, data, dataLength); |
| 243 } | 244 } |
| 244 | 245 |
| 245 void AssociatedURLLoader::ClientAdapter::didFinishLoading(unsigned long identifi er, double finishTime) | 246 void AssociatedURLLoader::ClientAdapter::didFinishLoading(unsigned long identifi er, double finishTime) |
| 246 { | 247 { |
| 247 if (!m_client) | 248 if (!m_client) |
| 248 return; | 249 return; |
| 249 | 250 |
| 251 m_loader->disposeObserver(); | |
| 252 | |
| 250 m_client->didFinishLoading(m_loader, finishTime, WebURLLoaderClient::kUnknow nEncodedDataLength); | 253 m_client->didFinishLoading(m_loader, finishTime, WebURLLoaderClient::kUnknow nEncodedDataLength); |
| 251 } | 254 } |
| 252 | 255 |
| 253 void AssociatedURLLoader::ClientAdapter::didFail(const ResourceError& error) | 256 void AssociatedURLLoader::ClientAdapter::didFail(const ResourceError& error) |
| 254 { | 257 { |
| 255 if (!m_client) | 258 if (!m_client) |
| 256 return; | 259 return; |
| 257 | 260 |
| 261 m_loader->disposeObserver(); | |
| 262 | |
| 258 m_didFail = true; | 263 m_didFail = true; |
| 259 m_error = WebURLError(error); | 264 m_error = WebURLError(error); |
| 260 if (m_enableErrorNotifications) | 265 if (m_enableErrorNotifications) |
| 261 notifyError(&m_errorTimer); | 266 notifyError(&m_errorTimer); |
| 262 } | 267 } |
| 263 | 268 |
| 264 void AssociatedURLLoader::ClientAdapter::didFailRedirectCheck() | 269 void AssociatedURLLoader::ClientAdapter::didFailRedirectCheck() |
| 265 { | 270 { |
| 266 didFail(ResourceError()); | 271 didFail(ResourceError()); |
| 267 } | 272 } |
| 268 | 273 |
| 269 void AssociatedURLLoader::ClientAdapter::setDelayedError(const ResourceError& er ror) | |
| 270 { | |
| 271 didFail(error); | |
| 272 } | |
| 273 | |
| 274 void AssociatedURLLoader::ClientAdapter::enableErrorNotifications() | 274 void AssociatedURLLoader::ClientAdapter::enableErrorNotifications() |
| 275 { | 275 { |
| 276 m_enableErrorNotifications = true; | 276 m_enableErrorNotifications = true; |
| 277 // If an error has already been received, start a timer to report it to the client | 277 // If an error has already been received, start a timer to report it to the client |
| 278 // after AssociatedURLLoader::loadAsynchronously has returned to the caller. | 278 // after AssociatedURLLoader::loadAsynchronously has returned to the caller. |
| 279 if (m_didFail) | 279 if (m_didFail) |
| 280 m_errorTimer.startOneShot(0, BLINK_FROM_HERE); | 280 m_errorTimer.startOneShot(0, BLINK_FROM_HERE); |
| 281 } | 281 } |
| 282 | 282 |
| 283 void AssociatedURLLoader::ClientAdapter::notifyError(Timer<ClientAdapter>* timer ) | 283 void AssociatedURLLoader::ClientAdapter::notifyError(Timer<ClientAdapter>* timer ) |
| 284 { | 284 { |
| 285 ASSERT_UNUSED(timer, timer == &m_errorTimer); | 285 ASSERT_UNUSED(timer, timer == &m_errorTimer); |
| 286 | 286 |
| 287 if (!m_client) | |
| 288 return; | |
| 289 | |
| 287 m_client->didFail(m_loader, m_error); | 290 m_client->didFail(m_loader, m_error); |
| 288 } | 291 } |
| 289 | 292 |
| 293 class AssociatedURLLoader::Observer final : public GarbageCollectedFinalized<Obs erver>, public ContextLifecycleObserver { | |
| 294 USING_GARBAGE_COLLECTED_MIXIN(Observer); | |
| 295 public: | |
| 296 Observer(AssociatedURLLoader* parent, Document* document) | |
| 297 : ContextLifecycleObserver(document) | |
| 298 , m_parent(parent) | |
| 299 { | |
| 300 } | |
| 301 | |
| 302 void dispose() | |
| 303 { | |
| 304 m_parent = nullptr; | |
| 305 clearContext(); | |
| 306 } | |
| 307 | |
| 308 void contextDestroyed() override | |
| 309 { | |
| 310 if (m_parent) | |
| 311 m_parent->documentDestroyed(); | |
| 312 } | |
| 313 | |
| 314 DEFINE_INLINE_VIRTUAL_TRACE() | |
| 315 { | |
| 316 ContextLifecycleObserver::trace(visitor); | |
| 317 } | |
| 318 | |
| 319 AssociatedURLLoader* m_parent; | |
| 320 }; | |
| 321 | |
| 290 AssociatedURLLoader::AssociatedURLLoader(RawPtr<WebLocalFrameImpl> frameImpl, co nst WebURLLoaderOptions& options) | 322 AssociatedURLLoader::AssociatedURLLoader(RawPtr<WebLocalFrameImpl> frameImpl, co nst WebURLLoaderOptions& options) |
| 291 : m_frameImpl(frameImpl) | 323 : m_options(options) |
| 292 , m_options(options) | 324 , m_observer(new Observer(this, frameImpl->frame()->document())) |
| 293 , m_client(0) | |
| 294 { | 325 { |
| 295 DCHECK(m_frameImpl); | |
| 296 } | 326 } |
| 297 | 327 |
| 298 AssociatedURLLoader::~AssociatedURLLoader() | 328 AssociatedURLLoader::~AssociatedURLLoader() |
| 299 { | 329 { |
| 300 cancel(); | 330 cancel(); |
| 301 } | 331 } |
| 302 | 332 |
| 303 #define STATIC_ASSERT_ENUM(a, b) \ | 333 #define STATIC_ASSERT_ENUM(a, b) \ |
| 304 static_assert(static_cast<int>(a) == static_cast<int>(b), \ | 334 static_assert(static_cast<int>(a) == static_cast<int>(b), \ |
| 305 "mismatching enum: " #a) | 335 "mismatching enum: " #a) |
| 306 | 336 |
| 307 STATIC_ASSERT_ENUM(WebURLLoaderOptions::CrossOriginRequestPolicyDeny, DenyCrossO riginRequests); | 337 STATIC_ASSERT_ENUM(WebURLLoaderOptions::CrossOriginRequestPolicyDeny, DenyCrossO riginRequests); |
| 308 STATIC_ASSERT_ENUM(WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl , UseAccessControl); | 338 STATIC_ASSERT_ENUM(WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl , UseAccessControl); |
| 309 STATIC_ASSERT_ENUM(WebURLLoaderOptions::CrossOriginRequestPolicyAllow, AllowCros sOriginRequests); | 339 STATIC_ASSERT_ENUM(WebURLLoaderOptions::CrossOriginRequestPolicyAllow, AllowCros sOriginRequests); |
| 310 | 340 |
| 311 STATIC_ASSERT_ENUM(WebURLLoaderOptions::ConsiderPreflight, ConsiderPreflight); | 341 STATIC_ASSERT_ENUM(WebURLLoaderOptions::ConsiderPreflight, ConsiderPreflight); |
| 312 STATIC_ASSERT_ENUM(WebURLLoaderOptions::ForcePreflight, ForcePreflight); | 342 STATIC_ASSERT_ENUM(WebURLLoaderOptions::ForcePreflight, ForcePreflight); |
| 313 STATIC_ASSERT_ENUM(WebURLLoaderOptions::PreventPreflight, PreventPreflight); | 343 STATIC_ASSERT_ENUM(WebURLLoaderOptions::PreventPreflight, PreventPreflight); |
| 314 | 344 |
| 315 void AssociatedURLLoader::loadSynchronously(const WebURLRequest& request, WebURL Response& response, WebURLError& error, WebData& data) | 345 void AssociatedURLLoader::loadSynchronously(const WebURLRequest& request, WebURL Response& response, WebURLError& error, WebData& data) |
| 316 { | 346 { |
| 317 DCHECK(0); // Synchronous loading is not supported. | 347 DCHECK(0); // Synchronous loading is not supported. |
| 318 } | 348 } |
| 319 | 349 |
| 320 void AssociatedURLLoader::loadAsynchronously(const WebURLRequest& request, WebUR LLoaderClient* client) | 350 void AssociatedURLLoader::loadAsynchronously(const WebURLRequest& request, WebUR LLoaderClient* client) |
| 321 { | 351 { |
| 322 DCHECK(!m_loader); | 352 DCHECK(!m_loader); |
| 323 DCHECK(!m_client); | 353 DCHECK(!m_clientAdapter); |
| 324 | 354 |
| 325 m_client = client; | 355 DCHECK(client); |
| 326 DCHECK(m_client); | |
| 327 | 356 |
| 328 bool allowLoad = true; | 357 bool allowLoad = true; |
| 329 WebURLRequest newRequest(request); | 358 WebURLRequest newRequest(request); |
| 330 if (m_options.untrustedHTTP) { | 359 if (m_options.untrustedHTTP) { |
| 331 WebString method = newRequest.httpMethod(); | 360 WebString method = newRequest.httpMethod(); |
| 332 allowLoad = isValidHTTPToken(method) && FetchUtils::isUsefulMethod(metho d); | 361 allowLoad = m_observer && isValidHTTPToken(method) && FetchUtils::isUsef ulMethod(method); |
| 333 if (allowLoad) { | 362 if (allowLoad) { |
| 334 newRequest.setHTTPMethod(FetchUtils::normalizeMethod(method)); | 363 newRequest.setHTTPMethod(FetchUtils::normalizeMethod(method)); |
| 335 HTTPRequestHeaderValidator validator; | 364 HTTPRequestHeaderValidator validator; |
| 336 newRequest.visitHTTPHeaderFields(&validator); | 365 newRequest.visitHTTPHeaderFields(&validator); |
| 337 allowLoad = validator.isSafe(); | 366 allowLoad = validator.isSafe(); |
| 338 } | 367 } |
| 339 } | 368 } |
| 340 | 369 |
| 341 m_clientAdapter = ClientAdapter::create(this, m_client, m_options); | 370 m_clientAdapter = ClientAdapter::create(this, client, m_options); |
| 342 | 371 |
| 343 if (allowLoad) { | 372 if (allowLoad) { |
| 344 ThreadableLoaderOptions options; | 373 ThreadableLoaderOptions options; |
| 345 options.preflightPolicy = static_cast<PreflightPolicy>(m_options.preflig htPolicy); | 374 options.preflightPolicy = static_cast<PreflightPolicy>(m_options.preflig htPolicy); |
| 346 options.crossOriginRequestPolicy = static_cast<CrossOriginRequestPolicy> (m_options.crossOriginRequestPolicy); | 375 options.crossOriginRequestPolicy = static_cast<CrossOriginRequestPolicy> (m_options.crossOriginRequestPolicy); |
| 347 | 376 |
| 348 ResourceLoaderOptions resourceLoaderOptions; | 377 ResourceLoaderOptions resourceLoaderOptions; |
| 349 resourceLoaderOptions.allowCredentials = m_options.allowCredentials ? Al lowStoredCredentials : DoNotAllowStoredCredentials; | 378 resourceLoaderOptions.allowCredentials = m_options.allowCredentials ? Al lowStoredCredentials : DoNotAllowStoredCredentials; |
| 350 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData; | 379 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData; |
| 351 | 380 |
| 352 const ResourceRequest& webcoreRequest = newRequest.toResourceRequest(); | 381 const ResourceRequest& webcoreRequest = newRequest.toResourceRequest(); |
| 353 if (webcoreRequest.requestContext() == WebURLRequest::RequestContextUnsp ecified) { | 382 if (webcoreRequest.requestContext() == WebURLRequest::RequestContextUnsp ecified) { |
| 354 // FIXME: We load URLs without setting a TargetType (and therefore a request context) in several | 383 // FIXME: We load URLs without setting a TargetType (and therefore a request context) in several |
| 355 // places in content/ (P2PPortAllocatorSession::AllocateLegacyRelayS ession, for example). Remove | 384 // places in content/ (P2PPortAllocatorSession::AllocateLegacyRelayS ession, for example). Remove |
| 356 // this once those places are patched up. | 385 // this once those places are patched up. |
| 357 newRequest.setRequestContext(WebURLRequest::RequestContextInternal); | 386 newRequest.setRequestContext(WebURLRequest::RequestContextInternal); |
| 358 } | 387 } |
| 359 | 388 |
| 360 Document* webcoreDocument = m_frameImpl->frame()->document(); | 389 Document* document = toDocument(m_observer->lifecycleContext()); |
| 361 DCHECK(webcoreDocument); | 390 DCHECK(document); |
| 362 m_loader = DocumentThreadableLoader::create(*webcoreDocument, m_clientAd apter.get(), options, resourceLoaderOptions); | 391 m_loader = DocumentThreadableLoader::create(*document, m_clientAdapter.g et(), options, resourceLoaderOptions); |
| 363 m_loader->start(webcoreRequest); | 392 m_loader->start(webcoreRequest); |
| 364 } | 393 } |
| 365 | 394 |
| 366 if (!m_loader) { | 395 if (!m_loader) { |
| 367 // FIXME: return meaningful error codes. | 396 // FIXME: return meaningful error codes. |
| 368 m_clientAdapter->setDelayedError(ResourceError()); | 397 m_clientAdapter->didFail(ResourceError()); |
| 369 } | 398 } |
| 370 m_clientAdapter->enableErrorNotifications(); | 399 m_clientAdapter->enableErrorNotifications(); |
| 371 } | 400 } |
| 372 | 401 |
| 373 void AssociatedURLLoader::cancel() | 402 void AssociatedURLLoader::cancel() |
| 374 { | 403 { |
| 375 if (m_clientAdapter) | 404 disposeObserver(); |
| 376 m_clientAdapter->clearClient(); | 405 |
| 377 if (m_loader) | 406 if (!m_clientAdapter) |
| 407 return; | |
| 408 | |
| 409 // Prevent invocation of the WebURLLoaderClient methods. | |
| 410 m_clientAdapter->clearClient(); | |
| 411 | |
| 412 if (m_loader) { | |
| 378 m_loader->cancel(); | 413 m_loader->cancel(); |
| 414 m_loader.clear(); | |
| 415 } | |
| 416 m_clientAdapter.clear(); | |
| 379 } | 417 } |
| 380 | 418 |
| 381 void AssociatedURLLoader::setDefersLoading(bool defersLoading) | 419 void AssociatedURLLoader::setDefersLoading(bool defersLoading) |
| 382 { | 420 { |
| 383 if (m_loader) | 421 if (m_loader) |
| 384 m_loader->setDefersLoading(defersLoading); | 422 m_loader->setDefersLoading(defersLoading); |
| 385 } | 423 } |
| 386 | 424 |
| 387 void AssociatedURLLoader::setLoadingTaskRunner(blink::WebTaskRunner*) | 425 void AssociatedURLLoader::setLoadingTaskRunner(blink::WebTaskRunner*) |
| 388 { | 426 { |
| 389 // TODO(alexclarke): Maybe support this one day if it proves worthwhile. | 427 // TODO(alexclarke): Maybe support this one day if it proves worthwhile. |
| 390 } | 428 } |
| 391 | 429 |
| 430 void AssociatedURLLoader::documentDestroyed() | |
| 431 { | |
| 432 cancel(); | |
| 433 | |
| 434 m_client->didFail(this, ResourceError()); | |
| 435 // |this| may be dead here. | |
| 436 } | |
| 437 | |
| 438 void AssociatedURLLoader::disposeObserver() | |
| 439 { | |
| 440 if (!m_observer) | |
| 441 return; | |
| 442 | |
| 443 // The method of detecting Document destruction implemented here doesn't | |
|
haraken
2016/04/08 07:34:13
Add TODO.
tyoshino (SeeGerritForStatus)
2016/04/08 07:56:58
Done.
| |
| 444 // work for all kinds of Documents. In case we reached here after the | |
| 445 // Oilpan is destroyed, we just crash the renderer process to prevent UaF. | |
|
haraken
2016/04/08 07:34:13
Sorry, how does this cause UaF?
tyoshino (SeeGerritForStatus)
2016/04/08 07:56:58
m_observer is on-heap. If the Oilpan is already sh
| |
| 446 RELEASE_ASSERT(ThreadState::current()); | |
| 447 | |
| 448 m_observer->dispose(); | |
| 449 m_observer = nullptr; | |
| 450 } | |
| 451 | |
| 392 } // namespace blink | 452 } // namespace blink |
| OLD | NEW |