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 |