OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "modules/fetch/BodyStreamBuffer.h" | 5 #include "modules/fetch/BodyStreamBuffer.h" |
6 | 6 |
| 7 #include "bindings/core/v8/ScriptState.h" |
| 8 #include "bindings/core/v8/V8HiddenValue.h" |
7 #include "core/dom/DOMArrayBuffer.h" | 9 #include "core/dom/DOMArrayBuffer.h" |
8 #include "core/dom/DOMTypedArray.h" | 10 #include "core/dom/DOMTypedArray.h" |
9 #include "core/dom/ExceptionCode.h" | 11 #include "core/dom/ExceptionCode.h" |
| 12 #include "core/streams/ReadableStreamController.h" |
| 13 #include "core/streams/ReadableStreamOperations.h" |
| 14 #include "modules/fetch/Body.h" |
10 #include "modules/fetch/DataConsumerHandleUtil.h" | 15 #include "modules/fetch/DataConsumerHandleUtil.h" |
| 16 #include "platform/RuntimeEnabledFeatures.h" |
11 #include "platform/blob/BlobData.h" | 17 #include "platform/blob/BlobData.h" |
12 #include "platform/network/EncodedFormData.h" | 18 #include "platform/network/EncodedFormData.h" |
13 | 19 |
14 namespace blink { | 20 namespace blink { |
15 | 21 |
16 class BodyStreamBuffer::LoaderClient final : public GarbageCollectedFinalized<Lo
aderClient>, public ActiveDOMObject, public FetchDataLoader::Client { | 22 class BodyStreamBuffer::LoaderClient final : public GarbageCollectedFinalized<Lo
aderClient>, public ActiveDOMObject, public FetchDataLoader::Client { |
17 WTF_MAKE_NONCOPYABLE(LoaderClient); | 23 WTF_MAKE_NONCOPYABLE(LoaderClient); |
18 USING_GARBAGE_COLLECTED_MIXIN(LoaderClient); | 24 USING_GARBAGE_COLLECTED_MIXIN(LoaderClient); |
19 public: | 25 public: |
20 LoaderClient(ExecutionContext* executionContext, BodyStreamBuffer* buffer, F
etchDataLoader::Client* client) | 26 LoaderClient(ExecutionContext* executionContext, BodyStreamBuffer* buffer, F
etchDataLoader::Client* client) |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 private: | 72 private: |
67 void stop() override | 73 void stop() override |
68 { | 74 { |
69 m_buffer->stopLoading(); | 75 m_buffer->stopLoading(); |
70 } | 76 } |
71 | 77 |
72 Member<BodyStreamBuffer> m_buffer; | 78 Member<BodyStreamBuffer> m_buffer; |
73 Member<FetchDataLoader::Client> m_client; | 79 Member<FetchDataLoader::Client> m_client; |
74 }; | 80 }; |
75 | 81 |
76 BodyStreamBuffer::BodyStreamBuffer(PassOwnPtr<FetchDataConsumerHandle> handle) | 82 BodyStreamBuffer::BodyStreamBuffer(ScriptState* scriptState, PassOwnPtr<FetchDat
aConsumerHandle> handle) |
77 : m_handle(std::move(handle)) | 83 : UnderlyingSourceBase(scriptState) |
| 84 , m_scriptState(scriptState) |
| 85 , m_handle(std::move(handle)) |
78 , m_reader(m_handle->obtainReader(this)) | 86 , m_reader(m_handle->obtainReader(this)) |
79 , m_stream(new ReadableByteStream(this, new ReadableByteStream::StrictStrate
gy)) | |
80 , m_streamNeedsMore(false) | |
81 { | 87 { |
82 m_stream->didSourceStart(); | 88 if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { |
| 89 ScriptState::Scope scope(scriptState); |
| 90 v8::Local<v8::Value> bodyValue = toV8(this, scriptState); |
| 91 ASSERT(!bodyValue.IsEmpty()); |
| 92 ASSERT(bodyValue->IsObject()); |
| 93 v8::Local<v8::Object> body = bodyValue.As<v8::Object>(); |
| 94 |
| 95 ScriptValue readableStream = ReadableStreamOperations::createReadableStr
eam( |
| 96 scriptState, this, ReadableStreamOperations::createCountQueuingStrat
egy(scriptState, 0)); |
| 97 V8HiddenValue::setHiddenValue(scriptState, body, V8HiddenValue::internal
BodyStream(scriptState->isolate()), readableStream.v8Value()); |
| 98 } else { |
| 99 m_stream = new ReadableByteStream(this, new ReadableByteStream::StrictSt
rategy); |
| 100 m_stream->didSourceStart(); |
| 101 } |
83 } | 102 } |
84 | 103 |
85 PassRefPtr<BlobDataHandle> BodyStreamBuffer::drainAsBlobDataHandle(ExecutionCont
ext* executionContext, FetchDataConsumerHandle::Reader::BlobSizePolicy policy) | 104 ScriptValue BodyStreamBuffer::stream() |
| 105 { |
| 106 ScriptState::Scope scope(m_scriptState.get()); |
| 107 if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { |
| 108 v8::Local<v8::Value> bodyValue = toV8(this, m_scriptState.get()); |
| 109 ASSERT(!bodyValue.IsEmpty()); |
| 110 ASSERT(bodyValue->IsObject()); |
| 111 v8::Local<v8::Object> body = bodyValue.As<v8::Object>(); |
| 112 return ScriptValue(m_scriptState.get(), V8HiddenValue::getHiddenValue(m_
scriptState.get(), body, V8HiddenValue::internalBodyStream(m_scriptState->isolat
e()))); |
| 113 } |
| 114 return ScriptValue(m_scriptState.get(), toV8(m_stream, m_scriptState.get()))
; |
| 115 } |
| 116 |
| 117 PassRefPtr<BlobDataHandle> BodyStreamBuffer::drainAsBlobDataHandle(FetchDataCons
umerHandle::Reader::BlobSizePolicy policy) |
86 { | 118 { |
87 ASSERT(!isStreamLocked()); | 119 ASSERT(!isStreamLocked()); |
88 ASSERT(!isStreamDisturbed()); | 120 ASSERT(!isStreamDisturbed()); |
89 if (isStreamClosed() || isStreamErrored()) | 121 if (isStreamClosed() || isStreamErrored()) |
90 return nullptr; | 122 return nullptr; |
91 | 123 |
92 RefPtr<BlobDataHandle> blobDataHandle = m_reader->drainAsBlobDataHandle(poli
cy); | 124 RefPtr<BlobDataHandle> blobDataHandle = m_reader->drainAsBlobDataHandle(poli
cy); |
93 if (blobDataHandle) { | 125 if (blobDataHandle) { |
94 NonThrowableExceptionState exceptionState; | 126 lockAndDisturb(); |
95 m_stream->getBytesReader(executionContext, exceptionState); | |
96 m_stream->setIsDisturbed(); | |
97 close(); | 127 close(); |
98 return blobDataHandle.release(); | 128 return blobDataHandle.release(); |
99 } | 129 } |
100 return nullptr; | 130 return nullptr; |
101 } | 131 } |
102 | 132 |
103 PassRefPtr<EncodedFormData> BodyStreamBuffer::drainAsFormData(ExecutionContext*
executionContext) | 133 PassRefPtr<EncodedFormData> BodyStreamBuffer::drainAsFormData() |
104 { | 134 { |
105 ASSERT(!isStreamLocked()); | 135 ASSERT(!isStreamLocked()); |
106 ASSERT(!isStreamDisturbed()); | 136 ASSERT(!isStreamDisturbed()); |
107 if (isStreamClosed() || isStreamErrored()) | 137 if (isStreamClosed() || isStreamErrored()) |
108 return nullptr; | 138 return nullptr; |
109 | 139 |
110 RefPtr<EncodedFormData> formData = m_reader->drainAsFormData(); | 140 RefPtr<EncodedFormData> formData = m_reader->drainAsFormData(); |
111 if (formData) { | 141 if (formData) { |
112 NonThrowableExceptionState exceptionState; | 142 lockAndDisturb(); |
113 m_stream->getBytesReader(executionContext, exceptionState); | |
114 m_stream->setIsDisturbed(); | |
115 close(); | 143 close(); |
116 return formData.release(); | 144 return formData.release(); |
117 } | 145 } |
118 return nullptr; | 146 return nullptr; |
119 } | 147 } |
120 | 148 |
121 PassOwnPtr<FetchDataConsumerHandle> BodyStreamBuffer::releaseHandle(ExecutionCon
text* executionContext) | 149 PassOwnPtr<FetchDataConsumerHandle> BodyStreamBuffer::releaseHandle() |
122 { | 150 { |
123 ASSERT(!isStreamLocked()); | 151 ASSERT(!isStreamLocked()); |
124 ASSERT(!isStreamDisturbed()); | 152 ASSERT(!isStreamDisturbed()); |
125 m_reader = nullptr; | 153 lockAndDisturb(); |
126 m_stream->setIsDisturbed(); | |
127 NonThrowableExceptionState exceptionState; | |
128 m_stream->getBytesReader(executionContext, exceptionState); | |
129 | 154 |
130 if (isStreamClosed()) | 155 if (isStreamClosed()) |
131 return createFetchDataConsumerHandleFromWebHandle(createDoneDataConsumer
Handle()); | 156 return createFetchDataConsumerHandleFromWebHandle(createDoneDataConsumer
Handle()); |
132 if (isStreamErrored()) | 157 if (isStreamErrored()) |
133 return createFetchDataConsumerHandleFromWebHandle(createUnexpectedErrorD
ataConsumerHandle()); | 158 return createFetchDataConsumerHandleFromWebHandle(createUnexpectedErrorD
ataConsumerHandle()); |
134 | 159 |
135 ASSERT(m_handle); | 160 ASSERT(m_handle); |
136 OwnPtr<FetchDataConsumerHandle> handle = m_handle.release(); | 161 OwnPtr<FetchDataConsumerHandle> handle = m_handle.release(); |
137 close(); | 162 close(); |
138 return handle.release(); | 163 return handle.release(); |
139 } | 164 } |
140 | 165 |
141 void BodyStreamBuffer::startLoading(ExecutionContext* executionContext, FetchDat
aLoader* loader, FetchDataLoader::Client* client) | 166 void BodyStreamBuffer::startLoading(FetchDataLoader* loader, FetchDataLoader::Cl
ient* client) |
142 { | 167 { |
143 ASSERT(!m_loader); | 168 ASSERT(!m_loader); |
144 OwnPtr<FetchDataConsumerHandle> handle = releaseHandle(executionContext); | 169 ASSERT(m_scriptState->contextIsValid()); |
| 170 OwnPtr<FetchDataConsumerHandle> handle = releaseHandle(); |
145 m_loader = loader; | 171 m_loader = loader; |
146 loader->start(handle.get(), new LoaderClient(executionContext, this, client)
); | 172 loader->start(handle.get(), new LoaderClient(m_scriptState->getExecutionCont
ext(), this, client)); |
147 } | |
148 | |
149 bool BodyStreamBuffer::hasPendingActivity() const | |
150 { | |
151 return m_loader || (isStreamLocked() && isStreamReadable()); | |
152 } | |
153 | |
154 void BodyStreamBuffer::stop() | |
155 { | |
156 m_reader = nullptr; | |
157 m_handle = nullptr; | |
158 } | 173 } |
159 | 174 |
160 void BodyStreamBuffer::pullSource() | 175 void BodyStreamBuffer::pullSource() |
161 { | 176 { |
162 ASSERT(!m_streamNeedsMore); | 177 ASSERT(!m_streamNeedsMore); |
163 m_streamNeedsMore = true; | 178 m_streamNeedsMore = true; |
164 processData(); | 179 processData(); |
165 } | 180 } |
166 | 181 |
167 ScriptPromise BodyStreamBuffer::cancelSource(ScriptState* scriptState, ScriptVal
ue) | 182 ScriptPromise BodyStreamBuffer::cancelSource(ScriptState* scriptState, ScriptVal
ue) |
168 { | 183 { |
| 184 ASSERT(scriptState == m_scriptState.get()); |
169 close(); | 185 close(); |
170 return ScriptPromise::castUndefined(scriptState); | 186 return ScriptPromise::castUndefined(scriptState); |
171 } | 187 } |
| 188 |
| 189 ScriptPromise BodyStreamBuffer::pull(ScriptState* scriptState) |
| 190 { |
| 191 ASSERT(!m_streamNeedsMore); |
| 192 ASSERT(scriptState == m_scriptState.get()); |
| 193 m_streamNeedsMore = true; |
| 194 processData(); |
| 195 return ScriptPromise::castUndefined(scriptState); |
| 196 } |
| 197 |
| 198 ScriptPromise BodyStreamBuffer::cancel(ScriptState* scriptState, ScriptValue rea
son) |
| 199 { |
| 200 ASSERT(scriptState == m_scriptState.get()); |
| 201 close(); |
| 202 return ScriptPromise::castUndefined(scriptState); |
| 203 } |
172 | 204 |
173 void BodyStreamBuffer::didGetReadable() | 205 void BodyStreamBuffer::didGetReadable() |
174 { | 206 { |
175 if (!m_reader) | 207 if (!m_reader) |
176 return; | 208 return; |
177 | 209 |
178 if (!m_streamNeedsMore) { | 210 if (!m_streamNeedsMore) { |
179 // Perform zero-length read to call close()/error() early. | 211 // Perform zero-length read to call close()/error() early. |
180 size_t readSize; | 212 size_t readSize; |
181 WebDataConsumerHandle::Result result = m_reader->read(nullptr, 0, WebDat
aConsumerHandle::FlagNone, &readSize); | 213 WebDataConsumerHandle::Result result = m_reader->read(nullptr, 0, WebDat
aConsumerHandle::FlagNone, &readSize); |
182 switch (result) { | 214 switch (result) { |
183 case WebDataConsumerHandle::Ok: | 215 case WebDataConsumerHandle::Ok: |
184 case WebDataConsumerHandle::ShouldWait: | 216 case WebDataConsumerHandle::ShouldWait: |
185 return; | 217 return; |
186 case WebDataConsumerHandle::Done: | 218 case WebDataConsumerHandle::Done: |
187 close(); | 219 close(); |
188 return; | 220 return; |
189 case WebDataConsumerHandle::Busy: | 221 case WebDataConsumerHandle::Busy: |
190 case WebDataConsumerHandle::ResourceExhausted: | 222 case WebDataConsumerHandle::ResourceExhausted: |
191 case WebDataConsumerHandle::UnexpectedError: | 223 case WebDataConsumerHandle::UnexpectedError: |
192 error(); | 224 error(); |
193 return; | 225 return; |
194 } | 226 } |
195 return; | 227 return; |
196 } | 228 } |
197 processData(); | 229 processData(); |
198 } | 230 } |
199 | 231 |
200 bool BodyStreamBuffer::isStreamReadable() const | 232 bool BodyStreamBuffer::hasPendingActivity() const |
201 { | 233 { |
| 234 if (m_loader) |
| 235 return true; |
| 236 if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) |
| 237 return UnderlyingSourceBase::hasPendingActivity(); |
| 238 |
| 239 return m_stream->stateInternal() == ReadableStream::Readable && m_stream->is
Locked(); |
| 240 } |
| 241 |
| 242 void BodyStreamBuffer::stop() |
| 243 { |
| 244 m_reader = nullptr; |
| 245 m_handle = nullptr; |
| 246 UnderlyingSourceBase::stop(); |
| 247 } |
| 248 |
| 249 bool BodyStreamBuffer::isStreamReadable() |
| 250 { |
| 251 if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { |
| 252 ScriptState::Scope scope(m_scriptState.get()); |
| 253 return ReadableStreamOperations::isReadable(m_scriptState.get(), stream(
)); |
| 254 } |
202 return m_stream->stateInternal() == ReadableStream::Readable; | 255 return m_stream->stateInternal() == ReadableStream::Readable; |
203 } | 256 } |
204 | 257 |
205 bool BodyStreamBuffer::isStreamClosed() const | 258 bool BodyStreamBuffer::isStreamClosed() |
206 { | 259 { |
| 260 if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { |
| 261 ScriptState::Scope scope(m_scriptState.get()); |
| 262 return ReadableStreamOperations::isClosed(m_scriptState.get(), stream())
; |
| 263 } |
207 return m_stream->stateInternal() == ReadableStream::Closed; | 264 return m_stream->stateInternal() == ReadableStream::Closed; |
208 } | 265 } |
209 | 266 |
210 bool BodyStreamBuffer::isStreamErrored() const | 267 bool BodyStreamBuffer::isStreamErrored() |
211 { | 268 { |
| 269 if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { |
| 270 ScriptState::Scope scope(m_scriptState.get()); |
| 271 return ReadableStreamOperations::isErrored(m_scriptState.get(), stream()
); |
| 272 } |
212 return m_stream->stateInternal() == ReadableStream::Errored; | 273 return m_stream->stateInternal() == ReadableStream::Errored; |
213 } | 274 } |
214 | 275 |
215 bool BodyStreamBuffer::isStreamLocked() const | 276 bool BodyStreamBuffer::isStreamLocked() |
216 { | 277 { |
| 278 if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { |
| 279 ScriptState::Scope scope(m_scriptState.get()); |
| 280 return ReadableStreamOperations::isLocked(m_scriptState.get(), stream())
; |
| 281 } |
217 return m_stream->isLocked(); | 282 return m_stream->isLocked(); |
218 } | 283 } |
219 | 284 |
220 bool BodyStreamBuffer::isStreamDisturbed() const | 285 bool BodyStreamBuffer::isStreamDisturbed() |
221 { | 286 { |
| 287 if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { |
| 288 ScriptState::Scope scope(m_scriptState.get()); |
| 289 return ReadableStreamOperations::isDisturbed(m_scriptState.get(), stream
()); |
| 290 } |
222 return m_stream->isDisturbed(); | 291 return m_stream->isDisturbed(); |
223 } | 292 } |
224 | 293 |
| 294 void BodyStreamBuffer::setDisturbed() |
| 295 { |
| 296 if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { |
| 297 ScriptState::Scope scope(m_scriptState.get()); |
| 298 ReadableStreamOperations::setDisturbed(m_scriptState.get(), stream()); |
| 299 } else { |
| 300 m_stream->setIsDisturbed(); |
| 301 } |
| 302 } |
| 303 |
| 304 void BodyStreamBuffer::lockAndDisturb() |
| 305 { |
| 306 if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { |
| 307 ScriptState::Scope scope(m_scriptState.get()); |
| 308 NonThrowableExceptionState exceptionState; |
| 309 ReadableStreamOperations::getReader(m_scriptState.get(), stream(), excep
tionState); |
| 310 ReadableStreamOperations::setDisturbed(m_scriptState.get(), stream()); |
| 311 } else { |
| 312 NonThrowableExceptionState exceptionState; |
| 313 m_stream->getBytesReader(m_scriptState->getExecutionContext(), exception
State); |
| 314 m_stream->setIsDisturbed(); |
| 315 } |
| 316 } |
| 317 |
225 void BodyStreamBuffer::close() | 318 void BodyStreamBuffer::close() |
226 { | 319 { |
| 320 if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) |
| 321 controller()->close(); |
| 322 else |
| 323 m_stream->close(); |
227 m_reader = nullptr; | 324 m_reader = nullptr; |
228 m_stream->close(); | 325 m_handle = nullptr; |
229 m_handle.clear(); | |
230 } | 326 } |
231 | 327 |
232 void BodyStreamBuffer::error() | 328 void BodyStreamBuffer::error() |
233 { | 329 { |
| 330 if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) |
| 331 controller()->error(DOMException::create(NetworkError, "network error"))
; |
| 332 else |
| 333 m_stream->error(DOMException::create(NetworkError, "network error")); |
234 m_reader = nullptr; | 334 m_reader = nullptr; |
235 m_stream->error(DOMException::create(NetworkError, "network error")); | 335 m_handle = nullptr; |
236 m_handle.clear(); | |
237 } | 336 } |
238 | 337 |
239 void BodyStreamBuffer::processData() | 338 void BodyStreamBuffer::processData() |
240 { | 339 { |
241 ASSERT(m_reader); | 340 ASSERT(m_reader); |
242 while (m_streamNeedsMore) { | 341 while (m_streamNeedsMore) { |
243 const void* buffer; | 342 const void* buffer; |
244 size_t available; | 343 size_t available; |
245 WebDataConsumerHandle::Result result = m_reader->beginRead(&buffer, WebD
ataConsumerHandle::FlagNone, &available); | 344 WebDataConsumerHandle::Result result = m_reader->beginRead(&buffer, WebD
ataConsumerHandle::FlagNone, &available); |
246 switch (result) { | 345 switch (result) { |
247 case WebDataConsumerHandle::Ok: | 346 case WebDataConsumerHandle::Ok: { |
248 m_streamNeedsMore = m_stream->enqueue(DOMUint8Array::create(static_c
ast<const unsigned char*>(buffer), available)); | 347 DOMUint8Array* array = DOMUint8Array::create(static_cast<const unsig
ned char*>(buffer), available); |
| 348 if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled())
{ |
| 349 controller()->enqueue(array); |
| 350 m_streamNeedsMore = controller()->desiredSize() > 0; |
| 351 } else { |
| 352 m_streamNeedsMore = m_stream->enqueue(array); |
| 353 } |
249 m_reader->endRead(available); | 354 m_reader->endRead(available); |
250 break; | 355 break; |
251 | 356 } |
252 case WebDataConsumerHandle::Done: | 357 case WebDataConsumerHandle::Done: |
253 close(); | 358 close(); |
254 return; | 359 return; |
255 | 360 |
256 case WebDataConsumerHandle::ShouldWait: | 361 case WebDataConsumerHandle::ShouldWait: |
257 return; | 362 return; |
258 | 363 |
259 case WebDataConsumerHandle::Busy: | 364 case WebDataConsumerHandle::Busy: |
260 case WebDataConsumerHandle::ResourceExhausted: | 365 case WebDataConsumerHandle::ResourceExhausted: |
261 case WebDataConsumerHandle::UnexpectedError: | 366 case WebDataConsumerHandle::UnexpectedError: |
(...skipping 11 matching lines...) Expand all Loading... |
273 | 378 |
274 void BodyStreamBuffer::stopLoading() | 379 void BodyStreamBuffer::stopLoading() |
275 { | 380 { |
276 if (!m_loader) | 381 if (!m_loader) |
277 return; | 382 return; |
278 m_loader->cancel(); | 383 m_loader->cancel(); |
279 m_loader = nullptr; | 384 m_loader = nullptr; |
280 } | 385 } |
281 | 386 |
282 } // namespace blink | 387 } // namespace blink |
OLD | NEW |