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 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 return xmlHttpRequest.release(); | 163 return xmlHttpRequest.release(); |
164 } | 164 } |
165 | 165 |
166 XMLHttpRequest::XMLHttpRequest(ExecutionContext* context, PassRefPtr<SecurityOri
gin> securityOrigin) | 166 XMLHttpRequest::XMLHttpRequest(ExecutionContext* context, PassRefPtr<SecurityOri
gin> securityOrigin) |
167 : ActiveDOMObject(context) | 167 : ActiveDOMObject(context) |
168 , m_async(true) | 168 , m_async(true) |
169 , m_includeCredentials(false) | 169 , m_includeCredentials(false) |
170 , m_timeoutMilliseconds(0) | 170 , m_timeoutMilliseconds(0) |
171 , m_state(UNSENT) | 171 , m_state(UNSENT) |
172 , m_createdDocument(false) | 172 , m_createdDocument(false) |
| 173 , m_downloadedBlobLength(0) |
173 , m_error(false) | 174 , m_error(false) |
174 , m_uploadEventsAllowed(true) | 175 , m_uploadEventsAllowed(true) |
175 , m_uploadComplete(false) | 176 , m_uploadComplete(false) |
176 , m_sameOriginRequest(true) | 177 , m_sameOriginRequest(true) |
177 , m_receivedLength(0) | 178 , m_receivedLength(0) |
178 , m_lastSendLineNumber(0) | 179 , m_lastSendLineNumber(0) |
179 , m_exceptionCode(0) | 180 , m_exceptionCode(0) |
180 , m_progressEventThrottle(this) | 181 , m_progressEventThrottle(this) |
181 , m_responseTypeCode(ResponseTypeDefault) | 182 , m_responseTypeCode(ResponseTypeDefault) |
182 , m_dropProtectionRunner(this, &XMLHttpRequest::dropProtection) | 183 , m_dropProtectionRunner(this, &XMLHttpRequest::dropProtection) |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 } | 267 } |
267 m_createdDocument = true; | 268 m_createdDocument = true; |
268 } | 269 } |
269 | 270 |
270 return m_responseDocument.get(); | 271 return m_responseDocument.get(); |
271 } | 272 } |
272 | 273 |
273 Blob* XMLHttpRequest::responseBlob() | 274 Blob* XMLHttpRequest::responseBlob() |
274 { | 275 { |
275 ASSERT(m_responseTypeCode == ResponseTypeBlob); | 276 ASSERT(m_responseTypeCode == ResponseTypeBlob); |
| 277 ASSERT(!m_binaryResponseBuilder.get()); |
276 | 278 |
277 // We always return null before DONE. | 279 // We always return null before DONE. |
278 if (m_error || m_state != DONE) | 280 if (m_error || m_state != DONE) |
279 return 0; | 281 return 0; |
280 | 282 |
281 if (!m_responseBlob) { | 283 if (!m_responseBlob) { |
282 // FIXME: This causes two (or more) unnecessary copies of the data. | 284 // When "blob" is specified for the responseType attribute, |
283 // Chromium stores blob data in the browser process, so we're pulling th
e data | 285 // we redirect the downloaded data to a file-handle directly |
284 // from the network only to copy it into the renderer to copy it back to
the browser. | 286 // in the browser process. |
285 // Ideally we'd get the blob/file-handle from the ResourceResponse direc
tly | 287 // We get the file-path from the ResourceResponse directly |
286 // instead of copying the bytes. Embedders who store blob data in the | 288 // instead of copying the bytes between the browser and the renderer. |
287 // same process as WebCore would at least to teach BlobData to take | |
288 // a SharedBuffer, even if they don't get the Blob from the network laye
r directly. | |
289 OwnPtr<BlobData> blobData = BlobData::create(); | 289 OwnPtr<BlobData> blobData = BlobData::create(); |
| 290 String filePath = m_response.downloadedFilePath(); |
290 // If we errored out or got no data, we still return a blob, just an emp
ty one. | 291 // If we errored out or got no data, we still return a blob, just an emp
ty one. |
291 size_t size = 0; | 292 if (!filePath.isEmpty() && m_downloadedBlobLength) { |
292 if (m_binaryResponseBuilder) { | 293 blobData->appendFile(filePath); |
293 RefPtr<RawData> rawData = RawData::create(); | |
294 size = m_binaryResponseBuilder->size(); | |
295 rawData->mutableData()->append(m_binaryResponseBuilder->data(), size
); | |
296 blobData->appendData(rawData, 0, BlobDataItem::toEndOfFile); | |
297 blobData->setContentType(responseMIMEType()); // responseMIMEType de
faults to text/xml which may be incorrect. | 294 blobData->setContentType(responseMIMEType()); // responseMIMEType de
faults to text/xml which may be incorrect. |
298 m_binaryResponseBuilder.clear(); | |
299 } | 295 } |
300 m_responseBlob = Blob::create(BlobDataHandle::create(blobData.release(),
size)); | 296 m_responseBlob = Blob::create(BlobDataHandle::create(blobData.release(),
m_downloadedBlobLength)); |
301 } | 297 } |
302 | 298 |
303 return m_responseBlob.get(); | 299 return m_responseBlob.get(); |
304 } | 300 } |
305 | 301 |
306 ArrayBuffer* XMLHttpRequest::responseArrayBuffer() | 302 ArrayBuffer* XMLHttpRequest::responseArrayBuffer() |
307 { | 303 { |
308 ASSERT(m_responseTypeCode == ResponseTypeArrayBuffer); | 304 ASSERT(m_responseTypeCode == ResponseTypeArrayBuffer); |
309 | 305 |
310 if (m_error || m_state != DONE) | 306 if (m_error || m_state != DONE) |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
402 return ""; | 398 return ""; |
403 } | 399 } |
404 | 400 |
405 XMLHttpRequestUpload* XMLHttpRequest::upload() | 401 XMLHttpRequestUpload* XMLHttpRequest::upload() |
406 { | 402 { |
407 if (!m_upload) | 403 if (!m_upload) |
408 m_upload = XMLHttpRequestUpload::create(this); | 404 m_upload = XMLHttpRequestUpload::create(this); |
409 return m_upload.get(); | 405 return m_upload.get(); |
410 } | 406 } |
411 | 407 |
| 408 void XMLHttpRequest::trackProgress(int length) |
| 409 { |
| 410 m_receivedLength += length; |
| 411 |
| 412 if (m_async) |
| 413 dispatchThrottledProgressEventSnapshot(EventTypeNames::progress); |
| 414 |
| 415 if (m_state != LOADING) { |
| 416 changeState(LOADING); |
| 417 } else { |
| 418 // Firefox calls readyStateChanged every time it receives data. Do |
| 419 // the same to align with Firefox. |
| 420 // |
| 421 // FIXME: Make our implementation and the spec consistent. This |
| 422 // behavior was needed when the progress event was not available. |
| 423 dispatchReadyStateChangeEvent(); |
| 424 } |
| 425 } |
| 426 |
412 void XMLHttpRequest::changeState(State newState) | 427 void XMLHttpRequest::changeState(State newState) |
413 { | 428 { |
414 if (m_state != newState) { | 429 if (m_state != newState) { |
415 m_state = newState; | 430 m_state = newState; |
416 dispatchReadyStateChangeEvent(); | 431 dispatchReadyStateChangeEvent(); |
417 } | 432 } |
418 } | 433 } |
419 | 434 |
420 void XMLHttpRequest::dispatchReadyStateChangeEvent() | 435 void XMLHttpRequest::dispatchReadyStateChangeEvent() |
421 { | 436 { |
(...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
782 m_sameOriginRequest = securityOrigin()->canRequest(m_url); | 797 m_sameOriginRequest = securityOrigin()->canRequest(m_url); |
783 | 798 |
784 // We also remember whether upload events should be allowed for this request
in case the upload listeners are | 799 // We also remember whether upload events should be allowed for this request
in case the upload listeners are |
785 // added after the request is started. | 800 // added after the request is started. |
786 m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCros
sOriginAccessRequest(m_method, m_requestHeaders); | 801 m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCros
sOriginAccessRequest(m_method, m_requestHeaders); |
787 | 802 |
788 ResourceRequest request(m_url); | 803 ResourceRequest request(m_url); |
789 request.setHTTPMethod(m_method); | 804 request.setHTTPMethod(m_method); |
790 request.setTargetType(ResourceRequest::TargetIsXHR); | 805 request.setTargetType(ResourceRequest::TargetIsXHR); |
791 | 806 |
| 807 // When "blob" is specified for the responseType attribute, |
| 808 // we redirect the downloaded data to a file-handle directly |
| 809 // and get the file-path as the result. |
| 810 if (responseTypeCode() == ResponseTypeBlob) |
| 811 request.setDownloadToFile(true); |
| 812 |
792 InspectorInstrumentation::willLoadXHR(executionContext(), this, this, m_meth
od, m_url, m_async, m_requestEntityBody ? m_requestEntityBody->deepCopy() : 0, m
_requestHeaders, m_includeCredentials); | 813 InspectorInstrumentation::willLoadXHR(executionContext(), this, this, m_meth
od, m_url, m_async, m_requestEntityBody ? m_requestEntityBody->deepCopy() : 0, m
_requestHeaders, m_includeCredentials); |
793 | 814 |
794 if (m_requestEntityBody) { | 815 if (m_requestEntityBody) { |
795 ASSERT(m_method != "GET"); | 816 ASSERT(m_method != "GET"); |
796 ASSERT(m_method != "HEAD"); | 817 ASSERT(m_method != "HEAD"); |
797 request.setHTTPBody(m_requestEntityBody.release()); | 818 request.setHTTPBody(m_requestEntityBody.release()); |
798 } | 819 } |
799 | 820 |
800 if (m_requestHeaders.size() > 0) | 821 if (m_requestHeaders.size() > 0) |
801 request.addHTTPHeaderFields(m_requestHeaders); | 822 request.addHTTPHeaderFields(m_requestHeaders); |
802 | 823 |
803 ThreadableLoaderOptions options; | 824 ThreadableLoaderOptions options; |
804 options.sendLoadCallbacks = SendCallbacks; | 825 options.sendLoadCallbacks = SendCallbacks; |
805 options.sniffContent = DoNotSniffContent; | 826 options.sniffContent = DoNotSniffContent; |
806 options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight; | 827 options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight; |
807 options.allowCredentials = (m_sameOriginRequest || m_includeCredentials) ? A
llowStoredCredentials : DoNotAllowStoredCredentials; | 828 options.allowCredentials = (m_sameOriginRequest || m_includeCredentials) ? A
llowStoredCredentials : DoNotAllowStoredCredentials; |
808 options.credentialsRequested = m_includeCredentials ? ClientRequestedCredent
ials : ClientDidNotRequestCredentials; | 829 options.credentialsRequested = m_includeCredentials ? ClientRequestedCredent
ials : ClientDidNotRequestCredentials; |
809 options.crossOriginRequestPolicy = UseAccessControl; | 830 options.crossOriginRequestPolicy = UseAccessControl; |
810 options.securityOrigin = securityOrigin(); | 831 options.securityOrigin = securityOrigin(); |
811 options.initiator = FetchInitiatorTypeNames::xmlhttprequest; | 832 options.initiator = FetchInitiatorTypeNames::xmlhttprequest; |
812 options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypa
ssMainWorld(executionContext()) ? DoNotEnforceContentSecurityPolicy : EnforceCon
nectSrcDirective; | 833 options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypa
ssMainWorld(executionContext()) ? DoNotEnforceContentSecurityPolicy : EnforceCon
nectSrcDirective; |
813 // TODO(tsepez): Specify TreatAsActiveContent per http://crbug.com/305303. | 834 // TODO(tsepez): Specify TreatAsActiveContent per http://crbug.com/305303. |
814 options.mixedContentBlockingTreatment = TreatAsPassiveContent; | 835 options.mixedContentBlockingTreatment = TreatAsPassiveContent; |
815 options.timeoutMilliseconds = m_timeoutMilliseconds; | 836 options.timeoutMilliseconds = m_timeoutMilliseconds; |
816 | 837 |
| 838 // Since we redirect the downloaded data to a file-handle directly |
| 839 // when "blob" is specified for the responseType attribute, |
| 840 // buffering is not needed. |
| 841 if (responseTypeCode() == ResponseTypeBlob) |
| 842 options.dataBufferingPolicy = DoNotBufferData; |
| 843 |
817 m_exceptionCode = 0; | 844 m_exceptionCode = 0; |
818 m_error = false; | 845 m_error = false; |
819 | 846 |
820 if (m_async) { | 847 if (m_async) { |
821 if (m_upload) | 848 if (m_upload) |
822 request.setReportUploadProgress(true); | 849 request.setReportUploadProgress(true); |
823 | 850 |
824 // ThreadableLoader::create can return null here, for example if we're n
o longer attached to a page. | 851 // ThreadableLoader::create can return null here, for example if we're n
o longer attached to a page. |
825 // This is true while running onunload handlers. | 852 // This is true while running onunload handlers. |
826 // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload
, <http://bugs.webkit.org/show_bug.cgi?id=10904>. | 853 // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload
, <http://bugs.webkit.org/show_bug.cgi?id=10904>. |
(...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1280 m_response.setHTTPHeaderField("Content-Type", m_mimeTypeOverride); | 1307 m_response.setHTTPHeaderField("Content-Type", m_mimeTypeOverride); |
1281 m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride); | 1308 m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride); |
1282 } | 1309 } |
1283 | 1310 |
1284 if (m_responseEncoding.isEmpty()) | 1311 if (m_responseEncoding.isEmpty()) |
1285 m_responseEncoding = response.textEncodingName(); | 1312 m_responseEncoding = response.textEncodingName(); |
1286 } | 1313 } |
1287 | 1314 |
1288 void XMLHttpRequest::didReceiveData(const char* data, int len) | 1315 void XMLHttpRequest::didReceiveData(const char* data, int len) |
1289 { | 1316 { |
| 1317 ASSERT(m_responseTypeCode != ResponseTypeBlob); |
| 1318 |
1290 if (m_error) | 1319 if (m_error) |
1291 return; | 1320 return; |
1292 | 1321 |
1293 if (m_state < HEADERS_RECEIVED) | 1322 if (m_state < HEADERS_RECEIVED) |
1294 changeState(HEADERS_RECEIVED); | 1323 changeState(HEADERS_RECEIVED); |
1295 | 1324 |
1296 bool useDecoder = m_responseTypeCode == ResponseTypeDefault || m_responseTyp
eCode == ResponseTypeText || m_responseTypeCode == ResponseTypeJSON || m_respons
eTypeCode == ResponseTypeDocument; | 1325 bool useDecoder = m_responseTypeCode == ResponseTypeDefault || m_responseTyp
eCode == ResponseTypeText || m_responseTypeCode == ResponseTypeJSON || m_respons
eTypeCode == ResponseTypeDocument; |
1297 | 1326 |
1298 if (useDecoder && !m_decoder) { | 1327 if (useDecoder && !m_decoder) { |
1299 if (m_responseTypeCode == ResponseTypeJSON) | 1328 if (m_responseTypeCode == ResponseTypeJSON) |
(...skipping 12 matching lines...) Expand all Loading... |
1312 } | 1341 } |
1313 | 1342 |
1314 if (!len) | 1343 if (!len) |
1315 return; | 1344 return; |
1316 | 1345 |
1317 if (len == -1) | 1346 if (len == -1) |
1318 len = strlen(data); | 1347 len = strlen(data); |
1319 | 1348 |
1320 if (useDecoder) { | 1349 if (useDecoder) { |
1321 m_responseText = m_responseText.concatenateWith(m_decoder->decode(data,
len)); | 1350 m_responseText = m_responseText.concatenateWith(m_decoder->decode(data,
len)); |
1322 } else if (m_responseTypeCode == ResponseTypeArrayBuffer || m_responseTypeCo
de == ResponseTypeBlob) { | 1351 } else if (m_responseTypeCode == ResponseTypeArrayBuffer) { |
1323 // Buffer binary data. | 1352 // Buffer binary data. |
1324 if (!m_binaryResponseBuilder) | 1353 if (!m_binaryResponseBuilder) |
1325 m_binaryResponseBuilder = SharedBuffer::create(); | 1354 m_binaryResponseBuilder = SharedBuffer::create(); |
1326 m_binaryResponseBuilder->append(data, len); | 1355 m_binaryResponseBuilder->append(data, len); |
1327 } else if (m_responseTypeCode == ResponseTypeStream) { | 1356 } else if (m_responseTypeCode == ResponseTypeStream) { |
1328 if (!m_responseStream) | 1357 if (!m_responseStream) |
1329 m_responseStream = Stream::create(executionContext(), responseMIMETy
pe()); | 1358 m_responseStream = Stream::create(executionContext(), responseMIMETy
pe()); |
1330 m_responseStream->addData(data, len); | 1359 m_responseStream->addData(data, len); |
1331 } | 1360 } |
1332 | 1361 |
1333 if (m_error) | 1362 if (m_error) |
1334 return; | 1363 return; |
1335 | 1364 |
1336 m_receivedLength += len; | 1365 trackProgress(len); |
| 1366 } |
1337 | 1367 |
1338 if (m_async) | 1368 void XMLHttpRequest::didDownloadData(int dataLength) |
1339 dispatchThrottledProgressEventSnapshot(EventTypeNames::progress); | 1369 { |
| 1370 ASSERT(m_responseTypeCode == ResponseTypeBlob); |
1340 | 1371 |
1341 if (m_state != LOADING) { | 1372 if (m_error) |
1342 changeState(LOADING); | 1373 return; |
1343 } else { | 1374 |
1344 // Firefox calls readyStateChanged every time it receives data. Do | 1375 if (m_state < HEADERS_RECEIVED) |
1345 // the same to align with Firefox. | 1376 changeState(HEADERS_RECEIVED); |
1346 // | 1377 |
1347 // FIXME: Make our implementation and the spec consistent. This | 1378 if (!dataLength) |
1348 // behavior was needed when the progress event was not available. | 1379 return; |
1349 dispatchReadyStateChangeEvent(); | 1380 |
1350 } | 1381 if (m_error) |
| 1382 return; |
| 1383 |
| 1384 m_downloadedBlobLength += dataLength; |
| 1385 trackProgress(dataLength); |
1351 } | 1386 } |
1352 | 1387 |
1353 void XMLHttpRequest::handleDidTimeout() | 1388 void XMLHttpRequest::handleDidTimeout() |
1354 { | 1389 { |
1355 WTF_LOG(Network, "XMLHttpRequest %p handleDidTimeout()", this); | 1390 WTF_LOG(Network, "XMLHttpRequest %p handleDidTimeout()", this); |
1356 | 1391 |
1357 // internalAbort() calls dropProtection(), which may release the last refere
nce. | 1392 // internalAbort() calls dropProtection(), which may release the last refere
nce. |
1358 RefPtr<XMLHttpRequest> protect(this); | 1393 RefPtr<XMLHttpRequest> protect(this); |
1359 | 1394 |
1360 // Response is cleared next, save needed progress event data. | 1395 // Response is cleared next, save needed progress event data. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1393 { | 1428 { |
1394 return EventTargetNames::XMLHttpRequest; | 1429 return EventTargetNames::XMLHttpRequest; |
1395 } | 1430 } |
1396 | 1431 |
1397 ExecutionContext* XMLHttpRequest::executionContext() const | 1432 ExecutionContext* XMLHttpRequest::executionContext() const |
1398 { | 1433 { |
1399 return ActiveDOMObject::executionContext(); | 1434 return ActiveDOMObject::executionContext(); |
1400 } | 1435 } |
1401 | 1436 |
1402 } // namespace WebCore | 1437 } // namespace WebCore |
OLD | NEW |