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

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, 3 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 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 } 269 }
270 m_createdDocument = true; 270 m_createdDocument = true;
271 } 271 }
272 272
273 return m_responseDocument.get(); 273 return m_responseDocument.get();
274 } 274 }
275 275
276 Blob* XMLHttpRequest::responseBlob() 276 Blob* XMLHttpRequest::responseBlob()
277 { 277 {
278 ASSERT(m_responseTypeCode == ResponseTypeBlob); 278 ASSERT(m_responseTypeCode == ResponseTypeBlob);
279 ASSERT(!m_binaryResponseBuilder.get());
279 280
280 // We always return null before DONE. 281 // We always return null before DONE.
281 if (m_error || m_state != DONE) 282 if (m_error || m_state != DONE)
282 return 0; 283 return 0;
283 284
284 if (!m_responseBlob) { 285 if (!m_responseBlob) {
285 // FIXME: This causes two (or more) unnecessary copies of the data. 286 // When "blob" is specified for the responseType attribute,
286 // Chromium stores blob data in the browser process, so we're pulling th e data 287 // 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. 288 // in the browser process.
288 // Ideally we'd get the blob/file-handle from the ResourceResponse direc tly 289 // We get the file-path from the ResourceResponse directly
289 // instead of copying the bytes. Embedders who store blob data in the 290 // 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(); 291 OwnPtr<BlobData> blobData = BlobData::create();
292 const String& filePath = m_response.downloadedFilePath();
293 // If we errored out or got no data, we still return a blob, just an emp ty one. 293 // If we errored out or got no data, we still return a blob, just an emp ty one.
294 size_t size = 0; 294 if (!filePath.isEmpty() && m_receivedLength) {
295 if (m_binaryResponseBuilder) { 295 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. 296 blobData->setContentType(responseMIMEType()); // responseMIMEType de faults to text/xml which may be incorrect.
301 m_binaryResponseBuilder.clear();
302 } 297 }
303 m_responseBlob = Blob::create(blobData.release(), size); 298 m_responseBlob = Blob::create(blobData.release(), m_receivedLength);
304 } 299 }
305 300
306 return m_responseBlob.get(); 301 return m_responseBlob.get();
307 } 302 }
308 303
309 ArrayBuffer* XMLHttpRequest::responseArrayBuffer() 304 ArrayBuffer* XMLHttpRequest::responseArrayBuffer()
310 { 305 {
311 ASSERT(m_responseTypeCode == ResponseTypeArrayBuffer); 306 ASSERT(m_responseTypeCode == ResponseTypeArrayBuffer);
312 307
313 if (m_error || m_state != DONE) 308 if (m_error || m_state != DONE)
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
405 return ""; 400 return "";
406 } 401 }
407 402
408 XMLHttpRequestUpload* XMLHttpRequest::upload() 403 XMLHttpRequestUpload* XMLHttpRequest::upload()
409 { 404 {
410 if (!m_upload) 405 if (!m_upload)
411 m_upload = XMLHttpRequestUpload::create(this); 406 m_upload = XMLHttpRequestUpload::create(this);
412 return m_upload.get(); 407 return m_upload.get();
413 } 408 }
414 409
410 void XMLHttpRequest::trackProgress(int len)
411 {
412 long long expectedLength = m_response.expectedContentLength();
413 m_receivedLength += len;
414
415 if (m_async) {
416 bool lengthComputable = expectedLength > 0 && m_receivedLength <= expect edLength;
417 unsigned long long total = lengthComputable ? expectedLength : 0;
418 m_progressEventThrottle.dispatchProgressEvent(lengthComputable, m_receiv edLength, total);
419 }
420
421 if (m_state != LOADING) {
422 changeState(LOADING);
423 } else {
424 // Firefox calls readyStateChanged every time it receives data, 4449442
425 callReadyStateChangeListener();
426 }
427 }
428
415 void XMLHttpRequest::changeState(State newState) 429 void XMLHttpRequest::changeState(State newState)
416 { 430 {
417 if (m_state != newState) { 431 if (m_state != newState) {
418 m_state = newState; 432 m_state = newState;
419 callReadyStateChangeListener(); 433 callReadyStateChangeListener();
420 } 434 }
421 } 435 }
422 436
423 void XMLHttpRequest::callReadyStateChangeListener() 437 void XMLHttpRequest::callReadyStateChangeListener()
424 { 438 {
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after
745 m_sameOriginRequest = securityOrigin()->canRequest(m_url); 759 m_sameOriginRequest = securityOrigin()->canRequest(m_url);
746 760
747 // We also remember whether upload events should be allowed for this request in case the upload listeners are 761 // We also remember whether upload events should be allowed for this request in case the upload listeners are
748 // added after the request is started. 762 // added after the request is started.
749 m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCros sOriginAccessRequest(m_method, m_requestHeaders); 763 m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCros sOriginAccessRequest(m_method, m_requestHeaders);
750 764
751 ResourceRequest request(m_url); 765 ResourceRequest request(m_url);
752 request.setHTTPMethod(m_method); 766 request.setHTTPMethod(m_method);
753 request.setTargetType(ResourceRequest::TargetIsXHR); 767 request.setTargetType(ResourceRequest::TargetIsXHR);
754 768
769 // When "blob" is specified for the responseType attribute,
770 // we redirect the downloaded data to a file-handle directly
yusukesuzuki 2013/09/19 07:34:34 Fixed comment.
771 // and get the file-path as the result.
772 if (responseTypeCode() == ResponseTypeBlob)
773 request.setDownloadToFile(true);
774
755 InspectorInstrumentation::willLoadXHR(scriptExecutionContext(), this, m_meth od, m_url, m_async, m_requestEntityBody ? m_requestEntityBody->deepCopy() : 0, m _requestHeaders, m_includeCredentials); 775 InspectorInstrumentation::willLoadXHR(scriptExecutionContext(), this, m_meth od, m_url, m_async, m_requestEntityBody ? m_requestEntityBody->deepCopy() : 0, m _requestHeaders, m_includeCredentials);
756 776
757 if (m_requestEntityBody) { 777 if (m_requestEntityBody) {
758 ASSERT(m_method != "GET"); 778 ASSERT(m_method != "GET");
759 ASSERT(m_method != "HEAD"); 779 ASSERT(m_method != "HEAD");
760 request.setHTTPBody(m_requestEntityBody.release()); 780 request.setHTTPBody(m_requestEntityBody.release());
761 } 781 }
762 782
763 if (m_requestHeaders.size() > 0) 783 if (m_requestHeaders.size() > 0)
764 request.addHTTPHeaderFields(m_requestHeaders); 784 request.addHTTPHeaderFields(m_requestHeaders);
765 785
766 ThreadableLoaderOptions options; 786 ThreadableLoaderOptions options;
767 options.sendLoadCallbacks = SendCallbacks; 787 options.sendLoadCallbacks = SendCallbacks;
768 options.sniffContent = DoNotSniffContent; 788 options.sniffContent = DoNotSniffContent;
769 options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight; 789 options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight;
770 options.allowCredentials = (m_sameOriginRequest || m_includeCredentials) ? A llowStoredCredentials : DoNotAllowStoredCredentials; 790 options.allowCredentials = (m_sameOriginRequest || m_includeCredentials) ? A llowStoredCredentials : DoNotAllowStoredCredentials;
771 options.credentialsRequested = m_includeCredentials ? ClientRequestedCredent ials : ClientDidNotRequestCredentials; 791 options.credentialsRequested = m_includeCredentials ? ClientRequestedCredent ials : ClientDidNotRequestCredentials;
772 options.crossOriginRequestPolicy = m_allowCrossOriginRequests ? AllowCrossOr iginRequests : UseAccessControl; 792 options.crossOriginRequestPolicy = m_allowCrossOriginRequests ? AllowCrossOr iginRequests : UseAccessControl;
773 options.securityOrigin = securityOrigin(); 793 options.securityOrigin = securityOrigin();
774 options.initiator = FetchInitiatorTypeNames::xmlhttprequest; 794 options.initiator = FetchInitiatorTypeNames::xmlhttprequest;
775 options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypa ssMainWorld(scriptExecutionContext()) ? DoNotEnforceContentSecurityPolicy : Enfo rceConnectSrcDirective; 795 options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypa ssMainWorld(scriptExecutionContext()) ? DoNotEnforceContentSecurityPolicy : Enfo rceConnectSrcDirective;
776 options.mixedContentBlockingTreatment = TreatAsActiveContent; 796 options.mixedContentBlockingTreatment = TreatAsActiveContent;
777 options.timeoutMilliseconds = m_timeoutMilliseconds; 797 options.timeoutMilliseconds = m_timeoutMilliseconds;
778 798
799 // Since we redirect the downloaded data to a file-handle directly
yusukesuzuki 2013/09/19 07:34:34 Fixed comment.
800 // when "blob" is specified for the responseType attribute,
801 // buffering is not needed.
802 if (responseTypeCode() == ResponseTypeBlob)
803 options.dataBufferingPolicy = DoNotBufferData;
804
779 m_exceptionCode = 0; 805 m_exceptionCode = 0;
780 m_error = false; 806 m_error = false;
781 807
782 if (m_async) { 808 if (m_async) {
783 if (m_upload) 809 if (m_upload)
784 request.setReportUploadProgress(true); 810 request.setReportUploadProgress(true);
785 811
786 // ThreadableLoader::create can return null here, for example if we're n o longer attached to a page. 812 // ThreadableLoader::create can return null here, for example if we're n o longer attached to a page.
787 // This is true while running onunload handlers. 813 // This is true while running onunload handlers.
788 // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload , <http://bugs.webkit.org/show_bug.cgi?id=10904>. 814 // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload , <http://bugs.webkit.org/show_bug.cgi?id=10904>.
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after
1169 m_response.setHTTPHeaderField("Content-Type", m_mimeTypeOverride); 1195 m_response.setHTTPHeaderField("Content-Type", m_mimeTypeOverride);
1170 m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride); 1196 m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride);
1171 } 1197 }
1172 1198
1173 if (m_responseEncoding.isEmpty()) 1199 if (m_responseEncoding.isEmpty())
1174 m_responseEncoding = response.textEncodingName(); 1200 m_responseEncoding = response.textEncodingName();
1175 } 1201 }
1176 1202
1177 void XMLHttpRequest::didReceiveData(const char* data, int len) 1203 void XMLHttpRequest::didReceiveData(const char* data, int len)
1178 { 1204 {
1205 ASSERT(m_responseTypeCode != ResponseTypeBlob);
1206
1179 if (m_error) 1207 if (m_error)
1180 return; 1208 return;
1181 1209
1182 if (m_state < HEADERS_RECEIVED) 1210 if (m_state < HEADERS_RECEIVED)
1183 changeState(HEADERS_RECEIVED); 1211 changeState(HEADERS_RECEIVED);
1184 1212
1185 bool useDecoder = m_responseTypeCode == ResponseTypeDefault || m_responseTyp eCode == ResponseTypeText || m_responseTypeCode == ResponseTypeJSON || m_respons eTypeCode == ResponseTypeDocument; 1213 bool useDecoder = m_responseTypeCode == ResponseTypeDefault || m_responseTyp eCode == ResponseTypeText || m_responseTypeCode == ResponseTypeJSON || m_respons eTypeCode == ResponseTypeDocument;
1186 1214
1187 if (useDecoder && !m_decoder) { 1215 if (useDecoder && !m_decoder) {
1188 if (m_responseTypeCode == ResponseTypeJSON) 1216 if (m_responseTypeCode == ResponseTypeJSON)
(...skipping 12 matching lines...) Expand all
1201 } 1229 }
1202 1230
1203 if (!len) 1231 if (!len)
1204 return; 1232 return;
1205 1233
1206 if (len == -1) 1234 if (len == -1)
1207 len = strlen(data); 1235 len = strlen(data);
1208 1236
1209 if (useDecoder) { 1237 if (useDecoder) {
1210 m_responseText = m_responseText.concatenateWith(m_decoder->decode(data, len)); 1238 m_responseText = m_responseText.concatenateWith(m_decoder->decode(data, len));
1211 } else if (m_responseTypeCode == ResponseTypeArrayBuffer || m_responseTypeCo de == ResponseTypeBlob) { 1239 } else if (m_responseTypeCode == ResponseTypeArrayBuffer) {
1212 // Buffer binary data. 1240 // Buffer binary data.
1213 if (!m_binaryResponseBuilder) 1241 if (!m_binaryResponseBuilder)
1214 m_binaryResponseBuilder = SharedBuffer::create(); 1242 m_binaryResponseBuilder = SharedBuffer::create();
1215 m_binaryResponseBuilder->append(data, len); 1243 m_binaryResponseBuilder->append(data, len);
1216 } else if (m_responseTypeCode == ResponseTypeStream) { 1244 } else if (m_responseTypeCode == ResponseTypeStream) {
1217 if (!m_responseStream) 1245 if (!m_responseStream)
1218 m_responseStream = Stream::create(responseMIMEType()); 1246 m_responseStream = Stream::create(responseMIMEType());
1219 m_responseStream->addData(data, len); 1247 m_responseStream->addData(data, len);
1220 } 1248 }
1221 1249
1222 if (!m_error) { 1250 if (!m_error)
1223 long long expectedLength = m_response.expectedContentLength(); 1251 trackProgress(len);
1224 m_receivedLength += len; 1252 }
1225 1253
1226 if (m_async) { 1254 void XMLHttpRequest::didDownloadData(int len)
1227 bool lengthComputable = expectedLength > 0 && m_receivedLength <= ex pectedLength; 1255 {
1228 unsigned long long total = lengthComputable ? expectedLength : 0; 1256 ASSERT(m_responseTypeCode == ResponseTypeBlob);
1229 m_progressEventThrottle.dispatchProgressEvent(lengthComputable, m_re ceivedLength, total);
1230 }
1231 1257
1232 if (m_state != LOADING) 1258 if (m_error)
1233 changeState(LOADING); 1259 return;
1234 else 1260
1235 // Firefox calls readyStateChanged every time it receives data, 4449 442 1261 if (m_state < HEADERS_RECEIVED)
1236 callReadyStateChangeListener(); 1262 changeState(HEADERS_RECEIVED);
1237 } 1263
1264 if (!len)
1265 return;
1266
1267 if (!m_error)
1268 trackProgress(len);
1238 } 1269 }
1239 1270
1240 void XMLHttpRequest::didTimeout() 1271 void XMLHttpRequest::didTimeout()
1241 { 1272 {
1242 // internalAbort() calls dropProtection(), which may release the last refere nce. 1273 // internalAbort() calls dropProtection(), which may release the last refere nce.
1243 RefPtr<XMLHttpRequest> protect(this); 1274 RefPtr<XMLHttpRequest> protect(this);
1244 internalAbort(); 1275 internalAbort();
1245 1276
1246 clearResponse(); 1277 clearResponse();
1247 clearRequest(); 1278 clearRequest();
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1295 { 1326 {
1296 return eventNames().interfaceForXMLHttpRequest; 1327 return eventNames().interfaceForXMLHttpRequest;
1297 } 1328 }
1298 1329
1299 ScriptExecutionContext* XMLHttpRequest::scriptExecutionContext() const 1330 ScriptExecutionContext* XMLHttpRequest::scriptExecutionContext() const
1300 { 1331 {
1301 return ActiveDOMObject::scriptExecutionContext(); 1332 return ActiveDOMObject::scriptExecutionContext();
1302 } 1333 }
1303 1334
1304 } // namespace WebCore 1335 } // 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