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

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: Created 7 years, 2 months 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 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 } 268 }
269 m_createdDocument = true; 269 m_createdDocument = true;
270 } 270 }
271 271
272 return m_responseDocument.get(); 272 return m_responseDocument.get();
273 } 273 }
274 274
275 Blob* XMLHttpRequest::responseBlob() 275 Blob* XMLHttpRequest::responseBlob()
276 { 276 {
277 ASSERT(m_responseTypeCode == ResponseTypeBlob); 277 ASSERT(m_responseTypeCode == ResponseTypeBlob);
278 ASSERT(!m_binaryResponseBuilder.get());
278 279
279 // We always return null before DONE. 280 // We always return null before DONE.
280 if (m_error || m_state != DONE) 281 if (m_error || m_state != DONE)
281 return 0; 282 return 0;
282 283
283 if (!m_responseBlob) { 284 if (!m_responseBlob) {
284 // FIXME: This causes two (or more) unnecessary copies of the data. 285 // When "blob" is specified for the responseType attribute,
285 // Chromium stores blob data in the browser process, so we're pulling th e data 286 // we redirect the downloaded data to a file-handle directly
286 // from the network only to copy it into the renderer to copy it back to the browser. 287 // in the browser process.
287 // Ideally we'd get the blob/file-handle from the ResourceResponse direc tly 288 // We get the file-path from the ResourceResponse directly
288 // instead of copying the bytes. Embedders who store blob data in the 289 // instead of copying the bytes between the browser and the renderer.
289 // same process as WebCore would at least to teach BlobData to take
290 // a SharedBuffer, even if they don't get the Blob from the network laye r directly.
291 OwnPtr<BlobData> blobData = BlobData::create(); 290 OwnPtr<BlobData> blobData = BlobData::create();
291 const String& filePath = m_response.downloadedFilePath();
292 // If we errored out or got no data, we still return a blob, just an emp ty one. 292 // If we errored out or got no data, we still return a blob, just an emp ty one.
293 size_t size = 0; 293 if (!filePath.isEmpty() && m_receivedLength) {
294 if (m_binaryResponseBuilder) { 294 blobData->appendFile(filePath);
295 RefPtr<RawData> rawData = RawData::create();
296 size = m_binaryResponseBuilder->size();
297 rawData->mutableData()->append(m_binaryResponseBuilder->data(), size );
298 blobData->appendData(rawData, 0, BlobDataItem::toEndOfFile);
299 blobData->setContentType(responseMIMEType()); // responseMIMEType de faults to text/xml which may be incorrect. 295 blobData->setContentType(responseMIMEType()); // responseMIMEType de faults to text/xml which may be incorrect.
300 m_binaryResponseBuilder.clear();
301 } 296 }
302 m_responseBlob = Blob::create(blobData.release(), size); 297 m_responseBlob = Blob::create(blobData.release(), m_receivedLength);
303 } 298 }
304 299
305 return m_responseBlob.get(); 300 return m_responseBlob.get();
306 } 301 }
307 302
308 ArrayBuffer* XMLHttpRequest::responseArrayBuffer() 303 ArrayBuffer* XMLHttpRequest::responseArrayBuffer()
309 { 304 {
310 ASSERT(m_responseTypeCode == ResponseTypeArrayBuffer); 305 ASSERT(m_responseTypeCode == ResponseTypeArrayBuffer);
311 306
312 if (m_error || m_state != DONE) 307 if (m_error || m_state != DONE)
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
404 return ""; 399 return "";
405 } 400 }
406 401
407 XMLHttpRequestUpload* XMLHttpRequest::upload() 402 XMLHttpRequestUpload* XMLHttpRequest::upload()
408 { 403 {
409 if (!m_upload) 404 if (!m_upload)
410 m_upload = XMLHttpRequestUpload::create(this); 405 m_upload = XMLHttpRequestUpload::create(this);
411 return m_upload.get(); 406 return m_upload.get();
412 } 407 }
413 408
409 void XMLHttpRequest::trackProgress(int len)
abarth-chromium 2013/10/13 05:20:30 len -> length
yusukesuzuki 2013/10/24 15:22:41 Done.
410 {
411 long long expectedLength = m_response.expectedContentLength();
412 m_receivedLength += len;
413
414 if (m_async) {
415 bool lengthComputable = expectedLength > 0 && m_receivedLength <= expect edLength;
416 unsigned long long total = lengthComputable ? expectedLength : 0;
417 m_progressEventThrottle.dispatchProgressEvent(lengthComputable, m_receiv edLength, total);
418 }
419
420 if (m_state != LOADING) {
421 changeState(LOADING);
422 } else {
423 // Firefox calls readyStateChanged every time it receives data, 4449442
abarth-chromium 2013/10/13 05:20:30 4449442 <-- What is this number? Can we make it a
tyoshino (SeeGerritForStatus) 2013/10/16 07:57:56 This is Apple Radar ID. I've replaced this with ex
yusukesuzuki 2013/10/24 15:22:41 Right. I've rebased and this issue is fixed by tha
424 callReadyStateChangeListener();
425 }
426 }
427
414 void XMLHttpRequest::changeState(State newState) 428 void XMLHttpRequest::changeState(State newState)
415 { 429 {
416 if (m_state != newState) { 430 if (m_state != newState) {
417 m_state = newState; 431 m_state = newState;
418 callReadyStateChangeListener(); 432 callReadyStateChangeListener();
419 } 433 }
420 } 434 }
421 435
422 void XMLHttpRequest::callReadyStateChangeListener() 436 void XMLHttpRequest::callReadyStateChangeListener()
423 { 437 {
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after
746 m_sameOriginRequest = securityOrigin()->canRequest(m_url); 760 m_sameOriginRequest = securityOrigin()->canRequest(m_url);
747 761
748 // We also remember whether upload events should be allowed for this request in case the upload listeners are 762 // We also remember whether upload events should be allowed for this request in case the upload listeners are
749 // added after the request is started. 763 // added after the request is started.
750 m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCros sOriginAccessRequest(m_method, m_requestHeaders); 764 m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCros sOriginAccessRequest(m_method, m_requestHeaders);
751 765
752 ResourceRequest request(m_url); 766 ResourceRequest request(m_url);
753 request.setHTTPMethod(m_method); 767 request.setHTTPMethod(m_method);
754 request.setTargetType(ResourceRequest::TargetIsXHR); 768 request.setTargetType(ResourceRequest::TargetIsXHR);
755 769
770 // When "blob" is specified for the responseType attribute,
771 // we redirect the downloaded data to a file-handle directly
772 // and get the file-path as the result.
773 if (responseTypeCode() == ResponseTypeBlob)
774 request.setDownloadToFile(true);
775
756 InspectorInstrumentation::willLoadXHR(scriptExecutionContext(), this, m_meth od, m_url, m_async, m_requestEntityBody ? m_requestEntityBody->deepCopy() : 0, m _requestHeaders, m_includeCredentials); 776 InspectorInstrumentation::willLoadXHR(scriptExecutionContext(), this, m_meth od, m_url, m_async, m_requestEntityBody ? m_requestEntityBody->deepCopy() : 0, m _requestHeaders, m_includeCredentials);
757 777
758 if (m_requestEntityBody) { 778 if (m_requestEntityBody) {
759 ASSERT(m_method != "GET"); 779 ASSERT(m_method != "GET");
760 ASSERT(m_method != "HEAD"); 780 ASSERT(m_method != "HEAD");
761 request.setHTTPBody(m_requestEntityBody.release()); 781 request.setHTTPBody(m_requestEntityBody.release());
762 } 782 }
763 783
764 if (m_requestHeaders.size() > 0) 784 if (m_requestHeaders.size() > 0)
765 request.addHTTPHeaderFields(m_requestHeaders); 785 request.addHTTPHeaderFields(m_requestHeaders);
766 786
767 ThreadableLoaderOptions options; 787 ThreadableLoaderOptions options;
768 options.sendLoadCallbacks = SendCallbacks; 788 options.sendLoadCallbacks = SendCallbacks;
769 options.sniffContent = DoNotSniffContent; 789 options.sniffContent = DoNotSniffContent;
770 options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight; 790 options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight;
771 options.allowCredentials = (m_sameOriginRequest || m_includeCredentials) ? A llowStoredCredentials : DoNotAllowStoredCredentials; 791 options.allowCredentials = (m_sameOriginRequest || m_includeCredentials) ? A llowStoredCredentials : DoNotAllowStoredCredentials;
772 options.credentialsRequested = m_includeCredentials ? ClientRequestedCredent ials : ClientDidNotRequestCredentials; 792 options.credentialsRequested = m_includeCredentials ? ClientRequestedCredent ials : ClientDidNotRequestCredentials;
773 options.crossOriginRequestPolicy = UseAccessControl; 793 options.crossOriginRequestPolicy = UseAccessControl;
774 options.securityOrigin = securityOrigin(); 794 options.securityOrigin = securityOrigin();
775 options.initiator = FetchInitiatorTypeNames::xmlhttprequest; 795 options.initiator = FetchInitiatorTypeNames::xmlhttprequest;
776 options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypa ssMainWorld(scriptExecutionContext()) ? DoNotEnforceContentSecurityPolicy : Enfo rceConnectSrcDirective; 796 options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypa ssMainWorld(scriptExecutionContext()) ? DoNotEnforceContentSecurityPolicy : Enfo rceConnectSrcDirective;
777 options.mixedContentBlockingTreatment = TreatAsActiveContent; 797 options.mixedContentBlockingTreatment = TreatAsActiveContent;
778 options.timeoutMilliseconds = m_timeoutMilliseconds; 798 options.timeoutMilliseconds = m_timeoutMilliseconds;
779 799
800 // Since we redirect the downloaded data to a file-handle directly
801 // when "blob" is specified for the responseType attribute,
802 // buffering is not needed.
803 if (responseTypeCode() == ResponseTypeBlob)
804 options.dataBufferingPolicy = DoNotBufferData;
805
780 m_exceptionCode = 0; 806 m_exceptionCode = 0;
781 m_error = false; 807 m_error = false;
782 808
783 if (m_async) { 809 if (m_async) {
784 if (m_upload) 810 if (m_upload)
785 request.setReportUploadProgress(true); 811 request.setReportUploadProgress(true);
786 812
787 // ThreadableLoader::create can return null here, for example if we're n o longer attached to a page. 813 // ThreadableLoader::create can return null here, for example if we're n o longer attached to a page.
788 // This is true while running onunload handlers. 814 // This is true while running onunload handlers.
789 // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload , <http://bugs.webkit.org/show_bug.cgi?id=10904>. 815 // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload , <http://bugs.webkit.org/show_bug.cgi?id=10904>.
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after
1195 m_response.setHTTPHeaderField("Content-Type", m_mimeTypeOverride); 1221 m_response.setHTTPHeaderField("Content-Type", m_mimeTypeOverride);
1196 m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride); 1222 m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride);
1197 } 1223 }
1198 1224
1199 if (m_responseEncoding.isEmpty()) 1225 if (m_responseEncoding.isEmpty())
1200 m_responseEncoding = response.textEncodingName(); 1226 m_responseEncoding = response.textEncodingName();
1201 } 1227 }
1202 1228
1203 void XMLHttpRequest::didReceiveData(const char* data, int len) 1229 void XMLHttpRequest::didReceiveData(const char* data, int len)
1204 { 1230 {
1231 ASSERT(m_responseTypeCode != ResponseTypeBlob);
1232
1205 if (m_error) 1233 if (m_error)
1206 return; 1234 return;
1207 1235
1208 if (m_state < HEADERS_RECEIVED) 1236 if (m_state < HEADERS_RECEIVED)
1209 changeState(HEADERS_RECEIVED); 1237 changeState(HEADERS_RECEIVED);
1210 1238
1211 bool useDecoder = m_responseTypeCode == ResponseTypeDefault || m_responseTyp eCode == ResponseTypeText || m_responseTypeCode == ResponseTypeJSON || m_respons eTypeCode == ResponseTypeDocument; 1239 bool useDecoder = m_responseTypeCode == ResponseTypeDefault || m_responseTyp eCode == ResponseTypeText || m_responseTypeCode == ResponseTypeJSON || m_respons eTypeCode == ResponseTypeDocument;
1212 1240
1213 if (useDecoder && !m_decoder) { 1241 if (useDecoder && !m_decoder) {
1214 if (m_responseTypeCode == ResponseTypeJSON) 1242 if (m_responseTypeCode == ResponseTypeJSON)
(...skipping 12 matching lines...) Expand all
1227 } 1255 }
1228 1256
1229 if (!len) 1257 if (!len)
1230 return; 1258 return;
1231 1259
1232 if (len == -1) 1260 if (len == -1)
1233 len = strlen(data); 1261 len = strlen(data);
1234 1262
1235 if (useDecoder) { 1263 if (useDecoder) {
1236 m_responseText = m_responseText.concatenateWith(m_decoder->decode(data, len)); 1264 m_responseText = m_responseText.concatenateWith(m_decoder->decode(data, len));
1237 } else if (m_responseTypeCode == ResponseTypeArrayBuffer || m_responseTypeCo de == ResponseTypeBlob) { 1265 } else if (m_responseTypeCode == ResponseTypeArrayBuffer) {
1238 // Buffer binary data. 1266 // Buffer binary data.
1239 if (!m_binaryResponseBuilder) 1267 if (!m_binaryResponseBuilder)
1240 m_binaryResponseBuilder = SharedBuffer::create(); 1268 m_binaryResponseBuilder = SharedBuffer::create();
1241 m_binaryResponseBuilder->append(data, len); 1269 m_binaryResponseBuilder->append(data, len);
1242 } else if (m_responseTypeCode == ResponseTypeStream) { 1270 } else if (m_responseTypeCode == ResponseTypeStream) {
1243 if (!m_responseStream) 1271 if (!m_responseStream)
1244 m_responseStream = Stream::create(responseMIMEType()); 1272 m_responseStream = Stream::create(responseMIMEType());
1245 m_responseStream->addData(data, len); 1273 m_responseStream->addData(data, len);
1246 } 1274 }
1247 1275
1248 if (!m_error) { 1276 if (!m_error)
1249 long long expectedLength = m_response.expectedContentLength(); 1277 trackProgress(len);
1250 m_receivedLength += len; 1278 }
1251 1279
1252 if (m_async) { 1280 void XMLHttpRequest::didDownloadData(int len)
1253 bool lengthComputable = expectedLength > 0 && m_receivedLength <= ex pectedLength; 1281 {
1254 unsigned long long total = lengthComputable ? expectedLength : 0; 1282 ASSERT(m_responseTypeCode == ResponseTypeBlob);
1255 m_progressEventThrottle.dispatchProgressEvent(lengthComputable, m_re ceivedLength, total);
1256 }
1257 1283
1258 if (m_state != LOADING) 1284 if (m_error)
1259 changeState(LOADING); 1285 return;
1260 else 1286
1261 // Firefox calls readyStateChanged every time it receives data, 4449 442 1287 if (m_state < HEADERS_RECEIVED)
1262 callReadyStateChangeListener(); 1288 changeState(HEADERS_RECEIVED);
1263 } 1289
1290 if (!len)
1291 return;
1292
1293 if (!m_error)
1294 trackProgress(len);
1264 } 1295 }
1265 1296
1266 void XMLHttpRequest::handleDidTimeout() 1297 void XMLHttpRequest::handleDidTimeout()
1267 { 1298 {
1268 // internalAbort() calls dropProtection(), which may release the last refere nce. 1299 // internalAbort() calls dropProtection(), which may release the last refere nce.
1269 RefPtr<XMLHttpRequest> protect(this); 1300 RefPtr<XMLHttpRequest> protect(this);
1270 1301
1271 if (!internalAbort()) 1302 if (!internalAbort())
1272 return; 1303 return;
1273 1304
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1314 { 1345 {
1315 return eventNames().interfaceForXMLHttpRequest; 1346 return eventNames().interfaceForXMLHttpRequest;
1316 } 1347 }
1317 1348
1318 ScriptExecutionContext* XMLHttpRequest::scriptExecutionContext() const 1349 ScriptExecutionContext* XMLHttpRequest::scriptExecutionContext() const
1319 { 1350 {
1320 return ActiveDOMObject::scriptExecutionContext(); 1351 return ActiveDOMObject::scriptExecutionContext();
1321 } 1352 }
1322 1353
1323 } // namespace WebCore 1354 } // 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