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

Side by Side Diff: Source/core/xml/XMLHttpRequest.cpp

Issue 23444058: Use downloadToFile option when XHR downloads a Blob (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Rebase test style and XHR Created 7 years 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
« no previous file with comments | « Source/core/xml/XMLHttpRequest.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « Source/core/xml/XMLHttpRequest.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698