Index: Source/core/xml/XMLHttpRequest.cpp |
diff --git a/Source/core/xml/XMLHttpRequest.cpp b/Source/core/xml/XMLHttpRequest.cpp |
index 30c501640c68d1f1d7c453ae08f7ca615b3f6e22..d263355af8508105b4306388040d991fe8ea86b1 100644 |
--- a/Source/core/xml/XMLHttpRequest.cpp |
+++ b/Source/core/xml/XMLHttpRequest.cpp |
@@ -26,6 +26,7 @@ |
#include "bindings/core/v8/ExceptionState.h" |
#include "core/FetchInitiatorTypeNames.h" |
#include "core/dom/ContextFeatures.h" |
+#include "core/dom/DOMException.h" |
#include "core/dom/DOMImplementation.h" |
#include "core/dom/ExceptionCode.h" |
#include "core/dom/XMLDocument.h" |
@@ -44,7 +45,10 @@ |
#include "core/inspector/InspectorInstrumentation.h" |
#include "core/inspector/InspectorTraceEvents.h" |
#include "core/loader/ThreadableLoader.h" |
+#include "core/streams/ReadableStream.h" |
+#include "core/streams/ReadableStreamImpl.h" |
#include "core/streams/Stream.h" |
+#include "core/streams/UnderlyingSource.h" |
#include "core/xml/XMLHttpRequestProgressEvent.h" |
#include "core/xml/XMLHttpRequestUpload.h" |
#include "platform/Logging.h" |
@@ -111,6 +115,34 @@ static void logConsoleError(ExecutionContext* context, const String& message) |
context->addConsoleMessage(ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, message)); |
} |
+namespace { |
+ |
+class ReadableStreamSource : public GarbageCollectedFinalized<ReadableStreamSource>, public UnderlyingSource { |
+ USING_GARBAGE_COLLECTED_MIXIN(ReadableStreamSource); |
+public: |
+ ReadableStreamSource(XMLHttpRequest* owner) : m_owner(owner) { } |
+ virtual ~ReadableStreamSource() { } |
+ virtual void pullSource() OVERRIDE { } |
+ virtual ScriptPromise cancelSource(ScriptState* scriptState, ScriptValue reason) OVERRIDE |
+ { |
+ m_owner->abort(); |
+ return ScriptPromise::cast(scriptState, v8::Undefined(scriptState->isolate())); |
+ } |
+ virtual void trace(Visitor* visitor) OVERRIDE |
+ { |
+ visitor->trace(m_owner); |
+ UnderlyingSource::trace(visitor); |
+ } |
+ |
+private: |
+ // This is RawPtr in non-oilpan build to avoid the reference cycle. To |
+ // avoid use-after free, the associated ReadableStream must be closed |
+ // or errored when m_owner is gone. |
+ RawPtrWillBeMember<XMLHttpRequest> m_owner; |
+}; |
+ |
+} // namespace |
+ |
PassRefPtrWillBeRawPtr<XMLHttpRequest> XMLHttpRequest::create(ExecutionContext* context, PassRefPtr<SecurityOrigin> securityOrigin) |
{ |
RefPtrWillBeRawPtr<XMLHttpRequest> xmlHttpRequest = adoptRefWillBeRefCountedGarbageCollected(new XMLHttpRequest(context, securityOrigin)); |
@@ -295,14 +327,23 @@ ArrayBuffer* XMLHttpRequest::responseArrayBuffer() |
return m_responseArrayBuffer.get(); |
} |
-Stream* XMLHttpRequest::responseStream() |
+Stream* XMLHttpRequest::responseLegacyStream() |
{ |
ASSERT(m_responseTypeCode == ResponseTypeLegacyStream); |
if (m_error || (m_state != LOADING && m_state != DONE)) |
return 0; |
- return m_responseStream.get(); |
+ return m_responseLegacyStream.get(); |
+} |
+ |
+ReadableStream* XMLHttpRequest::responseStream() |
+{ |
+ ASSERT(m_responseTypeCode == ResponseTypeStream); |
+ if (m_error || (m_state != LOADING && m_state != DONE)) |
+ return 0; |
+ |
+ return m_responseStream; |
} |
void XMLHttpRequest::setTimeout(unsigned long timeout, ExceptionState& exceptionState) |
@@ -356,6 +397,11 @@ void XMLHttpRequest::setResponseType(const String& responseType, ExceptionState& |
m_responseTypeCode = ResponseTypeLegacyStream; |
else |
return; |
+ } else if (responseType == "stream") { |
+ if (RuntimeEnabledFeatures::streamEnabled()) |
+ m_responseTypeCode = ResponseTypeStream; |
+ else |
+ return; |
} else { |
ASSERT_NOT_REACHED(); |
} |
@@ -378,6 +424,8 @@ String XMLHttpRequest::responseType() |
return "arraybuffer"; |
case ResponseTypeLegacyStream: |
return "legacystream"; |
+ case ResponseTypeStream: |
+ return "stream"; |
} |
return ""; |
} |
@@ -893,8 +941,15 @@ bool XMLHttpRequest::internalAbort() |
InspectorInstrumentation::didFailXHRLoading(executionContext(), this, this); |
- if (m_responseStream && m_state != DONE) |
- m_responseStream->abort(); |
+ if (m_responseLegacyStream && m_state != DONE) |
+ m_responseLegacyStream->abort(); |
+ |
+ if (m_responseStream) { |
+ // When the stream is already closed (including canceled from the |
+ // user), |error| does nothing. |
+ // FIXME: Create a more specific error. |
+ m_responseStream->error(DOMException::create(!m_async && m_exceptionCode ? m_exceptionCode : AbortError, "XMLHttpRequest::abort")); |
+ } |
if (!m_loader) |
return true; |
@@ -936,6 +991,7 @@ void XMLHttpRequest::clearResponse() |
m_responseBlob = nullptr; |
m_downloadedBlobLength = 0; |
+ m_responseLegacyStream = nullptr; |
m_responseStream = nullptr; |
// These variables may referred by the response accessors. So, we can clear |
@@ -1229,8 +1285,11 @@ void XMLHttpRequest::didFinishLoading(unsigned long identifier, double) |
if (m_decoder) |
m_responseText = m_responseText.concatenateWith(m_decoder->flush()); |
+ if (m_responseLegacyStream) |
+ m_responseLegacyStream->finalize(); |
+ |
if (m_responseStream) |
- m_responseStream->finalize(); |
+ m_responseStream->close(); |
clearVariablesForLoading(); |
@@ -1326,9 +1385,15 @@ void XMLHttpRequest::didReceiveData(const char* data, int len) |
m_binaryResponseBuilder = SharedBuffer::create(); |
m_binaryResponseBuilder->append(data, len); |
} else if (m_responseTypeCode == ResponseTypeLegacyStream) { |
- if (!m_responseStream) |
- m_responseStream = Stream::create(executionContext(), finalResponseMIMEType()); |
- m_responseStream->addData(data, len); |
+ if (!m_responseLegacyStream) |
+ m_responseLegacyStream = Stream::create(executionContext(), responseType()); |
+ m_responseLegacyStream->addData(data, len); |
+ } else if (m_responseTypeCode == ResponseTypeStream) { |
+ if (!m_responseStream) { |
+ m_responseStream = new ReadableStreamImpl<ReadableStreamChunkTypeTraits<ArrayBuffer> >(executionContext(), new ReadableStreamSource(this)); |
+ m_responseStream->didSourceStart(); |
+ } |
+ m_responseStream->enqueue(ArrayBuffer::create(data, len)); |
} |
if (m_error) |
@@ -1417,7 +1482,9 @@ ExecutionContext* XMLHttpRequest::executionContext() const |
void XMLHttpRequest::trace(Visitor* visitor) |
{ |
visitor->trace(m_responseBlob); |
+ visitor->trace(m_responseLegacyStream); |
visitor->trace(m_responseStream); |
+ visitor->trace(m_streamSource); |
visitor->trace(m_responseDocument); |
visitor->trace(m_progressEventThrottle); |
visitor->trace(m_upload); |