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

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

Issue 273993002: Allow XHR timeout attribute to be overridden after send(), per spec (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Avoid potential race-condition between load and timeout Created 6 years, 7 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
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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 } 69 }
70 70
71 DocumentThreadableLoader::DocumentThreadableLoader(Document& document, Threadabl eLoaderClient* client, BlockingBehavior blockingBehavior, const ResourceRequest& request, const ThreadableLoaderOptions& options) 71 DocumentThreadableLoader::DocumentThreadableLoader(Document& document, Threadabl eLoaderClient* client, BlockingBehavior blockingBehavior, const ResourceRequest& request, const ThreadableLoaderOptions& options)
72 : m_client(client) 72 : m_client(client)
73 , m_document(document) 73 , m_document(document)
74 , m_options(options) 74 , m_options(options)
75 , m_sameOriginRequest(securityOrigin()->canRequest(request.url())) 75 , m_sameOriginRequest(securityOrigin()->canRequest(request.url()))
76 , m_simpleRequest(true) 76 , m_simpleRequest(true)
77 , m_async(blockingBehavior == LoadAsynchronously) 77 , m_async(blockingBehavior == LoadAsynchronously)
78 , m_timeoutTimer(this, &DocumentThreadableLoader::didTimeout) 78 , m_timeoutTimer(this, &DocumentThreadableLoader::didTimeout)
79 , m_requestStarted(0.0)
79 { 80 {
80 ASSERT(client); 81 ASSERT(client);
81 // Setting an outgoing referer is only supported in the async code path. 82 // Setting an outgoing referer is only supported in the async code path.
82 ASSERT(m_async || request.httpReferrer().isEmpty()); 83 ASSERT(m_async || request.httpReferrer().isEmpty());
83 84
85 m_requestStarted = monotonicallyIncreasingTime();
86
84 // Save any CORS simple headers on the request here. If this request redirec ts cross-origin, we cancel the old request 87 // Save any CORS simple headers on the request here. If this request redirec ts cross-origin, we cancel the old request
85 // create a new one, and copy these headers. 88 // create a new one, and copy these headers.
86 const HTTPHeaderMap& headerMap = request.httpHeaderFields(); 89 const HTTPHeaderMap& headerMap = request.httpHeaderFields();
87 HTTPHeaderMap::const_iterator end = headerMap.end(); 90 HTTPHeaderMap::const_iterator end = headerMap.end();
88 for (HTTPHeaderMap::const_iterator it = headerMap.begin(); it != end; ++it) { 91 for (HTTPHeaderMap::const_iterator it = headerMap.begin(); it != end; ++it) {
89 if (isOnAccessControlSimpleRequestHeaderWhitelist(it->key, it->value)) 92 if (isOnAccessControlSimpleRequestHeaderWhitelist(it->key, it->value))
90 m_simpleRequestHeaders.add(it->key, it->value); 93 m_simpleRequestHeaders.add(it->key, it->value);
91 } 94 }
92 95
93 if (m_sameOriginRequest || m_options.crossOriginRequestPolicy == AllowCrossO riginRequests) { 96 if (m_sameOriginRequest || m_options.crossOriginRequestPolicy == AllowCrossO riginRequests) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 ResourceRequest preflightRequest = createAccessControlPreflightReque st(*m_actualRequest, securityOrigin()); 134 ResourceRequest preflightRequest = createAccessControlPreflightReque st(*m_actualRequest, securityOrigin());
132 loadRequest(preflightRequest); 135 loadRequest(preflightRequest);
133 } 136 }
134 } 137 }
135 } 138 }
136 139
137 DocumentThreadableLoader::~DocumentThreadableLoader() 140 DocumentThreadableLoader::~DocumentThreadableLoader()
138 { 141 {
139 } 142 }
140 143
144 void DocumentThreadableLoader::overrideTimeout(unsigned long timeoutMilliseconds )
145 {
146 if (!m_async)
147 return;
148 m_timeoutTimer.stop();
149 // At the time of this method's implementation, it is only ever called by
150 // XMLHttpRequest, when the timeout attribute is set after sending the
151 // request.
152 //
153 // The XHR request says to resolve the time relative to when the request
154 // was initially sent, however other uses of this method may need to
155 // behave differently, in which case this should be re-arranged somehow.
156 if (timeoutMilliseconds && m_requestStarted > 0.0) {
157 double elapsedTime = monotonicallyIncreasingTime() - m_requestStarted;
158 double nextFire = timeoutMilliseconds / 1000.0;
159 double resolvedTime = nextFire > elapsedTime ? nextFire - elapsedTime : 0.0;
eseidel 2014/05/21 21:41:50 std:min(nextfire - elapsedTime, 0) may be simpler.
160 m_timeoutTimer.startOneShot(resolvedTime, FROM_HERE);
161 }
162 }
163
141 void DocumentThreadableLoader::cancel() 164 void DocumentThreadableLoader::cancel()
142 { 165 {
143 cancelWithError(ResourceError()); 166 cancelWithError(ResourceError());
144 } 167 }
145 168
146 void DocumentThreadableLoader::cancelWithError(const ResourceError& error) 169 void DocumentThreadableLoader::cancelWithError(const ResourceError& error)
147 { 170 {
148 RefPtr<DocumentThreadableLoader> protect(this); 171 RefPtr<DocumentThreadableLoader> protect(this);
149 172
150 // Cancel can re-enter and m_resource might be null here as a result. 173 // Cancel can re-enter and m_resource might be null here as a result.
151 if (m_client && resource()) { 174 if (m_client && resource()) {
152 ResourceError errorForCallback = error; 175 ResourceError errorForCallback = error;
153 if (errorForCallback.isNull()) { 176 if (errorForCallback.isNull()) {
154 // FIXME: This error is sent to the client in didFail(), so it shoul d not be an internal one. Use FrameLoaderClient::cancelledError() instead. 177 // FIXME: This error is sent to the client in didFail(), so it shoul d not be an internal one. Use FrameLoaderClient::cancelledError() instead.
155 errorForCallback = ResourceError(errorDomainBlinkInternal, 0, resour ce()->url().string(), "Load cancelled"); 178 errorForCallback = ResourceError(errorDomainBlinkInternal, 0, resour ce()->url().string(), "Load cancelled");
156 errorForCallback.setIsCancellation(true); 179 errorForCallback.setIsCancellation(true);
157 } 180 }
158 m_client->didFail(errorForCallback); 181 m_client->didFail(errorForCallback);
159 } 182 }
160 clearResource(); 183 clearResource();
161 m_client = 0; 184 m_client = 0;
185 m_requestStarted = 0.0;
162 } 186 }
163 187
164 void DocumentThreadableLoader::setDefersLoading(bool value) 188 void DocumentThreadableLoader::setDefersLoading(bool value)
165 { 189 {
166 if (resource()) 190 if (resource())
167 resource()->setDefersLoading(value); 191 resource()->setDefersLoading(value);
168 } 192 }
169 193
170 void DocumentThreadableLoader::redirectReceived(Resource* resource, ResourceRequ est& request, const ResourceResponse& redirectResponse) 194 void DocumentThreadableLoader::redirectReceived(Resource* resource, ResourceRequ est& request, const ResourceResponse& redirectResponse)
171 { 195 {
172 ASSERT(m_client); 196 ASSERT(m_client);
173 ASSERT_UNUSED(resource, resource == this->resource()); 197 ASSERT_UNUSED(resource, resource == this->resource());
174 198
175 RefPtr<DocumentThreadableLoader> protect(this); 199 RefPtr<DocumentThreadableLoader> protect(this);
176 if (!isAllowedByPolicy(request.url())) { 200 if (!isAllowedByPolicy(request.url())) {
177 m_client->didFailRedirectCheck(); 201 m_client->didFailRedirectCheck();
178 request = ResourceRequest(); 202 request = ResourceRequest();
tyoshino (SeeGerritForStatus) 2014/05/28 02:21:26 m_requestStarted = 0.0;
179 return; 203 return;
180 } 204 }
181 205
182 // Allow same origin requests to continue after allowing clients to audit th e redirect. 206 // Allow same origin requests to continue after allowing clients to audit th e redirect.
183 if (isAllowedRedirect(request.url())) { 207 if (isAllowedRedirect(request.url())) {
184 if (m_client->isDocumentThreadableLoaderClient()) 208 if (m_client->isDocumentThreadableLoaderClient())
185 static_cast<DocumentThreadableLoaderClient*>(m_client)->willSendRequ est(request, redirectResponse); 209 static_cast<DocumentThreadableLoaderClient*>(m_client)->willSendRequ est(request, redirectResponse);
186 return; 210 return;
187 } 211 }
188 212
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 } 258 }
235 makeCrossOriginAccessRequest(request); 259 makeCrossOriginAccessRequest(request);
236 return; 260 return;
237 } 261 }
238 262
239 ResourceError error(errorDomainBlinkInternal, 0, redirectResponse.url(). string(), accessControlErrorDescription); 263 ResourceError error(errorDomainBlinkInternal, 0, redirectResponse.url(). string(), accessControlErrorDescription);
240 m_client->didFailAccessControlCheck(error); 264 m_client->didFailAccessControlCheck(error);
241 } else { 265 } else {
242 m_client->didFailRedirectCheck(); 266 m_client->didFailRedirectCheck();
243 } 267 }
244 request = ResourceRequest(); 268 request = ResourceRequest();
tyoshino (SeeGerritForStatus) 2014/05/28 02:21:26 m_requestStarted = 0.0;
245 } 269 }
246 270
247 void DocumentThreadableLoader::dataSent(Resource* resource, unsigned long long b ytesSent, unsigned long long totalBytesToBeSent) 271 void DocumentThreadableLoader::dataSent(Resource* resource, unsigned long long b ytesSent, unsigned long long totalBytesToBeSent)
248 { 272 {
249 ASSERT(m_client); 273 ASSERT(m_client);
250 ASSERT_UNUSED(resource, resource == this->resource()); 274 ASSERT_UNUSED(resource, resource == this->resource());
251 m_client->didSendData(bytesSent, totalBytesToBeSent); 275 m_client->didSendData(bytesSent, totalBytesToBeSent);
252 } 276 }
253 277
254 void DocumentThreadableLoader::dataDownloaded(Resource* resource, int dataLength ) 278 void DocumentThreadableLoader::dataDownloaded(Resource* resource, int dataLength )
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 { 354 {
331 ASSERT(m_client); 355 ASSERT(m_client);
332 ASSERT(resource == this->resource()); 356 ASSERT(resource == this->resource());
333 357
334 m_timeoutTimer.stop(); 358 m_timeoutTimer.stop();
335 359
336 if (resource->errorOccurred()) 360 if (resource->errorOccurred())
337 m_client->didFail(resource->resourceError()); 361 m_client->didFail(resource->resourceError());
338 else 362 else
339 didFinishLoading(resource->identifier(), resource->loadFinishTime()); 363 didFinishLoading(resource->identifier(), resource->loadFinishTime());
364
365 m_requestStarted = 0.0;
tyoshino (SeeGerritForStatus) 2014/05/28 02:21:26 not here. see below
340 } 366 }
341 367
342 void DocumentThreadableLoader::didFinishLoading(unsigned long identifier, double finishTime) 368 void DocumentThreadableLoader::didFinishLoading(unsigned long identifier, double finishTime)
343 { 369 {
344 if (m_actualRequest) { 370 if (m_actualRequest) {
345 ASSERT(!m_sameOriginRequest); 371 ASSERT(!m_sameOriginRequest);
346 ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); 372 ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl);
347 preflightSuccess(); 373 preflightSuccess();
348 } else 374 } else
349 m_client->didFinishLoading(identifier, finishTime); 375 m_client->didFinishLoading(identifier, finishTime);
tyoshino (SeeGerritForStatus) 2014/05/28 02:21:26 m_requestStarted = 0.0; inside else block
350 } 376 }
351 377
352 void DocumentThreadableLoader::didTimeout(Timer<DocumentThreadableLoader>* timer ) 378 void DocumentThreadableLoader::didTimeout(Timer<DocumentThreadableLoader>* timer )
353 { 379 {
354 ASSERT_UNUSED(timer, timer == &m_timeoutTimer); 380 ASSERT_UNUSED(timer, timer == &m_timeoutTimer);
355 381
356 // Using values from net/base/net_error_list.h ERR_TIMED_OUT, 382 // Using values from net/base/net_error_list.h ERR_TIMED_OUT,
357 // Same as existing FIXME above - this error should be coming from FrameLoad erClient to be identifiable. 383 // Same as existing FIXME above - this error should be coming from FrameLoad erClient to be identifiable.
358 static const int timeoutError = -7; 384 static const int timeoutError = -7;
359 ResourceError error("net", timeoutError, resource()->url(), String()); 385 ResourceError error("net", timeoutError, resource()->url(), String());
(...skipping 10 matching lines...) Expand all
370 396
371 clearResource(); 397 clearResource();
372 398
373 loadRequest(*actualRequest); 399 loadRequest(*actualRequest);
374 } 400 }
375 401
376 void DocumentThreadableLoader::preflightFailure(const String& url, const String& errorDescription) 402 void DocumentThreadableLoader::preflightFailure(const String& url, const String& errorDescription)
377 { 403 {
378 ResourceError error(errorDomainBlinkInternal, 0, url, errorDescription); 404 ResourceError error(errorDomainBlinkInternal, 0, url, errorDescription);
379 m_actualRequest = nullptr; // Prevent didFinishLoading() from bypassing acce ss check. 405 m_actualRequest = nullptr; // Prevent didFinishLoading() from bypassing acce ss check.
380 m_client->didFailAccessControlCheck(error); 406 m_client->didFailAccessControlCheck(error);
tyoshino (SeeGerritForStatus) 2014/05/28 02:21:26 m_requestStarted = 0.0;
381 } 407 }
382 408
383 void DocumentThreadableLoader::loadRequest(const ResourceRequest& request) 409 void DocumentThreadableLoader::loadRequest(const ResourceRequest& request)
384 { 410 {
385 // Any credential should have been removed from the cross-site requests. 411 // Any credential should have been removed from the cross-site requests.
386 const KURL& requestURL = request.url(); 412 const KURL& requestURL = request.url();
387 ASSERT(m_sameOriginRequest || requestURL.user().isEmpty()); 413 ASSERT(m_sameOriginRequest || requestURL.user().isEmpty());
388 ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty()); 414 ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty());
389 415
390 ThreadableLoaderOptions options = m_options; 416 ThreadableLoaderOptions options = m_options;
(...skipping 21 matching lines...) Expand all
412 438
413 FetchRequest fetchRequest(request, m_options.initiator, options); 439 FetchRequest fetchRequest(request, m_options.initiator, options);
414 ResourcePtr<Resource> resource = m_document.fetcher()->fetchSynchronously(fe tchRequest); 440 ResourcePtr<Resource> resource = m_document.fetcher()->fetchSynchronously(fe tchRequest);
415 ResourceResponse response = resource ? resource->response() : ResourceRespon se(); 441 ResourceResponse response = resource ? resource->response() : ResourceRespon se();
416 unsigned long identifier = resource ? resource->identifier() : std::numeric_ limits<unsigned long>::max(); 442 unsigned long identifier = resource ? resource->identifier() : std::numeric_ limits<unsigned long>::max();
417 ResourceError error = resource ? resource->resourceError() : ResourceError() ; 443 ResourceError error = resource ? resource->resourceError() : ResourceError() ;
418 444
419 InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient(&m _document, identifier, m_client); 445 InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient(&m _document, identifier, m_client);
420 446
421 if (!resource) { 447 if (!resource) {
422 m_client->didFail(error); 448 m_client->didFail(error);
tyoshino (SeeGerritForStatus) 2014/05/28 02:21:26 m_requestStarted = 0.0; unnecessary for sync case
423 return; 449 return;
424 } 450 }
425 451
426 // No exception for file:/// resources, see <rdar://problem/4962298>. 452 // No exception for file:/// resources, see <rdar://problem/4962298>.
427 // Also, if we have an HTTP response, then it wasn't a network error in fact . 453 // Also, if we have an HTTP response, then it wasn't a network error in fact .
428 if (!error.isNull() && !requestURL.isLocalFile() && response.httpStatusCode( ) <= 0) { 454 if (!error.isNull() && !requestURL.isLocalFile() && response.httpStatusCode( ) <= 0) {
429 m_client->didFail(error); 455 m_client->didFail(error);
tyoshino (SeeGerritForStatus) 2014/05/28 02:21:26 m_requestStarted = 0.0; unnecessary for sync case
430 return; 456 return;
431 } 457 }
432 458
433 // FIXME: A synchronous request does not tell us whether a redirect happened or not, so we guess by comparing the 459 // FIXME: A synchronous request does not tell us whether a redirect happened or not, so we guess by comparing the
434 // 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 460 // 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
435 // requested. Also comparing the request and response URLs as strings will f ail if the requestURL still has its credentials. 461 // requested. Also comparing the request and response URLs as strings will f ail if the requestURL still has its credentials.
436 if (requestURL != response.url() && (!isAllowedByPolicy(response.url()) || ! isAllowedRedirect(response.url()))) { 462 if (requestURL != response.url() && (!isAllowedByPolicy(response.url()) || ! isAllowedRedirect(response.url()))) {
437 m_client->didFailRedirectCheck(); 463 m_client->didFailRedirectCheck();
tyoshino (SeeGerritForStatus) 2014/05/28 02:21:26 m_requestStarted = 0.0; unnecessary for sync case
438 return; 464 return;
439 } 465 }
440 466
441 didReceiveResponse(identifier, response); 467 didReceiveResponse(identifier, response);
442 468
443 SharedBuffer* data = resource->resourceBuffer(); 469 SharedBuffer* data = resource->resourceBuffer();
444 if (data) 470 if (data)
445 didReceiveData(data->data(), data->size()); 471 didReceiveData(data->data(), data->size());
446 472
447 didFinishLoading(identifier, 0.0); 473 didFinishLoading(identifier, 0.0);
(...skipping 13 matching lines...) Expand all
461 return true; 487 return true;
462 return m_document.contentSecurityPolicy()->allowConnectToSource(url); 488 return m_document.contentSecurityPolicy()->allowConnectToSource(url);
463 } 489 }
464 490
465 SecurityOrigin* DocumentThreadableLoader::securityOrigin() const 491 SecurityOrigin* DocumentThreadableLoader::securityOrigin() const
466 { 492 {
467 return m_options.securityOrigin ? m_options.securityOrigin.get() : m_documen t.securityOrigin(); 493 return m_options.securityOrigin ? m_options.securityOrigin.get() : m_documen t.securityOrigin();
468 } 494 }
469 495
470 } // namespace WebCore 496 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698