Index: Source/core/xml/XMLHttpRequest.cpp |
diff --git a/Source/core/xml/XMLHttpRequest.cpp b/Source/core/xml/XMLHttpRequest.cpp |
index 155d442a87685d72eb63d6880596e1f05334d727..2a585245b23d0b254675ac78d083214150baeb33 100644 |
--- a/Source/core/xml/XMLHttpRequest.cpp |
+++ b/Source/core/xml/XMLHttpRequest.cpp |
@@ -171,6 +171,7 @@ XMLHttpRequest::XMLHttpRequest(ExecutionContext* context, PassRefPtr<SecurityOri |
, m_timeoutMilliseconds(0) |
, m_state(UNSENT) |
, m_createdDocument(false) |
+ , m_downloadedBlobLength(0) |
, m_error(false) |
, m_uploadEventsAllowed(true) |
, m_uploadComplete(false) |
@@ -276,26 +277,26 @@ Document* XMLHttpRequest::responseXML(ExceptionState& exceptionState) |
Blob* XMLHttpRequest::responseBlob() |
{ |
ASSERT(m_responseTypeCode == ResponseTypeBlob); |
+ ASSERT(!m_binaryResponseBuilder.get()); |
// We always return null before DONE. |
if (m_error || m_state != DONE) |
return 0; |
if (!m_responseBlob) { |
- // FIXME: Once RedirectToFileResourceHandler is fixed in Chromium, |
- // re-enable download-to-file optimization introduced by Blink revision |
- // 163141. |
+ // When responseType is set to "blob", we redirect the downloaded data |
+ // to a file-handle directly in the browser process. We get the |
+ // file-path from the ResourceResponse directly instead of copying the |
+ // bytes between the browser and the renderer. |
OwnPtr<BlobData> blobData = BlobData::create(); |
- size_t size = 0; |
- if (m_binaryResponseBuilder.get() && m_binaryResponseBuilder->size() > 0) { |
- RefPtr<RawData> rawData = RawData::create(); |
- size = m_binaryResponseBuilder->size(); |
- rawData->mutableData()->append(m_binaryResponseBuilder->data(), size); |
- blobData->appendData(rawData, 0, BlobDataItem::toEndOfFile); |
+ String filePath = m_response.downloadedFilePath(); |
+ // If we errored out or got no data, we still return a blob, just an |
+ // empty one. |
+ if (!filePath.isEmpty() && m_downloadedBlobLength) { |
+ blobData->appendFile(filePath); |
blobData->setContentType(responseMIMEType()); // responseMIMEType defaults to text/xml which may be incorrect. |
- m_binaryResponseBuilder.clear(); |
} |
- m_responseBlob = Blob::create(BlobDataHandle::create(blobData.release(), size)); |
+ m_responseBlob = Blob::create(BlobDataHandle::create(blobData.release(), m_downloadedBlobLength)); |
} |
return m_responseBlob.get(); |
@@ -854,6 +855,13 @@ void XMLHttpRequest::createRequest(ExceptionState& exceptionState) |
// TODO(tsepez): Specify TreatAsActiveContent per http://crbug.com/305303. |
resourceLoaderOptions.mixedContentBlockingTreatment = TreatAsPassiveContent; |
+ // When responseType is set to "blob", we redirect the downloaded data to a |
+ // file-handle directly. |
+ if (responseTypeCode() == ResponseTypeBlob) { |
+ request.setDownloadToFile(true); |
+ resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData; |
+ } |
+ |
m_exceptionCode = 0; |
m_error = false; |
@@ -977,6 +985,7 @@ void XMLHttpRequest::clearResponse() |
m_responseDocument = nullptr; |
m_responseBlob = nullptr; |
+ m_downloadedBlobLength = 0; |
m_responseStream = nullptr; |
@@ -1314,6 +1323,8 @@ void XMLHttpRequest::didReceiveResponse(unsigned long identifier, const Resource |
void XMLHttpRequest::didReceiveData(const char* data, int len) |
{ |
+ ASSERT(m_responseTypeCode != ResponseTypeBlob); |
+ |
if (m_error) |
return; |
@@ -1346,7 +1357,7 @@ void XMLHttpRequest::didReceiveData(const char* data, int len) |
if (useDecoder) { |
m_responseText = m_responseText.concatenateWith(m_decoder->decode(data, len)); |
- } else if (m_responseTypeCode == ResponseTypeArrayBuffer || m_responseTypeCode == ResponseTypeBlob) { |
+ } else if (m_responseTypeCode == ResponseTypeArrayBuffer) { |
// Buffer binary data. |
if (!m_binaryResponseBuilder) |
m_binaryResponseBuilder = SharedBuffer::create(); |
@@ -1363,6 +1374,29 @@ void XMLHttpRequest::didReceiveData(const char* data, int len) |
trackProgress(len); |
} |
+void XMLHttpRequest::didDownloadData(int dataLength) |
+{ |
+ ASSERT(m_responseTypeCode == ResponseTypeBlob); |
+ |
+ if (m_error) |
+ return; |
+ |
+ if (m_state < HEADERS_RECEIVED) |
+ changeState(HEADERS_RECEIVED); |
+ |
+ if (!dataLength) |
+ return; |
+ |
+ // readystatechange event handler may do something to put this XHR in error |
+ // state. We need to check m_error again here. |
+ if (m_error) |
+ return; |
+ |
+ m_downloadedBlobLength += dataLength; |
+ |
+ trackProgress(dataLength); |
+} |
+ |
void XMLHttpRequest::handleDidTimeout() |
{ |
WTF_LOG(Network, "XMLHttpRequest %p handleDidTimeout()", this); |