Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved. |
| 3 * Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org> | 3 * Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org> |
| 4 * Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org> | 4 * Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org> |
| 5 * Copyright (C) 2008, 2011 Google Inc. All rights reserved. | 5 * Copyright (C) 2008, 2011 Google Inc. All rights reserved. |
| 6 * Copyright (C) 2012 Intel Corporation | 6 * Copyright (C) 2012 Intel Corporation |
| 7 * | 7 * |
| 8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
| 9 * modify it under the terms of the GNU Lesser General Public | 9 * modify it under the terms of the GNU Lesser General Public |
| 10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 166 return xmlHttpRequest.release(); | 166 return xmlHttpRequest.release(); |
| 167 } | 167 } |
| 168 | 168 |
| 169 XMLHttpRequest::XMLHttpRequest(ExecutionContext* context, PassRefPtr<SecurityOri gin> securityOrigin) | 169 XMLHttpRequest::XMLHttpRequest(ExecutionContext* context, PassRefPtr<SecurityOri gin> securityOrigin) |
| 170 : ActiveDOMObject(context) | 170 : ActiveDOMObject(context) |
| 171 , m_async(true) | 171 , m_async(true) |
| 172 , m_includeCredentials(false) | 172 , m_includeCredentials(false) |
| 173 , m_timeoutMilliseconds(0) | 173 , m_timeoutMilliseconds(0) |
| 174 , m_state(UNSENT) | 174 , m_state(UNSENT) |
| 175 , m_createdDocument(false) | 175 , m_createdDocument(false) |
| 176 , m_downloadedBlobLength(0) | |
| 176 , m_error(false) | 177 , m_error(false) |
| 177 , m_uploadEventsAllowed(true) | 178 , m_uploadEventsAllowed(true) |
| 178 , m_uploadComplete(false) | 179 , m_uploadComplete(false) |
| 179 , m_sameOriginRequest(true) | 180 , m_sameOriginRequest(true) |
| 180 , m_receivedLength(0) | 181 , m_receivedLength(0) |
| 181 , m_lastSendLineNumber(0) | 182 , m_lastSendLineNumber(0) |
| 182 , m_exceptionCode(0) | 183 , m_exceptionCode(0) |
| 183 , m_progressEventThrottle(this) | 184 , m_progressEventThrottle(this) |
| 184 , m_responseTypeCode(ResponseTypeDefault) | 185 , m_responseTypeCode(ResponseTypeDefault) |
| 185 , m_dropProtectionRunner(this, &XMLHttpRequest::dropProtection) | 186 , m_dropProtectionRunner(this, &XMLHttpRequest::dropProtection) |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 269 } | 270 } |
| 270 m_createdDocument = true; | 271 m_createdDocument = true; |
| 271 } | 272 } |
| 272 | 273 |
| 273 return m_responseDocument.get(); | 274 return m_responseDocument.get(); |
| 274 } | 275 } |
| 275 | 276 |
| 276 Blob* XMLHttpRequest::responseBlob() | 277 Blob* XMLHttpRequest::responseBlob() |
| 277 { | 278 { |
| 278 ASSERT(m_responseTypeCode == ResponseTypeBlob); | 279 ASSERT(m_responseTypeCode == ResponseTypeBlob); |
| 280 ASSERT(!m_binaryResponseBuilder.get()); | |
| 279 | 281 |
| 280 // We always return null before DONE. | 282 // We always return null before DONE. |
| 281 if (m_error || m_state != DONE) | 283 if (m_error || m_state != DONE) |
| 282 return 0; | 284 return 0; |
| 283 | 285 |
| 284 if (!m_responseBlob) { | 286 if (!m_responseBlob) { |
| 285 // FIXME: This causes two (or more) unnecessary copies of the data. | 287 // When "blob" is specified for the responseType attribute, |
| 286 // Chromium stores blob data in the browser process, so we're pulling th e data | 288 // we redirect the downloaded data to a file-handle directly |
| 287 // from the network only to copy it into the renderer to copy it back to the browser. | 289 // in the browser process. |
| 288 // Ideally we'd get the blob/file-handle from the ResourceResponse direc tly | 290 // We get the file-path from the ResourceResponse directly |
| 289 // instead of copying the bytes. Embedders who store blob data in the | 291 // instead of copying the bytes between the browser and the renderer. |
| 290 // same process as WebCore would at least to teach BlobData to take | |
| 291 // a SharedBuffer, even if they don't get the Blob from the network laye r directly. | |
| 292 OwnPtr<BlobData> blobData = BlobData::create(); | 292 OwnPtr<BlobData> blobData = BlobData::create(); |
| 293 const String& filePath = m_response.downloadedFilePath(); | |
|
abarth-chromium
2013/11/05 07:01:51
const String& -> String
String is a value type wi
yusukesuzuki
2013/11/05 11:04:00
That's reasonable. Done.
| |
| 293 // If we errored out or got no data, we still return a blob, just an emp ty one. | 294 // If we errored out or got no data, we still return a blob, just an emp ty one. |
| 294 size_t size = 0; | 295 if (!filePath.isEmpty() && m_downloadedBlobLength) { |
|
yusukesuzuki
2013/10/24 15:22:41
In the previous patch, I used m_receivedLength as
| |
| 295 if (m_binaryResponseBuilder) { | 296 blobData->appendFile(filePath); |
| 296 RefPtr<RawData> rawData = RawData::create(); | |
| 297 size = m_binaryResponseBuilder->size(); | |
| 298 rawData->mutableData()->append(m_binaryResponseBuilder->data(), size ); | |
| 299 blobData->appendData(rawData, 0, BlobDataItem::toEndOfFile); | |
| 300 blobData->setContentType(responseMIMEType()); // responseMIMEType de faults to text/xml which may be incorrect. | 297 blobData->setContentType(responseMIMEType()); // responseMIMEType de faults to text/xml which may be incorrect. |
| 301 m_binaryResponseBuilder.clear(); | |
| 302 } | 298 } |
| 303 m_responseBlob = Blob::create(BlobDataHandle::create(blobData.release(), size)); | 299 m_responseBlob = Blob::create(BlobDataHandle::create(blobData.release(), m_downloadedBlobLength)); |
| 304 } | 300 } |
| 305 | 301 |
| 306 return m_responseBlob.get(); | 302 return m_responseBlob.get(); |
| 307 } | 303 } |
| 308 | 304 |
| 309 ArrayBuffer* XMLHttpRequest::responseArrayBuffer() | 305 ArrayBuffer* XMLHttpRequest::responseArrayBuffer() |
| 310 { | 306 { |
| 311 ASSERT(m_responseTypeCode == ResponseTypeArrayBuffer); | 307 ASSERT(m_responseTypeCode == ResponseTypeArrayBuffer); |
| 312 | 308 |
| 313 if (m_error || m_state != DONE) | 309 if (m_error || m_state != DONE) |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 405 return ""; | 401 return ""; |
| 406 } | 402 } |
| 407 | 403 |
| 408 XMLHttpRequestUpload* XMLHttpRequest::upload() | 404 XMLHttpRequestUpload* XMLHttpRequest::upload() |
| 409 { | 405 { |
| 410 if (!m_upload) | 406 if (!m_upload) |
| 411 m_upload = XMLHttpRequestUpload::create(this); | 407 m_upload = XMLHttpRequestUpload::create(this); |
| 412 return m_upload.get(); | 408 return m_upload.get(); |
| 413 } | 409 } |
| 414 | 410 |
| 411 void XMLHttpRequest::trackProgress(int length) | |
| 412 { | |
| 413 m_receivedLength += length; | |
| 414 | |
| 415 if (m_async) { | |
| 416 long long expectedLength = m_response.expectedContentLength(); | |
| 417 bool lengthComputable = expectedLength > 0 && m_receivedLength <= expect edLength; | |
| 418 unsigned long long total = lengthComputable ? expectedLength : 0; | |
| 419 | |
| 420 m_progressEventThrottle.dispatchProgressEvent(lengthComputable, m_receiv edLength, total); | |
| 421 } | |
| 422 | |
| 423 if (m_state != LOADING) { | |
| 424 changeState(LOADING); | |
| 425 } else { | |
| 426 // Firefox calls readyStateChanged every time it receives data. Do | |
| 427 // the same to align with Firefox. | |
| 428 // | |
| 429 // FIXME: Make our implementation and the spec consistent. This | |
| 430 // behavior was needed when the progress event was not available. | |
| 431 dispatchReadyStateChangeEvent(); | |
| 432 } | |
| 433 } | |
| 434 | |
| 415 void XMLHttpRequest::changeState(State newState) | 435 void XMLHttpRequest::changeState(State newState) |
| 416 { | 436 { |
| 417 if (m_state != newState) { | 437 if (m_state != newState) { |
| 418 m_state = newState; | 438 m_state = newState; |
| 419 dispatchReadyStateChangeEvent(); | 439 dispatchReadyStateChangeEvent(); |
| 420 } | 440 } |
| 421 } | 441 } |
| 422 | 442 |
| 423 void XMLHttpRequest::dispatchReadyStateChangeEvent() | 443 void XMLHttpRequest::dispatchReadyStateChangeEvent() |
| 424 { | 444 { |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 778 m_sameOriginRequest = securityOrigin()->canRequest(m_url); | 798 m_sameOriginRequest = securityOrigin()->canRequest(m_url); |
| 779 | 799 |
| 780 // We also remember whether upload events should be allowed for this request in case the upload listeners are | 800 // We also remember whether upload events should be allowed for this request in case the upload listeners are |
| 781 // added after the request is started. | 801 // added after the request is started. |
| 782 m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCros sOriginAccessRequest(m_method, m_requestHeaders); | 802 m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCros sOriginAccessRequest(m_method, m_requestHeaders); |
| 783 | 803 |
| 784 ResourceRequest request(m_url); | 804 ResourceRequest request(m_url); |
| 785 request.setHTTPMethod(m_method); | 805 request.setHTTPMethod(m_method); |
| 786 request.setTargetType(ResourceRequest::TargetIsXHR); | 806 request.setTargetType(ResourceRequest::TargetIsXHR); |
| 787 | 807 |
| 808 // When "blob" is specified for the responseType attribute, | |
| 809 // we redirect the downloaded data to a file-handle directly | |
| 810 // and get the file-path as the result. | |
| 811 if (responseTypeCode() == ResponseTypeBlob) | |
| 812 request.setDownloadToFile(true); | |
| 813 | |
| 788 InspectorInstrumentation::willLoadXHR(executionContext(), this, m_method, m_ url, m_async, m_requestEntityBody ? m_requestEntityBody->deepCopy() : 0, m_reque stHeaders, m_includeCredentials); | 814 InspectorInstrumentation::willLoadXHR(executionContext(), this, m_method, m_ url, m_async, m_requestEntityBody ? m_requestEntityBody->deepCopy() : 0, m_reque stHeaders, m_includeCredentials); |
| 789 | 815 |
| 790 if (m_requestEntityBody) { | 816 if (m_requestEntityBody) { |
| 791 ASSERT(m_method != "GET"); | 817 ASSERT(m_method != "GET"); |
| 792 ASSERT(m_method != "HEAD"); | 818 ASSERT(m_method != "HEAD"); |
| 793 request.setHTTPBody(m_requestEntityBody.release()); | 819 request.setHTTPBody(m_requestEntityBody.release()); |
| 794 } | 820 } |
| 795 | 821 |
| 796 if (m_requestHeaders.size() > 0) | 822 if (m_requestHeaders.size() > 0) |
| 797 request.addHTTPHeaderFields(m_requestHeaders); | 823 request.addHTTPHeaderFields(m_requestHeaders); |
| 798 | 824 |
| 799 ThreadableLoaderOptions options; | 825 ThreadableLoaderOptions options; |
| 800 options.sendLoadCallbacks = SendCallbacks; | 826 options.sendLoadCallbacks = SendCallbacks; |
| 801 options.sniffContent = DoNotSniffContent; | 827 options.sniffContent = DoNotSniffContent; |
| 802 options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight; | 828 options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight; |
| 803 options.allowCredentials = (m_sameOriginRequest || m_includeCredentials) ? A llowStoredCredentials : DoNotAllowStoredCredentials; | 829 options.allowCredentials = (m_sameOriginRequest || m_includeCredentials) ? A llowStoredCredentials : DoNotAllowStoredCredentials; |
| 804 options.credentialsRequested = m_includeCredentials ? ClientRequestedCredent ials : ClientDidNotRequestCredentials; | 830 options.credentialsRequested = m_includeCredentials ? ClientRequestedCredent ials : ClientDidNotRequestCredentials; |
| 805 options.crossOriginRequestPolicy = UseAccessControl; | 831 options.crossOriginRequestPolicy = UseAccessControl; |
| 806 options.securityOrigin = securityOrigin(); | 832 options.securityOrigin = securityOrigin(); |
| 807 options.initiator = FetchInitiatorTypeNames::xmlhttprequest; | 833 options.initiator = FetchInitiatorTypeNames::xmlhttprequest; |
| 808 options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypa ssMainWorld(executionContext()) ? DoNotEnforceContentSecurityPolicy : EnforceCon nectSrcDirective; | 834 options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypa ssMainWorld(executionContext()) ? DoNotEnforceContentSecurityPolicy : EnforceCon nectSrcDirective; |
| 809 // TODO(tsepez): Specify TreatAsActiveContent per http://crbug.com/305303. | 835 // TODO(tsepez): Specify TreatAsActiveContent per http://crbug.com/305303. |
| 810 options.mixedContentBlockingTreatment = TreatAsPassiveContent; | 836 options.mixedContentBlockingTreatment = TreatAsPassiveContent; |
| 811 options.timeoutMilliseconds = m_timeoutMilliseconds; | 837 options.timeoutMilliseconds = m_timeoutMilliseconds; |
| 812 | 838 |
| 839 // Since we redirect the downloaded data to a file-handle directly | |
| 840 // when "blob" is specified for the responseType attribute, | |
| 841 // buffering is not needed. | |
| 842 if (responseTypeCode() == ResponseTypeBlob) | |
| 843 options.dataBufferingPolicy = DoNotBufferData; | |
| 844 | |
| 813 m_exceptionCode = 0; | 845 m_exceptionCode = 0; |
| 814 m_error = false; | 846 m_error = false; |
| 815 | 847 |
| 816 if (m_async) { | 848 if (m_async) { |
| 817 if (m_upload) | 849 if (m_upload) |
| 818 request.setReportUploadProgress(true); | 850 request.setReportUploadProgress(true); |
| 819 | 851 |
| 820 // ThreadableLoader::create can return null here, for example if we're n o longer attached to a page. | 852 // ThreadableLoader::create can return null here, for example if we're n o longer attached to a page. |
| 821 // This is true while running onunload handlers. | 853 // This is true while running onunload handlers. |
| 822 // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload , <http://bugs.webkit.org/show_bug.cgi?id=10904>. | 854 // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload , <http://bugs.webkit.org/show_bug.cgi?id=10904>. |
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1249 m_response.setHTTPHeaderField("Content-Type", m_mimeTypeOverride); | 1281 m_response.setHTTPHeaderField("Content-Type", m_mimeTypeOverride); |
| 1250 m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride); | 1282 m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride); |
| 1251 } | 1283 } |
| 1252 | 1284 |
| 1253 if (m_responseEncoding.isEmpty()) | 1285 if (m_responseEncoding.isEmpty()) |
| 1254 m_responseEncoding = response.textEncodingName(); | 1286 m_responseEncoding = response.textEncodingName(); |
| 1255 } | 1287 } |
| 1256 | 1288 |
| 1257 void XMLHttpRequest::didReceiveData(const char* data, int len) | 1289 void XMLHttpRequest::didReceiveData(const char* data, int len) |
| 1258 { | 1290 { |
| 1291 ASSERT(m_responseTypeCode != ResponseTypeBlob); | |
| 1292 | |
| 1259 if (m_error) | 1293 if (m_error) |
| 1260 return; | 1294 return; |
| 1261 | 1295 |
| 1262 if (m_state < HEADERS_RECEIVED) | 1296 if (m_state < HEADERS_RECEIVED) |
| 1263 changeState(HEADERS_RECEIVED); | 1297 changeState(HEADERS_RECEIVED); |
| 1264 | 1298 |
| 1265 bool useDecoder = m_responseTypeCode == ResponseTypeDefault || m_responseTyp eCode == ResponseTypeText || m_responseTypeCode == ResponseTypeJSON || m_respons eTypeCode == ResponseTypeDocument; | 1299 bool useDecoder = m_responseTypeCode == ResponseTypeDefault || m_responseTyp eCode == ResponseTypeText || m_responseTypeCode == ResponseTypeJSON || m_respons eTypeCode == ResponseTypeDocument; |
| 1266 | 1300 |
| 1267 if (useDecoder && !m_decoder) { | 1301 if (useDecoder && !m_decoder) { |
| 1268 if (m_responseTypeCode == ResponseTypeJSON) | 1302 if (m_responseTypeCode == ResponseTypeJSON) |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1281 } | 1315 } |
| 1282 | 1316 |
| 1283 if (!len) | 1317 if (!len) |
| 1284 return; | 1318 return; |
| 1285 | 1319 |
| 1286 if (len == -1) | 1320 if (len == -1) |
| 1287 len = strlen(data); | 1321 len = strlen(data); |
| 1288 | 1322 |
| 1289 if (useDecoder) { | 1323 if (useDecoder) { |
| 1290 m_responseText = m_responseText.concatenateWith(m_decoder->decode(data, len)); | 1324 m_responseText = m_responseText.concatenateWith(m_decoder->decode(data, len)); |
| 1291 } else if (m_responseTypeCode == ResponseTypeArrayBuffer || m_responseTypeCo de == ResponseTypeBlob) { | 1325 } else if (m_responseTypeCode == ResponseTypeArrayBuffer) { |
| 1292 // Buffer binary data. | 1326 // Buffer binary data. |
| 1293 if (!m_binaryResponseBuilder) | 1327 if (!m_binaryResponseBuilder) |
| 1294 m_binaryResponseBuilder = SharedBuffer::create(); | 1328 m_binaryResponseBuilder = SharedBuffer::create(); |
| 1295 m_binaryResponseBuilder->append(data, len); | 1329 m_binaryResponseBuilder->append(data, len); |
| 1296 } else if (m_responseTypeCode == ResponseTypeStream) { | 1330 } else if (m_responseTypeCode == ResponseTypeStream) { |
| 1297 if (!m_responseStream) | 1331 if (!m_responseStream) |
| 1298 m_responseStream = Stream::create(executionContext(), responseMIMETy pe()); | 1332 m_responseStream = Stream::create(executionContext(), responseMIMETy pe()); |
| 1299 m_responseStream->addData(data, len); | 1333 m_responseStream->addData(data, len); |
| 1300 } | 1334 } |
| 1301 | 1335 |
| 1302 if (m_error) | 1336 if (m_error) |
| 1303 return; | 1337 return; |
| 1304 | 1338 |
| 1305 m_receivedLength += len; | 1339 trackProgress(len); |
| 1340 } | |
| 1306 | 1341 |
| 1307 if (m_async) { | 1342 void XMLHttpRequest::didDownloadData(int dataLength) |
| 1308 long long expectedLength = m_response.expectedContentLength(); | 1343 { |
| 1309 bool lengthComputable = expectedLength > 0 && m_receivedLength <= expect edLength; | 1344 ASSERT(m_responseTypeCode == ResponseTypeBlob); |
| 1310 unsigned long long total = lengthComputable ? expectedLength : 0; | |
| 1311 | 1345 |
| 1312 m_progressEventThrottle.dispatchProgressEvent(lengthComputable, m_receiv edLength, total); | 1346 if (m_error) |
| 1313 } | 1347 return; |
| 1314 | 1348 |
| 1315 if (m_state != LOADING) { | 1349 if (m_state < HEADERS_RECEIVED) |
| 1316 changeState(LOADING); | 1350 changeState(HEADERS_RECEIVED); |
| 1317 } else { | 1351 |
| 1318 // Firefox calls readyStateChanged every time it receives data. Do | 1352 if (!dataLength) |
| 1319 // the same to align with Firefox. | 1353 return; |
| 1320 // | 1354 |
| 1321 // FIXME: Make our implementation and the spec consistent. This | 1355 if (m_error) |
| 1322 // behavior was needed when the progress event was not available. | 1356 return; |
|
abarth-chromium
2013/11/05 07:01:51
Can changeState set m_error? We just checked it a
yusukesuzuki
2013/11/05 11:04:00
Yeah, changeState can set m_error. changeState cau
| |
| 1323 dispatchReadyStateChangeEvent(); | 1357 |
| 1324 } | 1358 m_downloadedBlobLength += dataLength; |
| 1359 trackProgress(dataLength); | |
| 1325 } | 1360 } |
| 1326 | 1361 |
| 1327 void XMLHttpRequest::handleDidTimeout() | 1362 void XMLHttpRequest::handleDidTimeout() |
| 1328 { | 1363 { |
| 1329 LOG(Network, "XMLHttpRequest %p handleDidTimeout()", this); | 1364 LOG(Network, "XMLHttpRequest %p handleDidTimeout()", this); |
| 1330 | 1365 |
| 1331 // internalAbort() calls dropProtection(), which may release the last refere nce. | 1366 // internalAbort() calls dropProtection(), which may release the last refere nce. |
| 1332 RefPtr<XMLHttpRequest> protect(this); | 1367 RefPtr<XMLHttpRequest> protect(this); |
| 1333 | 1368 |
| 1334 if (!internalAbort()) | 1369 if (!internalAbort()) |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1372 { | 1407 { |
| 1373 return EventTargetNames::XMLHttpRequest; | 1408 return EventTargetNames::XMLHttpRequest; |
| 1374 } | 1409 } |
| 1375 | 1410 |
| 1376 ExecutionContext* XMLHttpRequest::executionContext() const | 1411 ExecutionContext* XMLHttpRequest::executionContext() const |
| 1377 { | 1412 { |
| 1378 return ActiveDOMObject::executionContext(); | 1413 return ActiveDOMObject::executionContext(); |
| 1379 } | 1414 } |
| 1380 | 1415 |
| 1381 } // namespace WebCore | 1416 } // namespace WebCore |
| OLD | NEW |