OLD | NEW |
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 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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_resourceLoaderOptions(resourceLoaderOptions) | 75 , m_resourceLoaderOptions(resourceLoaderOptions) |
76 , m_forceDoNotAllowStoredCredentials(false) | 76 , m_forceDoNotAllowStoredCredentials(false) |
77 , m_securityOrigin(m_resourceLoaderOptions.securityOrigin) | 77 , m_securityOrigin(m_resourceLoaderOptions.securityOrigin) |
78 , m_sameOriginRequest(securityOrigin()->canRequest(request.url())) | 78 , m_sameOriginRequest(securityOrigin()->canRequest(request.url())) |
79 , m_simpleRequest(true) | 79 , m_simpleRequest(true) |
80 , m_async(blockingBehavior == LoadAsynchronously) | 80 , m_async(blockingBehavior == LoadAsynchronously) |
81 , m_timeoutTimer(this, &DocumentThreadableLoader::didTimeout) | 81 , m_timeoutTimer(this, &DocumentThreadableLoader::didTimeout) |
82 , m_requestStartedSeconds(0.0) | |
83 { | 82 { |
84 ASSERT(client); | 83 ASSERT(client); |
85 // Setting an outgoing referer is only supported in the async code path. | 84 // Setting an outgoing referer is only supported in the async code path. |
86 ASSERT(m_async || request.httpReferrer().isEmpty()); | 85 ASSERT(m_async || request.httpReferrer().isEmpty()); |
87 | 86 |
88 m_requestStartedSeconds = monotonicallyIncreasingTime(); | |
89 | |
90 // 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 |
91 // create a new one, and copy these headers. | 88 // create a new one, and copy these headers. |
92 const HTTPHeaderMap& headerMap = request.httpHeaderFields(); | 89 const HTTPHeaderMap& headerMap = request.httpHeaderFields(); |
93 HTTPHeaderMap::const_iterator end = headerMap.end(); | 90 HTTPHeaderMap::const_iterator end = headerMap.end(); |
94 for (HTTPHeaderMap::const_iterator it = headerMap.begin(); it != end; ++it)
{ | 91 for (HTTPHeaderMap::const_iterator it = headerMap.begin(); it != end; ++it)
{ |
95 if (isOnAccessControlSimpleRequestHeaderWhitelist(it->key, it->value)) | 92 if (isOnAccessControlSimpleRequestHeaderWhitelist(it->key, it->value)) |
96 m_simpleRequestHeaders.add(it->key, it->value); | 93 m_simpleRequestHeaders.add(it->key, it->value); |
97 } | 94 } |
98 | 95 |
99 if (m_sameOriginRequest || m_options.crossOriginRequestPolicy == AllowCrossO
riginRequests) { | 96 if (m_sameOriginRequest || m_options.crossOriginRequestPolicy == AllowCrossO
riginRequests) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 preflightOptions.allowCredentials = DoNotAllowStoredCredentials; | 140 preflightOptions.allowCredentials = DoNotAllowStoredCredentials; |
144 loadRequest(preflightRequest, preflightOptions); | 141 loadRequest(preflightRequest, preflightOptions); |
145 } | 142 } |
146 } | 143 } |
147 } | 144 } |
148 | 145 |
149 DocumentThreadableLoader::~DocumentThreadableLoader() | 146 DocumentThreadableLoader::~DocumentThreadableLoader() |
150 { | 147 { |
151 } | 148 } |
152 | 149 |
153 void DocumentThreadableLoader::overrideTimeout(unsigned long timeoutMilliseconds
) | |
154 { | |
155 if (!m_async) | |
156 return; | |
157 m_timeoutTimer.stop(); | |
158 // At the time of this method's implementation, it is only ever called by | |
159 // XMLHttpRequest, when the timeout attribute is set after sending the | |
160 // request. | |
161 // | |
162 // The XHR request says to resolve the time relative to when the request | |
163 // was initially sent, however other uses of this method may need to | |
164 // behave differently, in which case this should be re-arranged somehow. | |
165 if (timeoutMilliseconds && m_requestStartedSeconds > 0.0) { | |
166 double elapsedTime = monotonicallyIncreasingTime() - m_requestStartedSec
onds; | |
167 double nextFire = timeoutMilliseconds / 1000.0; | |
168 double resolvedTime = std::max(nextFire - elapsedTime, 0.0); | |
169 m_timeoutTimer.startOneShot(resolvedTime, FROM_HERE); | |
170 } | |
171 } | |
172 | |
173 void DocumentThreadableLoader::cancel() | 150 void DocumentThreadableLoader::cancel() |
174 { | 151 { |
175 cancelWithError(ResourceError()); | 152 cancelWithError(ResourceError()); |
176 } | 153 } |
177 | 154 |
178 void DocumentThreadableLoader::cancelWithError(const ResourceError& error) | 155 void DocumentThreadableLoader::cancelWithError(const ResourceError& error) |
179 { | 156 { |
180 RefPtr<DocumentThreadableLoader> protect(this); | 157 RefPtr<DocumentThreadableLoader> protect(this); |
181 | 158 |
182 // Cancel can re-enter and m_resource might be null here as a result. | 159 // Cancel can re-enter and m_resource might be null here as a result. |
183 if (m_client && resource()) { | 160 if (m_client && resource()) { |
184 ResourceError errorForCallback = error; | 161 ResourceError errorForCallback = error; |
185 if (errorForCallback.isNull()) { | 162 if (errorForCallback.isNull()) { |
186 // FIXME: This error is sent to the client in didFail(), so it shoul
d not be an internal one. Use FrameLoaderClient::cancelledError() instead. | 163 // FIXME: This error is sent to the client in didFail(), so it shoul
d not be an internal one. Use FrameLoaderClient::cancelledError() instead. |
187 errorForCallback = ResourceError(errorDomainBlinkInternal, 0, resour
ce()->url().string(), "Load cancelled"); | 164 errorForCallback = ResourceError(errorDomainBlinkInternal, 0, resour
ce()->url().string(), "Load cancelled"); |
188 errorForCallback.setIsCancellation(true); | 165 errorForCallback.setIsCancellation(true); |
189 } | 166 } |
190 m_client->didFail(errorForCallback); | 167 m_client->didFail(errorForCallback); |
191 } | 168 } |
192 clearResource(); | 169 clearResource(); |
193 m_client = 0; | 170 m_client = 0; |
194 m_requestStartedSeconds = 0.0; | |
195 } | 171 } |
196 | 172 |
197 void DocumentThreadableLoader::setDefersLoading(bool value) | 173 void DocumentThreadableLoader::setDefersLoading(bool value) |
198 { | 174 { |
199 if (resource()) | 175 if (resource()) |
200 resource()->setDefersLoading(value); | 176 resource()->setDefersLoading(value); |
201 } | 177 } |
202 | 178 |
203 void DocumentThreadableLoader::redirectReceived(Resource* resource, ResourceRequ
est& request, const ResourceResponse& redirectResponse) | 179 void DocumentThreadableLoader::redirectReceived(Resource* resource, ResourceRequ
est& request, const ResourceResponse& redirectResponse) |
204 { | 180 { |
205 ASSERT(m_client); | 181 ASSERT(m_client); |
206 ASSERT_UNUSED(resource, resource == this->resource()); | 182 ASSERT_UNUSED(resource, resource == this->resource()); |
207 | 183 |
208 RefPtr<DocumentThreadableLoader> protect(this); | 184 RefPtr<DocumentThreadableLoader> protect(this); |
209 if (!isAllowedByPolicy(request.url())) { | 185 if (!isAllowedByPolicy(request.url())) { |
210 m_client->didFailRedirectCheck(); | 186 m_client->didFailRedirectCheck(); |
211 request = ResourceRequest(); | 187 request = ResourceRequest(); |
212 m_requestStartedSeconds = 0.0; | |
213 return; | 188 return; |
214 } | 189 } |
215 | 190 |
216 // Allow same origin requests to continue after allowing clients to audit th
e redirect. | 191 // Allow same origin requests to continue after allowing clients to audit th
e redirect. |
217 if (isAllowedRedirect(request.url())) { | 192 if (isAllowedRedirect(request.url())) { |
218 if (m_client->isDocumentThreadableLoaderClient()) | 193 if (m_client->isDocumentThreadableLoaderClient()) |
219 static_cast<DocumentThreadableLoaderClient*>(m_client)->willSendRequ
est(request, redirectResponse); | 194 static_cast<DocumentThreadableLoaderClient*>(m_client)->willSendRequ
est(request, redirectResponse); |
220 return; | 195 return; |
221 } | 196 } |
222 | 197 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
269 makeCrossOriginAccessRequest(request); | 244 makeCrossOriginAccessRequest(request); |
270 return; | 245 return; |
271 } | 246 } |
272 | 247 |
273 ResourceError error(errorDomainBlinkInternal, 0, redirectResponse.url().
string(), accessControlErrorDescription); | 248 ResourceError error(errorDomainBlinkInternal, 0, redirectResponse.url().
string(), accessControlErrorDescription); |
274 m_client->didFailAccessControlCheck(error); | 249 m_client->didFailAccessControlCheck(error); |
275 } else { | 250 } else { |
276 m_client->didFailRedirectCheck(); | 251 m_client->didFailRedirectCheck(); |
277 } | 252 } |
278 request = ResourceRequest(); | 253 request = ResourceRequest(); |
279 m_requestStartedSeconds = 0.0; | |
280 } | 254 } |
281 | 255 |
282 void DocumentThreadableLoader::dataSent(Resource* resource, unsigned long long b
ytesSent, unsigned long long totalBytesToBeSent) | 256 void DocumentThreadableLoader::dataSent(Resource* resource, unsigned long long b
ytesSent, unsigned long long totalBytesToBeSent) |
283 { | 257 { |
284 ASSERT(m_client); | 258 ASSERT(m_client); |
285 ASSERT_UNUSED(resource, resource == this->resource()); | 259 ASSERT_UNUSED(resource, resource == this->resource()); |
286 m_client->didSendData(bytesSent, totalBytesToBeSent); | 260 m_client->didSendData(bytesSent, totalBytesToBeSent); |
287 } | 261 } |
288 | 262 |
289 void DocumentThreadableLoader::dataDownloaded(Resource* resource, int dataLength
) | 263 void DocumentThreadableLoader::dataDownloaded(Resource* resource, int dataLength
) |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 else | 355 else |
382 handleSuccessfulFinish(resource->identifier(), resource->loadFinishTime(
)); | 356 handleSuccessfulFinish(resource->identifier(), resource->loadFinishTime(
)); |
383 } | 357 } |
384 | 358 |
385 void DocumentThreadableLoader::handleSuccessfulFinish(unsigned long identifier,
double finishTime) | 359 void DocumentThreadableLoader::handleSuccessfulFinish(unsigned long identifier,
double finishTime) |
386 { | 360 { |
387 if (m_actualRequest) { | 361 if (m_actualRequest) { |
388 ASSERT(!m_sameOriginRequest); | 362 ASSERT(!m_sameOriginRequest); |
389 ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); | 363 ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); |
390 loadActualRequest(); | 364 loadActualRequest(); |
391 } else { | 365 } else |
392 m_client->didFinishLoading(identifier, finishTime); | 366 m_client->didFinishLoading(identifier, finishTime); |
393 m_requestStartedSeconds = 0.0; | |
394 } | |
395 } | 367 } |
396 | 368 |
397 void DocumentThreadableLoader::didTimeout(Timer<DocumentThreadableLoader>* timer
) | 369 void DocumentThreadableLoader::didTimeout(Timer<DocumentThreadableLoader>* timer
) |
398 { | 370 { |
399 ASSERT_UNUSED(timer, timer == &m_timeoutTimer); | 371 ASSERT_UNUSED(timer, timer == &m_timeoutTimer); |
400 | 372 |
401 // Using values from net/base/net_error_list.h ERR_TIMED_OUT, | 373 // Using values from net/base/net_error_list.h ERR_TIMED_OUT, |
402 // Same as existing FIXME above - this error should be coming from FrameLoad
erClient to be identifiable. | 374 // Same as existing FIXME above - this error should be coming from FrameLoad
erClient to be identifiable. |
403 static const int timeoutError = -7; | 375 static const int timeoutError = -7; |
404 ResourceError error("net", timeoutError, resource()->url(), String()); | 376 ResourceError error("net", timeoutError, resource()->url(), String()); |
(...skipping 16 matching lines...) Expand all Loading... |
421 } | 393 } |
422 | 394 |
423 void DocumentThreadableLoader::handlePreflightFailure(const String& url, const S
tring& errorDescription) | 395 void DocumentThreadableLoader::handlePreflightFailure(const String& url, const S
tring& errorDescription) |
424 { | 396 { |
425 ResourceError error(errorDomainBlinkInternal, 0, url, errorDescription); | 397 ResourceError error(errorDomainBlinkInternal, 0, url, errorDescription); |
426 | 398 |
427 // Prevent handleSuccessfulFinish() from bypassing access check. | 399 // Prevent handleSuccessfulFinish() from bypassing access check. |
428 m_actualRequest = nullptr; | 400 m_actualRequest = nullptr; |
429 | 401 |
430 m_client->didFailAccessControlCheck(error); | 402 m_client->didFailAccessControlCheck(error); |
431 m_requestStartedSeconds = 0.0; | |
432 } | 403 } |
433 | 404 |
434 void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, Resou
rceLoaderOptions resourceLoaderOptions) | 405 void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, Resou
rceLoaderOptions resourceLoaderOptions) |
435 { | 406 { |
436 // Any credential should have been removed from the cross-site requests. | 407 // Any credential should have been removed from the cross-site requests. |
437 const KURL& requestURL = request.url(); | 408 const KURL& requestURL = request.url(); |
438 ASSERT(m_sameOriginRequest || requestURL.user().isEmpty()); | 409 ASSERT(m_sameOriginRequest || requestURL.user().isEmpty()); |
439 ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty()); | 410 ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty()); |
440 | 411 |
441 // Update resourceLoaderOptions with enforced values. | 412 // Update resourceLoaderOptions with enforced values. |
(...skipping 25 matching lines...) Expand all Loading... |
467 FetchRequest fetchRequest(request, m_options.initiator, resourceLoaderOption
s); | 438 FetchRequest fetchRequest(request, m_options.initiator, resourceLoaderOption
s); |
468 ResourcePtr<Resource> resource = m_document.fetcher()->fetchSynchronously(fe
tchRequest); | 439 ResourcePtr<Resource> resource = m_document.fetcher()->fetchSynchronously(fe
tchRequest); |
469 ResourceResponse response = resource ? resource->response() : ResourceRespon
se(); | 440 ResourceResponse response = resource ? resource->response() : ResourceRespon
se(); |
470 unsigned long identifier = resource ? resource->identifier() : std::numeric_
limits<unsigned long>::max(); | 441 unsigned long identifier = resource ? resource->identifier() : std::numeric_
limits<unsigned long>::max(); |
471 ResourceError error = resource ? resource->resourceError() : ResourceError()
; | 442 ResourceError error = resource ? resource->resourceError() : ResourceError()
; |
472 | 443 |
473 InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient(&m
_document, identifier, m_client); | 444 InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient(&m
_document, identifier, m_client); |
474 | 445 |
475 if (!resource) { | 446 if (!resource) { |
476 m_client->didFail(error); | 447 m_client->didFail(error); |
477 m_requestStartedSeconds = 0.0; // Unnecessary for synchronous request, b
ut for API consistency. | |
478 return; | 448 return; |
479 } | 449 } |
480 | 450 |
481 // No exception for file:/// resources, see <rdar://problem/4962298>. | 451 // No exception for file:/// resources, see <rdar://problem/4962298>. |
482 // Also, if we have an HTTP response, then it wasn't a network error in fact
. | 452 // Also, if we have an HTTP response, then it wasn't a network error in fact
. |
483 if (!error.isNull() && !requestURL.isLocalFile() && response.httpStatusCode(
) <= 0) { | 453 if (!error.isNull() && !requestURL.isLocalFile() && response.httpStatusCode(
) <= 0) { |
484 m_client->didFail(error); | 454 m_client->didFail(error); |
485 return; | 455 return; |
486 } | 456 } |
487 | 457 |
488 // FIXME: A synchronous request does not tell us whether a redirect happened
or not, so we guess by comparing the | 458 // FIXME: A synchronous request does not tell us whether a redirect happened
or not, so we guess by comparing the |
489 // 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 | 459 // 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 |
490 // requested. Also comparing the request and response URLs as strings will f
ail if the requestURL still has its credentials. | 460 // requested. Also comparing the request and response URLs as strings will f
ail if the requestURL still has its credentials. |
491 if (requestURL != response.url() && (!isAllowedByPolicy(response.url()) || !
isAllowedRedirect(response.url()))) { | 461 if (requestURL != response.url() && (!isAllowedByPolicy(response.url()) || !
isAllowedRedirect(response.url()))) { |
492 m_client->didFailRedirectCheck(); | 462 m_client->didFailRedirectCheck(); |
493 m_requestStartedSeconds = 0.0; // Unnecessary for synchronous request, b
ut for API consistency. | |
494 return; | 463 return; |
495 } | 464 } |
496 | 465 |
497 handleResponse(identifier, response); | 466 handleResponse(identifier, response); |
498 | 467 |
499 SharedBuffer* data = resource->resourceBuffer(); | 468 SharedBuffer* data = resource->resourceBuffer(); |
500 if (data) | 469 if (data) |
501 handleReceivedData(data->data(), data->size()); | 470 handleReceivedData(data->data(), data->size()); |
502 | 471 |
503 handleSuccessfulFinish(identifier, 0.0); | 472 handleSuccessfulFinish(identifier, 0.0); |
(...skipping 20 matching lines...) Expand all Loading... |
524 return DoNotAllowStoredCredentials; | 493 return DoNotAllowStoredCredentials; |
525 return m_resourceLoaderOptions.allowCredentials; | 494 return m_resourceLoaderOptions.allowCredentials; |
526 } | 495 } |
527 | 496 |
528 SecurityOrigin* DocumentThreadableLoader::securityOrigin() const | 497 SecurityOrigin* DocumentThreadableLoader::securityOrigin() const |
529 { | 498 { |
530 return m_securityOrigin ? m_securityOrigin.get() : m_document.securityOrigin
(); | 499 return m_securityOrigin ? m_securityOrigin.get() : m_document.securityOrigin
(); |
531 } | 500 } |
532 | 501 |
533 } // namespace WebCore | 502 } // namespace WebCore |
OLD | NEW |