Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(246)

Side by Side Diff: Source/core/loader/DocumentThreadableLoader.cpp

Issue 1262593004: Prevent ThreadableLoaderClient methods from being called after failure notification (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/core/loader/DocumentThreadableLoader.h ('k') | Source/core/loader/ThreadableLoader.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved. 2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
3 * Copyright (C) 2013, Intel Corporation 3 * Copyright (C) 2013, Intel Corporation
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are 6 * modification, are permitted provided that the following conditions are
7 * met: 7 * met:
8 * 8 *
9 * * Redistributions of source code must retain the above copyright 9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 , m_timeoutTimer(this, &DocumentThreadableLoader::didTimeout) 138 , m_timeoutTimer(this, &DocumentThreadableLoader::didTimeout)
139 , m_requestStartedSeconds(0.0) 139 , m_requestStartedSeconds(0.0)
140 , m_corsRedirectLimit(kMaxCORSRedirects) 140 , m_corsRedirectLimit(kMaxCORSRedirects)
141 , m_redirectMode(request.fetchRedirectMode()) 141 , m_redirectMode(request.fetchRedirectMode())
142 { 142 {
143 ASSERT(client); 143 ASSERT(client);
144 // Setting an outgoing referer is only supported in the async code path. 144 // Setting an outgoing referer is only supported in the async code path.
145 ASSERT(m_async || request.httpReferrer().isEmpty()); 145 ASSERT(m_async || request.httpReferrer().isEmpty());
146 146
147 if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == DenyCrossO riginRequests) { 147 if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == DenyCrossO riginRequests) {
148 m_client->didFail(ResourceError(errorDomainBlinkInternal, 0, request.url ().string(), "Cross origin requests are not supported.")); 148 ThreadableLoaderClient* client = m_client;
149 clear();
150 client->didFail(ResourceError(errorDomainBlinkInternal, 0, request.url() .string(), "Cross origin requests are not supported."));
151 // |this| may be dead here.
149 return; 152 return;
150 } 153 }
151 154
152 m_requestStartedSeconds = monotonicallyIncreasingTime(); 155 m_requestStartedSeconds = monotonicallyIncreasingTime();
153 156
154 // Save any CORS simple headers on the request here. If this request redirec ts cross-origin, we cancel the old request 157 // Save any CORS simple headers on the request here. If this request redirec ts cross-origin, we cancel the old request
155 // create a new one, and copy these headers. 158 // create a new one, and copy these headers.
156 const HTTPHeaderMap& headerMap = request.httpHeaderFields(); 159 const HTTPHeaderMap& headerMap = request.httpHeaderFields();
157 for (const auto& header : headerMap) { 160 for (const auto& header : headerMap) {
158 if (FetchUtils::isSimpleHeader(header.key, header.value)) 161 if (FetchUtils::isSimpleHeader(header.key, header.value))
(...skipping 20 matching lines...) Expand all
179 newRequest.setFetchRequestMode(WebURLRequest::FetchRequestModeCORS); 182 newRequest.setFetchRequestMode(WebURLRequest::FetchRequestModeCORS);
180 183
181 m_fallbackRequestForServiceWorker = adoptPtr(new ResourceRequest(request )); 184 m_fallbackRequestForServiceWorker = adoptPtr(new ResourceRequest(request ));
182 m_fallbackRequestForServiceWorker->setSkipServiceWorker(true); 185 m_fallbackRequestForServiceWorker->setSkipServiceWorker(true);
183 186
184 loadRequest(newRequest, m_resourceLoaderOptions); 187 loadRequest(newRequest, m_resourceLoaderOptions);
185 return; 188 return;
186 } 189 }
187 190
188 dispatchInitialRequest(request); 191 dispatchInitialRequest(request);
192 // |this| may be dead here in async mode.
189 } 193 }
190 194
191 void DocumentThreadableLoader::dispatchInitialRequest(const ResourceRequest& req uest) 195 void DocumentThreadableLoader::dispatchInitialRequest(const ResourceRequest& req uest)
192 { 196 {
193 if (m_sameOriginRequest || m_options.crossOriginRequestPolicy == AllowCrossO riginRequests) { 197 if (m_sameOriginRequest || m_options.crossOriginRequestPolicy == AllowCrossO riginRequests) {
194 loadRequest(request, m_resourceLoaderOptions); 198 loadRequest(request, m_resourceLoaderOptions);
195 return; 199 return;
196 } 200 }
197 201
198 ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); 202 ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl);
199 203
200 makeCrossOriginAccessRequest(request); 204 makeCrossOriginAccessRequest(request);
205 // |this| may be dead here in async mode.
201 } 206 }
202 207
203 void DocumentThreadableLoader::makeCrossOriginAccessRequest(const ResourceReques t& request) 208 void DocumentThreadableLoader::makeCrossOriginAccessRequest(const ResourceReques t& request)
204 { 209 {
205 ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); 210 ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl);
211 ASSERT(m_client);
212 ASSERT(!resource());
206 213
207 // Cross-origin requests are only allowed certain registered schemes. 214 // Cross-origin requests are only allowed certain registered schemes.
208 // We would catch this when checking response headers later, but there 215 // We would catch this when checking response headers later, but there
209 // is no reason to send a request, preflighted or not, that's guaranteed 216 // is no reason to send a request, preflighted or not, that's guaranteed
210 // to be denied. 217 // to be denied.
211 if (!SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(request.url().protoco l())) { 218 if (!SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(request.url().protoco l())) {
212 m_client->didFailAccessControlCheck(ResourceError(errorDomainBlinkIntern al, 0, request.url().string(), "Cross origin requests are only supported for pro tocol schemes: " + SchemeRegistry::listOfCORSEnabledURLSchemes() + ".")); 219 ThreadableLoaderClient* client = m_client;
220 clear();
221 client->didFailAccessControlCheck(ResourceError(errorDomainBlinkInternal , 0, request.url().string(), "Cross origin requests are only supported for proto col schemes: " + SchemeRegistry::listOfCORSEnabledURLSchemes() + "."));
222 // |this| may be dead here in async mode.
213 return; 223 return;
214 } 224 }
215 225
216 // We use isSimpleOrForbiddenRequest() here since |request| may have been 226 // We use isSimpleOrForbiddenRequest() here since |request| may have been
217 // modified in the process of loading (not from the user's input). For 227 // modified in the process of loading (not from the user's input). For
218 // example, referrer. We need to accept them. For security, we must reject 228 // example, referrer. We need to accept them. For security, we must reject
219 // forbidden headers/methods at the point we accept user's input. Not here. 229 // forbidden headers/methods at the point we accept user's input. Not here.
220 if ((m_options.preflightPolicy == ConsiderPreflight && FetchUtils::isSimpleO rForbiddenRequest(request.httpMethod(), request.httpHeaderFields())) || m_option s.preflightPolicy == PreventPreflight) { 230 if ((m_options.preflightPolicy == ConsiderPreflight && FetchUtils::isSimpleO rForbiddenRequest(request.httpMethod(), request.httpHeaderFields())) || m_option s.preflightPolicy == PreventPreflight) {
221 ResourceRequest crossOriginRequest(request); 231 ResourceRequest crossOriginRequest(request);
222 ResourceLoaderOptions crossOriginOptions(m_resourceLoaderOptions); 232 ResourceLoaderOptions crossOriginOptions(m_resourceLoaderOptions);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 double elapsedTime = monotonicallyIncreasingTime() - m_requestStartedSec onds; 276 double elapsedTime = monotonicallyIncreasingTime() - m_requestStartedSec onds;
267 double nextFire = timeoutMilliseconds / 1000.0; 277 double nextFire = timeoutMilliseconds / 1000.0;
268 double resolvedTime = std::max(nextFire - elapsedTime, 0.0); 278 double resolvedTime = std::max(nextFire - elapsedTime, 0.0);
269 m_timeoutTimer.startOneShot(resolvedTime, FROM_HERE); 279 m_timeoutTimer.startOneShot(resolvedTime, FROM_HERE);
270 } 280 }
271 } 281 }
272 282
273 void DocumentThreadableLoader::cancel() 283 void DocumentThreadableLoader::cancel()
274 { 284 {
275 cancelWithError(ResourceError()); 285 cancelWithError(ResourceError());
286 // |this| may be dead here.
276 } 287 }
277 288
278 void DocumentThreadableLoader::cancelWithError(const ResourceError& error) 289 void DocumentThreadableLoader::cancelWithError(const ResourceError& error)
279 { 290 {
280 RefPtr<DocumentThreadableLoader> protect(this); 291 // Cancel can re-enter and m_resource might be null here as a result.
292 if (!m_client || !resource()) {
293 clear();
294 return;
295 }
281 296
282 // Cancel can re-enter and m_resource might be null here as a result. 297 ResourceError errorForCallback = error;
283 if (m_client && resource()) { 298 if (errorForCallback.isNull()) {
284 ResourceError errorForCallback = error; 299 // FIXME: This error is sent to the client in didFail(), so it should no t be an internal one. Use FrameLoaderClient::cancelledError() instead.
285 if (errorForCallback.isNull()) { 300 errorForCallback = ResourceError(errorDomainBlinkInternal, 0, resource() ->url().string(), "Load cancelled");
286 // FIXME: This error is sent to the client in didFail(), so it shoul d not be an internal one. Use FrameLoaderClient::cancelledError() instead. 301 errorForCallback.setIsCancellation(true);
287 errorForCallback = ResourceError(errorDomainBlinkInternal, 0, resour ce()->url().string(), "Load cancelled");
288 errorForCallback.setIsCancellation(true);
289 }
290 m_client->didFail(errorForCallback);
291 } 302 }
292 clearResource(); 303
293 m_client = 0; 304 ThreadableLoaderClient* client = m_client;
294 m_requestStartedSeconds = 0.0; 305 clear();
306 client->didFail(errorForCallback);
307 // |this| may be dead here in async mode.
295 } 308 }
296 309
297 void DocumentThreadableLoader::setDefersLoading(bool value) 310 void DocumentThreadableLoader::setDefersLoading(bool value)
298 { 311 {
299 if (resource()) 312 if (resource())
300 resource()->setDefersLoading(value); 313 resource()->setDefersLoading(value);
301 } 314 }
302 315
316 void DocumentThreadableLoader::clear()
317 {
318 m_client = 0;
319
320 if (!m_async)
321 return;
322
323 clearResource();
324 m_timeoutTimer.stop();
325 m_requestStartedSeconds = 0.0;
326 }
327
303 // In this method, we can clear |request| to tell content::WebURLLoaderImpl of 328 // In this method, we can clear |request| to tell content::WebURLLoaderImpl of
304 // Chromium not to follow the redirect. This works only when this method is 329 // Chromium not to follow the redirect. This works only when this method is
305 // called by RawResource::willSendRequest(). If called by 330 // called by RawResource::willSendRequest(). If called by
306 // RawResource::didAddClient(), clearing |request| won't be propagated 331 // RawResource::didAddClient(), clearing |request| won't be propagated
307 // to content::WebURLLoaderImpl. So, this loader must also get detached from 332 // to content::WebURLLoaderImpl. So, this loader must also get detached from
308 // the resource by calling clearResource(). 333 // the resource by calling clearResource().
309 void DocumentThreadableLoader::redirectReceived(Resource* resource, ResourceRequ est& request, const ResourceResponse& redirectResponse) 334 void DocumentThreadableLoader::redirectReceived(Resource* resource, ResourceRequ est& request, const ResourceResponse& redirectResponse)
310 { 335 {
311 ASSERT(m_client); 336 ASSERT(m_client);
312 ASSERT_UNUSED(resource, resource == this->resource()); 337 ASSERT_UNUSED(resource, resource == this->resource());
313 ASSERT(m_async); 338 ASSERT(m_async);
314 339
315 RefPtr<DocumentThreadableLoader> protect(this); 340 RefPtr<DocumentThreadableLoader> protect(this);
hiroshige 2015/09/15 08:54:16 Is this |protect| needed? (This |protect| is remov
tyoshino (SeeGerritForStatus) 2015/09/15 13:29:34 Seems accidentally re-introduced on merge. But it
316 341
317 if (m_actualRequest) { 342 if (m_actualRequest) {
318 reportResponseReceived(resource->identifier(), redirectResponse); 343 reportResponseReceived(resource->identifier(), redirectResponse);
319 344
320 clearResource(); 345 handlePreflightFailure(redirectResponse.url().string(), "Response for pr eflight is invalid (redirect)");
346 // |this| may be dead here.
347
321 request = ResourceRequest(); 348 request = ResourceRequest();
322 349
323 m_requestStartedSeconds = 0.0;
324
325 handlePreflightFailure(redirectResponse.url().string(), "Response for pr eflight is invalid (redirect)");
326
327 return; 350 return;
328 } 351 }
329 352
330 if (m_redirectMode == WebURLRequest::FetchRedirectModeManual) { 353 if (m_redirectMode == WebURLRequest::FetchRedirectModeManual) {
331 // We use |m_redirectMode| to check the original redirect mode. 354 // We use |m_redirectMode| to check the original redirect mode.
332 // |request| is a new request for redirect. So we don't set the redirect 355 // |request| is a new request for redirect. So we don't set the redirect
333 // mode of it in WebURLLoaderImpl::Context::OnReceivedRedirect(). 356 // mode of it in WebURLLoaderImpl::Context::OnReceivedRedirect().
334 ASSERT(request.useStreamOnResponse()); 357 ASSERT(request.useStreamOnResponse());
335 // There is no need to read the body of redirect response because there 358 // There is no need to read the body of redirect response because there
336 // is no way to read the body of opaque-redirect filtered response's 359 // is no way to read the body of opaque-redirect filtered response's
337 // internal response. 360 // internal response.
338 // TODO(horo): If we support any API which expose the internal body, we 361 // TODO(horo): If we support any API which expose the internal body, we
339 // will have to read the body. And also HTTPCache changes will be needed 362 // will have to read the body. And also HTTPCache changes will be needed
340 // because it doesn't store the body of redirect responses. 363 // because it doesn't store the body of redirect responses.
341 responseReceived(resource, redirectResponse, adoptPtr(new EmptyDataHandl e())); 364 responseReceived(resource, redirectResponse, adoptPtr(new EmptyDataHandl e()));
342 notifyFinished(resource); 365
343 clearResource(); 366 if (resource->errorOccurred()) {
hiroshige 2015/09/15 08:54:17 What is the reason for calling handleError() / han
tyoshino (SeeGerritForStatus) 2015/09/15 13:29:34 Ah, after refactoring they became identical. Rever
367 handleError(resource->resourceError());
368 // |this| may be dead here.
369 } else {
370 handleSuccessfulActualRequestFinish(resource->identifier(), resource ->loadFinishTime());
371 // |this| may be dead here.
372 }
373
344 request = ResourceRequest(); 374 request = ResourceRequest();
375
345 return; 376 return;
346 } 377 }
347 378
348 if (m_redirectMode == WebURLRequest::FetchRedirectModeError || !isAllowedByC ontentSecurityPolicy(request.url(), ContentSecurityPolicy::DidRedirect)) { 379 if (m_redirectMode == WebURLRequest::FetchRedirectModeError || !isAllowedByC ontentSecurityPolicy(request.url(), ContentSecurityPolicy::DidRedirect)) {
349 m_client->didFailRedirectCheck(); 380 ThreadableLoaderClient* client = m_client;
381 clear();
382 client->didFailRedirectCheck();
383 // |this| may be dead here.
350 384
351 clearResource();
352 request = ResourceRequest(); 385 request = ResourceRequest();
353 386
354 m_requestStartedSeconds = 0.0;
355 return; 387 return;
356 } 388 }
357 389
358 // Allow same origin requests to continue after allowing clients to audit th e redirect. 390 // Allow same origin requests to continue after allowing clients to audit th e redirect.
359 if (isAllowedRedirect(request.url())) { 391 if (isAllowedRedirect(request.url())) {
360 if (m_client->isDocumentThreadableLoaderClient()) 392 if (m_client->isDocumentThreadableLoaderClient())
361 static_cast<DocumentThreadableLoaderClient*>(m_client)->willFollowRe direct(request, redirectResponse); 393 static_cast<DocumentThreadableLoaderClient*>(m_client)->willFollowRe direct(request, redirectResponse);
362 return; 394 return;
363 } 395 }
364 396
365 if (m_corsRedirectLimit <= 0) { 397 if (m_corsRedirectLimit <= 0) {
366 m_client->didFailRedirectCheck(); 398 ThreadableLoaderClient* client = m_client;
399 clear();
400 client->didFailRedirectCheck();
401 // |this| may be dead here.
367 } else if (m_options.crossOriginRequestPolicy == UseAccessControl) { 402 } else if (m_options.crossOriginRequestPolicy == UseAccessControl) {
368 --m_corsRedirectLimit; 403 --m_corsRedirectLimit;
369 404
370 InspectorInstrumentation::didReceiveCORSRedirectResponse(m_document.fram e(), resource->identifier(), m_document.frame()->loader().documentLoader(), redi rectResponse, 0); 405 InspectorInstrumentation::didReceiveCORSRedirectResponse(m_document.fram e(), resource->identifier(), m_document.frame()->loader().documentLoader(), redi rectResponse, 0);
371 406
372 bool allowRedirect = false; 407 bool allowRedirect = false;
373 String accessControlErrorDescription; 408 String accessControlErrorDescription;
374 409
375 // Non-simple cross origin requests (both preflight and actual one) are 410 // Non-simple cross origin requests (both preflight and actual one) are
376 // not allowed to follow redirect. 411 // not allowed to follow redirect.
(...skipping 27 matching lines...) Expand all
404 m_forceDoNotAllowStoredCredentials = true; 439 m_forceDoNotAllowStoredCredentials = true;
405 440
406 // Remove any headers that may have been added by the network layer that cause access control to fail. 441 // Remove any headers that may have been added by the network layer that cause access control to fail.
407 request.clearHTTPReferrer(); 442 request.clearHTTPReferrer();
408 request.clearHTTPOrigin(); 443 request.clearHTTPOrigin();
409 request.clearHTTPUserAgent(); 444 request.clearHTTPUserAgent();
410 // Add any CORS simple request headers which we previously saved fro m the original request. 445 // Add any CORS simple request headers which we previously saved fro m the original request.
411 for (const auto& header : m_simpleRequestHeaders) 446 for (const auto& header : m_simpleRequestHeaders)
412 request.setHTTPHeaderField(header.key, header.value); 447 request.setHTTPHeaderField(header.key, header.value);
413 makeCrossOriginAccessRequest(request); 448 makeCrossOriginAccessRequest(request);
449 // |this| may be dead here.
414 return; 450 return;
415 } 451 }
416 452
417 ResourceError error(errorDomainBlinkInternal, 0, redirectResponse.url(). string(), accessControlErrorDescription); 453 ThreadableLoaderClient* client = m_client;
418 m_client->didFailAccessControlCheck(error); 454 clear();
455 client->didFailAccessControlCheck(ResourceError(errorDomainBlinkInternal , 0, redirectResponse.url().string(), accessControlErrorDescription));
456 // |this| may be dead here.
419 } else { 457 } else {
420 m_client->didFailRedirectCheck(); 458 ThreadableLoaderClient* client = m_client;
459 clear();
460 client->didFailRedirectCheck();
461 // |this| may be dead here.
421 } 462 }
422 463
423 clearResource();
424 request = ResourceRequest(); 464 request = ResourceRequest();
425
426 m_requestStartedSeconds = 0.0;
427 } 465 }
428 466
429 void DocumentThreadableLoader::dataSent(Resource* resource, unsigned long long b ytesSent, unsigned long long totalBytesToBeSent) 467 void DocumentThreadableLoader::dataSent(Resource* resource, unsigned long long b ytesSent, unsigned long long totalBytesToBeSent)
430 { 468 {
431 ASSERT(m_client); 469 ASSERT(m_client);
432 ASSERT_UNUSED(resource, resource == this->resource()); 470 ASSERT_UNUSED(resource, resource == this->resource());
433 ASSERT(m_async); 471 ASSERT(m_async);
434 472
435 m_client->didSendData(bytesSent, totalBytesToBeSent); 473 m_client->didSendData(bytesSent, totalBytesToBeSent);
474 // |this| may be dead here.
436 } 475 }
437 476
438 void DocumentThreadableLoader::dataDownloaded(Resource* resource, int dataLength ) 477 void DocumentThreadableLoader::dataDownloaded(Resource* resource, int dataLength )
439 { 478 {
440 ASSERT(m_client); 479 ASSERT(m_client);
441 ASSERT_UNUSED(resource, resource == this->resource()); 480 ASSERT_UNUSED(resource, resource == this->resource());
442 ASSERT(!m_actualRequest); 481 ASSERT(!m_actualRequest);
443 ASSERT(m_async); 482 ASSERT(m_async);
444 483
445 m_client->didDownloadData(dataLength); 484 m_client->didDownloadData(dataLength);
485 // |this| may be dead here.
446 } 486 }
447 487
448 void DocumentThreadableLoader::didReceiveResourceTiming(Resource* resource, cons t ResourceTimingInfo& info) 488 void DocumentThreadableLoader::didReceiveResourceTiming(Resource* resource, cons t ResourceTimingInfo& info)
449 { 489 {
450 ASSERT(m_client); 490 ASSERT(m_client);
451 ASSERT_UNUSED(resource, resource == this->resource()); 491 ASSERT_UNUSED(resource, resource == this->resource());
452 ASSERT(m_async); 492 ASSERT(m_async);
453 493
454 m_client->didReceiveResourceTiming(info); 494 m_client->didReceiveResourceTiming(info);
495 // |this| may be dead here.
455 } 496 }
456 497
457 void DocumentThreadableLoader::responseReceived(Resource* resource, const Resour ceResponse& response, PassOwnPtr<WebDataConsumerHandle> handle) 498 void DocumentThreadableLoader::responseReceived(Resource* resource, const Resour ceResponse& response, PassOwnPtr<WebDataConsumerHandle> handle)
458 { 499 {
459 ASSERT_UNUSED(resource, resource == this->resource()); 500 ASSERT_UNUSED(resource, resource == this->resource());
460 ASSERT(m_async); 501 ASSERT(m_async);
461 502
462 if (handle) 503 if (handle)
463 m_isUsingDataConsumerHandle = true; 504 m_isUsingDataConsumerHandle = true;
464 505
465 handleResponse(resource->identifier(), response, handle); 506 handleResponse(resource->identifier(), response, handle);
507 // |this| may be dead here.
466 } 508 }
467 509
468 void DocumentThreadableLoader::handlePreflightResponse(const ResourceResponse& r esponse) 510 void DocumentThreadableLoader::handlePreflightResponse(const ResourceResponse& r esponse)
469 { 511 {
470 String accessControlErrorDescription; 512 String accessControlErrorDescription;
471 513
472 if (!passesAccessControlCheck(response, effectiveAllowCredentials(), securit yOrigin(), accessControlErrorDescription, m_requestContext)) { 514 if (!passesAccessControlCheck(response, effectiveAllowCredentials(), securit yOrigin(), accessControlErrorDescription, m_requestContext)) {
473 handlePreflightFailure(response.url().string(), "Response to preflight r equest doesn't pass access control check: " + accessControlErrorDescription); 515 handlePreflightFailure(response.url().string(), "Response to preflight r equest doesn't pass access control check: " + accessControlErrorDescription);
516 // |this| may be dead here in async mode.
474 return; 517 return;
475 } 518 }
476 519
477 if (!passesPreflightStatusCheck(response, accessControlErrorDescription)) { 520 if (!passesPreflightStatusCheck(response, accessControlErrorDescription)) {
478 handlePreflightFailure(response.url().string(), accessControlErrorDescri ption); 521 handlePreflightFailure(response.url().string(), accessControlErrorDescri ption);
522 // |this| may be dead here in async mode.
479 return; 523 return;
480 } 524 }
481 525
482 OwnPtr<CrossOriginPreflightResultCacheItem> preflightResult = adoptPtr(new C rossOriginPreflightResultCacheItem(effectiveAllowCredentials())); 526 OwnPtr<CrossOriginPreflightResultCacheItem> preflightResult = adoptPtr(new C rossOriginPreflightResultCacheItem(effectiveAllowCredentials()));
483 if (!preflightResult->parse(response, accessControlErrorDescription) 527 if (!preflightResult->parse(response, accessControlErrorDescription)
484 || !preflightResult->allowsCrossOriginMethod(m_actualRequest->httpMethod (), accessControlErrorDescription) 528 || !preflightResult->allowsCrossOriginMethod(m_actualRequest->httpMethod (), accessControlErrorDescription)
485 || !preflightResult->allowsCrossOriginHeaders(m_actualRequest->httpHeade rFields(), accessControlErrorDescription)) { 529 || !preflightResult->allowsCrossOriginHeaders(m_actualRequest->httpHeade rFields(), accessControlErrorDescription)) {
486 handlePreflightFailure(response.url().string(), accessControlErrorDescri ption); 530 handlePreflightFailure(response.url().string(), accessControlErrorDescri ption);
531 // |this| may be dead here in async mode.
487 return; 532 return;
488 } 533 }
489 534
490 CrossOriginPreflightResultCache::shared().appendEntry(securityOrigin()->toSt ring(), m_actualRequest->url(), preflightResult.release()); 535 CrossOriginPreflightResultCache::shared().appendEntry(securityOrigin()->toSt ring(), m_actualRequest->url(), preflightResult.release());
491 } 536 }
492 537
493 void DocumentThreadableLoader::reportResponseReceived(unsigned long identifier, const ResourceResponse& response) 538 void DocumentThreadableLoader::reportResponseReceived(unsigned long identifier, const ResourceResponse& response)
494 { 539 {
495 DocumentLoader* loader = m_document.frame()->loader().documentLoader(); 540 DocumentLoader* loader = m_document.frame()->loader().documentLoader();
496 TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceReceiveResponse", TRACE_E VENT_SCOPE_THREAD, "data", InspectorReceiveResponseEvent::data(identifier, m_doc ument.frame(), response)); 541 TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceReceiveResponse", TRACE_E VENT_SCOPE_THREAD, "data", InspectorReceiveResponseEvent::data(identifier, m_doc ument.frame(), response));
497 LocalFrame* frame = m_document.frame(); 542 LocalFrame* frame = m_document.frame();
498 InspectorInstrumentation::didReceiveResourceResponse(frame, identifier, load er, response, resource() ? resource()->loader() : 0); 543 InspectorInstrumentation::didReceiveResourceResponse(frame, identifier, load er, response, resource() ? resource()->loader() : 0);
499 frame->console().reportResourceResponseReceived(loader, identifier, response ); 544 frame->console().reportResourceResponseReceived(loader, identifier, response );
500 } 545 }
501 546
502 void DocumentThreadableLoader::handleResponse(unsigned long identifier, const Re sourceResponse& response, PassOwnPtr<WebDataConsumerHandle> handle) 547 void DocumentThreadableLoader::handleResponse(unsigned long identifier, const Re sourceResponse& response, PassOwnPtr<WebDataConsumerHandle> handle)
503 { 548 {
504 ASSERT(m_client); 549 ASSERT(m_client);
505 550
506 if (m_actualRequest) { 551 if (m_actualRequest) {
507 reportResponseReceived(identifier, response); 552 reportResponseReceived(identifier, response);
508 handlePreflightResponse(response); 553 handlePreflightResponse(response);
554 // |this| may be dead here in async mode.
509 return; 555 return;
510 } 556 }
511 557
512 if (response.wasFetchedViaServiceWorker()) { 558 if (response.wasFetchedViaServiceWorker()) {
513 // It's still possible to reach here with null m_fallbackRequestForServi ceWorker 559 // It's still possible to reach here with null m_fallbackRequestForServi ceWorker
514 // if the request was for main resource loading (i.e. for SharedWorker), for which 560 // if the request was for main resource loading (i.e. for SharedWorker), for which
515 // we create DocumentLoader before the controller ServiceWorker is set. 561 // we create DocumentLoader before the controller ServiceWorker is set.
516 ASSERT(m_fallbackRequestForServiceWorker || m_requestContext == WebURLRe quest::RequestContextSharedWorker); 562 ASSERT(m_fallbackRequestForServiceWorker || m_requestContext == WebURLRe quest::RequestContextSharedWorker);
517 if (response.wasFallbackRequiredByServiceWorker()) { 563 if (response.wasFallbackRequiredByServiceWorker()) {
518 // At this point we must have m_fallbackRequestForServiceWorker. 564 // At this point we must have m_fallbackRequestForServiceWorker.
519 // (For SharedWorker the request won't be CORS or CORS-with-prefligh t, 565 // (For SharedWorker the request won't be CORS or CORS-with-prefligh t,
520 // therefore fallback-to-network is handled in the browser process 566 // therefore fallback-to-network is handled in the browser process
521 // when the ServiceWorker does not call respondWith().) 567 // when the ServiceWorker does not call respondWith().)
522 ASSERT(m_fallbackRequestForServiceWorker); 568 ASSERT(m_fallbackRequestForServiceWorker);
523 reportResponseReceived(identifier, response); 569 reportResponseReceived(identifier, response);
524 loadFallbackRequestForServiceWorker(); 570 loadFallbackRequestForServiceWorker();
571 // |this| may be dead here in async mode.
525 return; 572 return;
526 } 573 }
527 m_fallbackRequestForServiceWorker = nullptr; 574 m_fallbackRequestForServiceWorker = nullptr;
528 m_client->didReceiveResponse(identifier, response, handle); 575 m_client->didReceiveResponse(identifier, response, handle);
529 return; 576 return;
530 } 577 }
531 578
532 // Even if the request met the conditions to get handled by a Service Worker 579 // Even if the request met the conditions to get handled by a Service Worker
533 // in the constructor of this class (and therefore 580 // in the constructor of this class (and therefore
534 // |m_fallbackRequestForServiceWorker| is set), the Service Worker may skip 581 // |m_fallbackRequestForServiceWorker| is set), the Service Worker may skip
535 // processing the request. Only if the request is same origin, the skipped 582 // processing the request. Only if the request is same origin, the skipped
536 // response may come here (wasFetchedViaServiceWorker() returns false) since 583 // response may come here (wasFetchedViaServiceWorker() returns false) since
537 // such a request doesn't have to go through the CORS algorithm by calling 584 // such a request doesn't have to go through the CORS algorithm by calling
538 // loadFallbackRequestForServiceWorker(). 585 // loadFallbackRequestForServiceWorker().
539 // FIXME: We should use |m_sameOriginRequest| when we will support 586 // FIXME: We should use |m_sameOriginRequest| when we will support
540 // Suborigins (crbug.com/336894) for Service Worker. 587 // Suborigins (crbug.com/336894) for Service Worker.
541 ASSERT(!m_fallbackRequestForServiceWorker || securityOrigin()->canRequest(m_ fallbackRequestForServiceWorker->url())); 588 ASSERT(!m_fallbackRequestForServiceWorker || securityOrigin()->canRequest(m_ fallbackRequestForServiceWorker->url()));
542 m_fallbackRequestForServiceWorker = nullptr; 589 m_fallbackRequestForServiceWorker = nullptr;
543 590
544 if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == UseAccessC ontrol) { 591 if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == UseAccessC ontrol) {
545 String accessControlErrorDescription; 592 String accessControlErrorDescription;
546 if (!passesAccessControlCheck(response, effectiveAllowCredentials(), sec urityOrigin(), accessControlErrorDescription, m_requestContext)) { 593 if (!passesAccessControlCheck(response, effectiveAllowCredentials(), sec urityOrigin(), accessControlErrorDescription, m_requestContext)) {
547 reportResponseReceived(identifier, response); 594 reportResponseReceived(identifier, response);
548 m_client->didFailAccessControlCheck(ResourceError(errorDomainBlinkIn ternal, 0, response.url().string(), accessControlErrorDescription)); 595
596 ThreadableLoaderClient* client = m_client;
597 clear();
598 client->didFailAccessControlCheck(ResourceError(errorDomainBlinkInte rnal, 0, response.url().string(), accessControlErrorDescription));
599 // |this| may be dead here.
549 return; 600 return;
550 } 601 }
551 } 602 }
552 603
553 m_client->didReceiveResponse(identifier, response, handle); 604 m_client->didReceiveResponse(identifier, response, handle);
554 } 605 }
555 606
556 void DocumentThreadableLoader::setSerializedCachedMetadata(Resource*, const char * data, size_t size) 607 void DocumentThreadableLoader::setSerializedCachedMetadata(Resource*, const char * data, size_t size)
557 { 608 {
558 if (m_actualRequest) 609 if (m_actualRequest)
559 return; 610 return;
560 m_client->didReceiveCachedMetadata(data, size); 611 m_client->didReceiveCachedMetadata(data, size);
612 // |this| may be dead here.
561 } 613 }
562 614
563 void DocumentThreadableLoader::dataReceived(Resource* resource, const char* data , unsigned dataLength) 615 void DocumentThreadableLoader::dataReceived(Resource* resource, const char* data , unsigned dataLength)
564 { 616 {
565 ASSERT_UNUSED(resource, resource == this->resource()); 617 ASSERT_UNUSED(resource, resource == this->resource());
566 ASSERT(m_async); 618 ASSERT(m_async);
567 619
568 if (m_isUsingDataConsumerHandle) 620 if (m_isUsingDataConsumerHandle)
569 return; 621 return;
570 622
571 handleReceivedData(data, dataLength); 623 handleReceivedData(data, dataLength);
624 // |this| may be dead here.
572 } 625 }
573 626
574 void DocumentThreadableLoader::handleReceivedData(const char* data, unsigned dat aLength) 627 void DocumentThreadableLoader::handleReceivedData(const char* data, unsigned dat aLength)
575 { 628 {
576 ASSERT(m_client); 629 ASSERT(m_client);
577 630
578 // Preflight data should be invisible to clients. 631 // Preflight data should be invisible to clients.
579 if (m_actualRequest) 632 if (m_actualRequest)
580 return; 633 return;
581 634
582 ASSERT(!m_fallbackRequestForServiceWorker); 635 ASSERT(!m_fallbackRequestForServiceWorker);
583 636
584 m_client->didReceiveData(data, dataLength); 637 m_client->didReceiveData(data, dataLength);
638 // |this| may be dead here in async mode.
585 } 639 }
586 640
587 void DocumentThreadableLoader::notifyFinished(Resource* resource) 641 void DocumentThreadableLoader::notifyFinished(Resource* resource)
588 { 642 {
589 ASSERT(m_client); 643 ASSERT(m_client);
590 ASSERT(resource == this->resource()); 644 ASSERT(resource == this->resource());
591 ASSERT(m_async); 645 ASSERT(m_async);
592 646
593 m_timeoutTimer.stop(); 647 if (resource->errorOccurred()) {
648 handleError(resource->resourceError());
649 // |this| may be dead here.
650 } else {
651 handleSuccessfulFinish(resource->identifier(), resource->loadFinishTime( ));
652 // |this| may be dead here.
653 }
654 }
594 655
595 if (resource->errorOccurred()) 656 void DocumentThreadableLoader::handleSuccessfulActualRequestFinish(unsigned long identifier, double finishTime)
596 m_client->didFail(resource->resourceError()); 657 {
597 else 658 ThreadableLoaderClient* client = m_client;
598 handleSuccessfulFinish(resource->identifier(), resource->loadFinishTime( )); 659 m_client = 0;
660 // Don't clear the resource as the client may need to access the downloaded
661 // file which will be released when the resource is destoryed.
662 if (m_async) {
663 m_timeoutTimer.stop();
664 m_requestStartedSeconds = 0.0;
665 }
666 client->didFinishLoading(identifier, finishTime);
667 // |this| may be dead here in async mode.
599 } 668 }
600 669
601 void DocumentThreadableLoader::handleSuccessfulFinish(unsigned long identifier, double finishTime) 670 void DocumentThreadableLoader::handleSuccessfulFinish(unsigned long identifier, double finishTime)
602 { 671 {
603 ASSERT(!m_fallbackRequestForServiceWorker); 672 ASSERT(!m_fallbackRequestForServiceWorker);
604 673
605 if (m_actualRequest) { 674 if (!m_actualRequest) {
606 ASSERT(!m_sameOriginRequest); 675 handleSuccessfulActualRequestFinish(identifier, finishTime);
607 ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); 676 // |this| may be dead here in async mode.
608 loadActualRequest(); 677 return;
609 } else {
610 // FIXME: Should prevent timeout from being overridden after finished lo ading, without
611 // resetting m_requestStartedSeconds to 0.0
612 m_client->didFinishLoading(identifier, finishTime);
613 } 678 }
679
680 // FIXME: Timeout should be applied to whole fetch, not for each of
681 // preflight and actual request.
682 m_timeoutTimer.stop();
683 ASSERT(!m_sameOriginRequest);
684 ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl);
685 loadActualRequest();
614 } 686 }
615 687
616 void DocumentThreadableLoader::didTimeout(Timer<DocumentThreadableLoader>* timer ) 688 void DocumentThreadableLoader::didTimeout(Timer<DocumentThreadableLoader>* timer )
617 { 689 {
618 ASSERT_UNUSED(timer, timer == &m_timeoutTimer); 690 ASSERT_UNUSED(timer, timer == &m_timeoutTimer);
619 691
620 // Using values from net/base/net_error_list.h ERR_TIMED_OUT, 692 // Using values from net/base/net_error_list.h ERR_TIMED_OUT,
621 // Same as existing FIXME above - this error should be coming from FrameLoad erClient to be identifiable. 693 // Same as existing FIXME above - this error should be coming from FrameLoad erClient to be identifiable.
622 static const int timeoutError = -7; 694 static const int timeoutError = -7;
623 ResourceError error("net", timeoutError, resource()->url(), String()); 695 ResourceError error("net", timeoutError, resource()->url(), String());
624 error.setIsTimeout(true); 696 error.setIsTimeout(true);
625 cancelWithError(error); 697 cancelWithError(error);
698 // |this| may be dead here.
626 } 699 }
627 700
628 void DocumentThreadableLoader::loadFallbackRequestForServiceWorker() 701 void DocumentThreadableLoader::loadFallbackRequestForServiceWorker()
629 { 702 {
630 clearResource(); 703 clearResource();
631 OwnPtr<ResourceRequest> fallbackRequest(m_fallbackRequestForServiceWorker.re lease()); 704 OwnPtr<ResourceRequest> fallbackRequest(m_fallbackRequestForServiceWorker.re lease());
632 dispatchInitialRequest(*fallbackRequest); 705 dispatchInitialRequest(*fallbackRequest);
706 // |this| may be dead here in async mode.
633 } 707 }
634 708
635 void DocumentThreadableLoader::loadActualRequest() 709 void DocumentThreadableLoader::loadActualRequest()
636 { 710 {
637 OwnPtr<ResourceRequest> actualRequest; 711 OwnPtr<ResourceRequest> actualRequest;
638 actualRequest.swap(m_actualRequest); 712 actualRequest.swap(m_actualRequest);
639 OwnPtr<ResourceLoaderOptions> actualOptions; 713 OwnPtr<ResourceLoaderOptions> actualOptions;
640 actualOptions.swap(m_actualOptions); 714 actualOptions.swap(m_actualOptions);
641 715
642 actualRequest->setHTTPOrigin(securityOrigin()->toAtomicString()); 716 actualRequest->setHTTPOrigin(securityOrigin()->toAtomicString());
643 717
644 clearResource(); 718 clearResource();
645 719
646 loadRequest(*actualRequest, *actualOptions); 720 loadRequest(*actualRequest, *actualOptions);
647 } 721 }
648 722
649 void DocumentThreadableLoader::handlePreflightFailure(const String& url, const S tring& errorDescription) 723 void DocumentThreadableLoader::handlePreflightFailure(const String& url, const S tring& errorDescription)
650 { 724 {
651 ResourceError error(errorDomainBlinkInternal, 0, url, errorDescription); 725 ResourceError error(errorDomainBlinkInternal, 0, url, errorDescription);
652 726
653 // Prevent handleSuccessfulFinish() from bypassing access check. 727 // Prevent handleSuccessfulFinish() from bypassing access check.
654 m_actualRequest = nullptr; 728 m_actualRequest = nullptr;
655 729
656 // FIXME: Should prevent timeout from being overridden after preflight failu re, without 730 ThreadableLoaderClient* client = m_client;
657 // resetting m_requestStartedSeconds to 0.0 731 clear();
658 m_client->didFailAccessControlCheck(error); 732 client->didFailAccessControlCheck(error);
733 // |this| may be dead here in async mode.
734 }
735
736 void DocumentThreadableLoader::handleError(const ResourceError& error)
737 {
738 // Copy the ResourceError instance to make it sure that the
739 // ResourceError outlive the resource for convenience.
hiroshige 2015/09/15 08:54:16 This sounds as if |copiedError| *always* outlive t
tyoshino (SeeGerritForStatus) 2015/09/15 13:29:34 Good point and nice rephrasing. Done
740 ResourceError copiedError = error;
741
742 ThreadableLoaderClient* client = m_client;
743 clear();
744 client->didFail(copiedError);
745 // |this| may be dead here.
659 } 746 }
660 747
661 void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, Resou rceLoaderOptions resourceLoaderOptions) 748 void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, Resou rceLoaderOptions resourceLoaderOptions)
662 { 749 {
663 // Any credential should have been removed from the cross-site requests. 750 // Any credential should have been removed from the cross-site requests.
664 const KURL& requestURL = request.url(); 751 const KURL& requestURL = request.url();
665 ASSERT(m_sameOriginRequest || requestURL.user().isEmpty()); 752 ASSERT(m_sameOriginRequest || requestURL.user().isEmpty());
666 ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty()); 753 ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty());
667 754
668 // Update resourceLoaderOptions with enforced values. 755 // Update resourceLoaderOptions with enforced values.
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
716 // FIXME: A synchronous request does not tell us whether a redirect happened or not, so we guess by comparing the 803 // FIXME: A synchronous request does not tell us whether a redirect happened or not, so we guess by comparing the
717 // request and response URLs. This isn't a perfect test though, since a serv er can serve a redirect to the same URL that was 804 // request and response URLs. This isn't a perfect test though, since a serv er can serve a redirect to the same URL that was
718 // requested. Also comparing the request and response URLs as strings will f ail if the requestURL still has its credentials. 805 // requested. Also comparing the request and response URLs as strings will f ail if the requestURL still has its credentials.
719 if (requestURL != response.url() && (!isAllowedByContentSecurityPolicy(respo nse.url(), ContentSecurityPolicy::DidRedirect) || !isAllowedRedirect(response.ur l()))) { 806 if (requestURL != response.url() && (!isAllowedByContentSecurityPolicy(respo nse.url(), ContentSecurityPolicy::DidRedirect) || !isAllowedRedirect(response.ur l()))) {
720 m_client->didFailRedirectCheck(); 807 m_client->didFailRedirectCheck();
721 return; 808 return;
722 } 809 }
723 810
724 handleResponse(identifier, response, nullptr); 811 handleResponse(identifier, response, nullptr);
725 812
813 // handleResponse() may detect an error. In such a case (check |m_client|
814 // as it gets reset by clear() call), skip the rest.
815 //
816 // |this| is alive here since loadResourceSynchronously() keeps it alive
817 // until the end of the function.
818 if (!m_client)
819 return;
820
726 SharedBuffer* data = resource->resourceBuffer(); 821 SharedBuffer* data = resource->resourceBuffer();
727 if (data) 822 if (data)
728 handleReceivedData(data->data(), data->size()); 823 handleReceivedData(data->data(), data->size());
729 824
hiroshige 2015/09/15 08:54:17 Do we need "if (!m_client) return" also here for c
tyoshino (SeeGerritForStatus) 2015/09/15 13:29:35 Right! We need to take care of cancel().
730 handleSuccessfulFinish(identifier, 0.0); 825 handleSuccessfulFinish(identifier, 0.0);
731 } 826 }
732 827
733 bool DocumentThreadableLoader::isAllowedRedirect(const KURL& url) const 828 bool DocumentThreadableLoader::isAllowedRedirect(const KURL& url) const
734 { 829 {
735 if (m_options.crossOriginRequestPolicy == AllowCrossOriginRequests) 830 if (m_options.crossOriginRequestPolicy == AllowCrossOriginRequests)
736 return true; 831 return true;
737 832
738 return m_sameOriginRequest && securityOrigin()->canRequest(url); 833 return m_sameOriginRequest && securityOrigin()->canRequest(url);
739 } 834 }
(...skipping 11 matching lines...) Expand all
751 return DoNotAllowStoredCredentials; 846 return DoNotAllowStoredCredentials;
752 return m_resourceLoaderOptions.allowCredentials; 847 return m_resourceLoaderOptions.allowCredentials;
753 } 848 }
754 849
755 SecurityOrigin* DocumentThreadableLoader::securityOrigin() const 850 SecurityOrigin* DocumentThreadableLoader::securityOrigin() const
756 { 851 {
757 return m_securityOrigin ? m_securityOrigin.get() : m_document.securityOrigin (); 852 return m_securityOrigin ? m_securityOrigin.get() : m_document.securityOrigin ();
758 } 853 }
759 854
760 } // namespace blink 855 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/loader/DocumentThreadableLoader.h ('k') | Source/core/loader/ThreadableLoader.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698