Chromium Code Reviews| Index: Source/core/xml/XMLHttpRequest.cpp |
| diff --git a/Source/core/xml/XMLHttpRequest.cpp b/Source/core/xml/XMLHttpRequest.cpp |
| index a60f006e62f9df73f7c3665f4f391ec5fc78247d..9607ea44d7a7ac95c4d4154e589450faa4f83e7f 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(); |
| @@ -824,6 +825,11 @@ void XMLHttpRequest::createRequest(ExceptionState& exceptionState) |
| request.setHTTPMethod(m_method); |
| request.setTargetType(ResourceRequest::TargetIsXHR); |
| + // When responseType is set to "blob", we redirect the downloaded data to a |
| + // file-handle directly. |
| + if (responseTypeCode() == ResponseTypeBlob) |
| + request.setDownloadToFile(true); |
| + |
| InspectorInstrumentation::willLoadXHR(&executionContext, this, this, m_method, m_url, m_async, m_requestEntityBody ? m_requestEntityBody->deepCopy() : nullptr, m_requestHeaders, m_includeCredentials); |
| if (m_requestEntityBody) { |
| @@ -848,6 +854,11 @@ void XMLHttpRequest::createRequest(ExceptionState& exceptionState) |
| options.mixedContentBlockingTreatment = TreatAsPassiveContent; |
| options.timeoutMilliseconds = m_timeoutMilliseconds; |
| + // When responseType is set to "blob", we redirect the downloaded data to a |
| + // file-handle directly. So, buffering is not needed. |
| + if (responseTypeCode() == ResponseTypeBlob) |
|
Nate Chapin
2014/06/02 16:59:51
Can we combine the two blob cases in this function
tyoshino (SeeGerritForStatus)
2014/06/04 04:39:50
Done.
|
| + options.dataBufferingPolicy = DoNotBufferData; |
| + |
| m_exceptionCode = 0; |
| m_error = false; |
| @@ -971,6 +982,7 @@ void XMLHttpRequest::clearResponse() |
| m_responseDocument = nullptr; |
| m_responseBlob = nullptr; |
| + m_downloadedBlobLength = 0; |
| m_responseStream = nullptr; |
| @@ -1308,6 +1320,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; |
| @@ -1340,7 +1354,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(); |
| @@ -1357,6 +1371,27 @@ 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; |
| + |
| + if (m_error) |
|
Nate Chapin
2014/06/02 16:59:51
This looks redundant. Can changeState cancel the X
tyoshino (SeeGerritForStatus)
2014/06/04 04:39:50
Yes. We need this. changeState() calls readystatec
|
| + return; |
| + |
| + m_downloadedBlobLength += dataLength; |
| + |
| + trackProgress(dataLength); |
| +} |
| + |
| void XMLHttpRequest::handleDidTimeout() |
| { |
| WTF_LOG(Network, "XMLHttpRequest %p handleDidTimeout()", this); |