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

Side by Side Diff: third_party/WebKit/Source/modules/fetch/Body.cpp

Issue 1899873006: Make Response::body return v8-extra based stream behind flag (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@notify-locked-released
Patch Set: Created 4 years, 8 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
OLDNEW
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/Body.h" 5 #include "modules/fetch/Body.h"
6 6
7 #include "bindings/core/v8/ExceptionState.h"
8 #include "bindings/core/v8/ScriptPromiseResolver.h" 7 #include "bindings/core/v8/ScriptPromiseResolver.h"
9 #include "bindings/core/v8/ScriptState.h" 8 #include "bindings/core/v8/ScriptState.h"
10 #include "bindings/core/v8/V8ArrayBuffer.h" 9 #include "bindings/core/v8/V8ArrayBuffer.h"
11 #include "bindings/core/v8/V8ThrowException.h" 10 #include "bindings/core/v8/V8ThrowException.h"
12 #include "core/dom/DOMArrayBuffer.h" 11 #include "core/dom/DOMArrayBuffer.h"
13 #include "core/dom/DOMTypedArray.h" 12 #include "core/dom/DOMTypedArray.h"
14 #include "core/dom/ExceptionCode.h" 13 #include "core/dom/ExceptionCode.h"
15 #include "core/fileapi/Blob.h" 14 #include "core/fileapi/Blob.h"
16 #include "core/frame/UseCounter.h" 15 #include "core/frame/UseCounter.h"
17 #include "core/streams/ReadableStreamController.h"
18 #include "core/streams/ReadableStreamOperations.h"
19 #include "core/streams/UnderlyingSourceBase.h"
20 #include "modules/fetch/BodyStreamBuffer.h" 16 #include "modules/fetch/BodyStreamBuffer.h"
21 #include "modules/fetch/FetchDataLoader.h" 17 #include "modules/fetch/FetchDataLoader.h"
22 #include "public/platform/WebDataConsumerHandle.h" 18 #include "public/platform/WebDataConsumerHandle.h"
23 #include "wtf/OwnPtr.h" 19 #include "wtf/OwnPtr.h"
24 #include "wtf/PassRefPtr.h" 20 #include "wtf/PassRefPtr.h"
25 #include "wtf/RefPtr.h" 21 #include "wtf/RefPtr.h"
26 22
27 namespace blink { 23 namespace blink {
28 24
29 namespace { 25 namespace {
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 v8::Local<v8::String> inputString = v8String(isolate, string); 93 v8::Local<v8::String> inputString = v8String(isolate, string);
98 v8::TryCatch trycatch(isolate); 94 v8::TryCatch trycatch(isolate);
99 v8::Local<v8::Value> parsed; 95 v8::Local<v8::Value> parsed;
100 if (v8Call(v8::JSON::Parse(isolate, inputString), parsed, trycatch)) 96 if (v8Call(v8::JSON::Parse(isolate, inputString), parsed, trycatch))
101 resolver()->resolve(parsed); 97 resolver()->resolve(parsed);
102 else 98 else
103 resolver()->reject(trycatch.Exception()); 99 resolver()->reject(trycatch.Exception());
104 } 100 }
105 }; 101 };
106 102
107 class UnderlyingSourceFromDataConsumerHandle final : public UnderlyingSourceBase , public WebDataConsumerHandle::Client {
108 EAGERLY_FINALIZE();
109 DECLARE_EAGER_FINALIZATION_OPERATOR_NEW();
110 public:
111 UnderlyingSourceFromDataConsumerHandle(ScriptState* scriptState, PassOwnPtr< WebDataConsumerHandle> handle)
112 : UnderlyingSourceBase(scriptState)
113 , m_scriptState(scriptState)
114 , m_reader(handle->obtainReader(this))
115 {
116 }
117
118 ScriptPromise pull(ScriptState* scriptState) override
119 {
120 didGetReadable();
121 return ScriptPromise::castUndefined(scriptState);
122 }
123
124 ScriptPromise cancel(ScriptState* scriptState, ScriptValue reason) override
125 {
126 m_reader = nullptr;
127 return ScriptPromise::castUndefined(scriptState);
128 }
129
130 void didGetReadable() override
131 {
132 while (controller()->desiredSize() > 0) {
133 size_t available = 0;
134 const void* buffer = nullptr;
135 WebDataConsumerHandle::Result result = m_reader->beginRead(&buffer, WebDataConsumerHandle::FlagNone, &available);
136 if (result == WebDataConsumerHandle::Ok) {
137 RefPtr<ArrayBuffer> arrayBuffer = ArrayBuffer::create(available, 1);
138 memcpy(arrayBuffer->data(), buffer, available);
139 m_reader->endRead(available);
140 controller()->enqueue(DOMUint8Array::create(arrayBuffer.release( ), 0, available));
141 } else if (result == WebDataConsumerHandle::ShouldWait) {
142 break;
143 } else if (result == WebDataConsumerHandle::Done) {
144 m_reader = nullptr;
145 controller()->close();
146 break;
147 } else {
148 m_reader = nullptr;
149 controller()->error(V8ThrowException::createTypeError(m_scriptSt ate->isolate(), "Network error"));
150 break;
151 }
152 }
153 }
154
155 private:
156 RefPtr<ScriptState> m_scriptState;
157 OwnPtr<WebDataConsumerHandle::Reader> m_reader;
158 };
159
160 } // namespace 103 } // namespace
161 104
162 ScriptPromise Body::arrayBuffer(ScriptState* scriptState) 105 ScriptPromise Body::arrayBuffer(ScriptState* scriptState)
163 { 106 {
164 ScriptPromise promise = rejectInvalidConsumption(scriptState); 107 ScriptPromise promise = rejectInvalidConsumption(scriptState);
165 if (!promise.isEmpty()) 108 if (!promise.isEmpty())
166 return promise; 109 return promise;
167 110
168 // When the main thread sends a V8::TerminateExecution() signal to a worker 111 // When the main thread sends a V8::TerminateExecution() signal to a worker
169 // thread, any V8 API on the worker thread starts returning an empty 112 // thread, any V8 API on the worker thread starts returning an empty
170 // handle. This can happen in this function. To avoid the situation, we 113 // handle. This can happen in this function. To avoid the situation, we
171 // first check the ExecutionContext and return immediately if it's already 114 // first check the ExecutionContext and return immediately if it's already
172 // gone (which means that the V8::TerminateExecution() signal has been sent 115 // gone (which means that the V8::TerminateExecution() signal has been sent
173 // to this worker thread). 116 // to this worker thread).
174 if (!scriptState->getExecutionContext()) 117 if (!scriptState->getExecutionContext())
175 return ScriptPromise(); 118 return ScriptPromise();
176 119
177 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; 120 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
178 promise = resolver->promise(); 121 promise = resolver->promise();
179 if (bodyBuffer()) { 122 if (bodyBuffer()) {
180 bodyBuffer()->startLoading(scriptState->getExecutionContext(), FetchData Loader::createLoaderAsArrayBuffer(), new BodyArrayBufferConsumer(resolver)); 123 bodyBuffer()->startLoading(FetchDataLoader::createLoaderAsArrayBuffer(), new BodyArrayBufferConsumer(resolver));
181 } else { 124 } else {
182 resolver->resolve(DOMArrayBuffer::create(0u, 1)); 125 resolver->resolve(DOMArrayBuffer::create(0u, 1));
183 } 126 }
184 return promise; 127 return promise;
185 } 128 }
186 129
187 ScriptPromise Body::blob(ScriptState* scriptState) 130 ScriptPromise Body::blob(ScriptState* scriptState)
188 { 131 {
189 ScriptPromise promise = rejectInvalidConsumption(scriptState); 132 ScriptPromise promise = rejectInvalidConsumption(scriptState);
190 if (!promise.isEmpty()) 133 if (!promise.isEmpty())
191 return promise; 134 return promise;
192 135
193 // See above comment. 136 // See above comment.
194 if (!scriptState->getExecutionContext()) 137 if (!scriptState->getExecutionContext())
195 return ScriptPromise(); 138 return ScriptPromise();
196 139
197 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; 140 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
198 promise = resolver->promise(); 141 promise = resolver->promise();
199 if (bodyBuffer()) { 142 if (bodyBuffer()) {
200 bodyBuffer()->startLoading(scriptState->getExecutionContext(), FetchData Loader::createLoaderAsBlobHandle(mimeType()), new BodyBlobConsumer(resolver)); 143 bodyBuffer()->startLoading(FetchDataLoader::createLoaderAsBlobHandle(mim eType()), new BodyBlobConsumer(resolver));
201 } else { 144 } else {
202 OwnPtr<BlobData> blobData = BlobData::create(); 145 OwnPtr<BlobData> blobData = BlobData::create();
203 blobData->setContentType(mimeType()); 146 blobData->setContentType(mimeType());
204 resolver->resolve(Blob::create(BlobDataHandle::create(blobData.release() , 0))); 147 resolver->resolve(Blob::create(BlobDataHandle::create(blobData.release() , 0)));
205 } 148 }
206 return promise; 149 return promise;
207 150
208 } 151 }
209 152
210 ScriptPromise Body::json(ScriptState* scriptState) 153 ScriptPromise Body::json(ScriptState* scriptState)
211 { 154 {
212 ScriptPromise promise = rejectInvalidConsumption(scriptState); 155 ScriptPromise promise = rejectInvalidConsumption(scriptState);
213 if (!promise.isEmpty()) 156 if (!promise.isEmpty())
214 return promise; 157 return promise;
215 158
216 // See above comment. 159 // See above comment.
217 if (!scriptState->getExecutionContext()) 160 if (!scriptState->getExecutionContext())
218 return ScriptPromise(); 161 return ScriptPromise();
219 162
220 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; 163 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
221 promise = resolver->promise(); 164 promise = resolver->promise();
222 if (bodyBuffer()) { 165 if (bodyBuffer()) {
223 bodyBuffer()->startLoading(scriptState->getExecutionContext(), FetchData Loader::createLoaderAsString(), new BodyJsonConsumer(resolver)); 166 bodyBuffer()->startLoading(FetchDataLoader::createLoaderAsString(), new BodyJsonConsumer(resolver));
224 } else { 167 } else {
225 resolver->reject(V8ThrowException::createSyntaxError(scriptState->isolat e(), "Unexpected end of input")); 168 resolver->reject(V8ThrowException::createSyntaxError(scriptState->isolat e(), "Unexpected end of input"));
226 } 169 }
227 return promise; 170 return promise;
228 } 171 }
229 172
230 ScriptPromise Body::text(ScriptState* scriptState) 173 ScriptPromise Body::text(ScriptState* scriptState)
231 { 174 {
232 ScriptPromise promise = rejectInvalidConsumption(scriptState); 175 ScriptPromise promise = rejectInvalidConsumption(scriptState);
233 if (!promise.isEmpty()) 176 if (!promise.isEmpty())
234 return promise; 177 return promise;
235 178
236 // See above comment. 179 // See above comment.
237 if (!scriptState->getExecutionContext()) 180 if (!scriptState->getExecutionContext())
238 return ScriptPromise(); 181 return ScriptPromise();
239 182
240 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; 183 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
241 promise = resolver->promise(); 184 promise = resolver->promise();
242 if (bodyBuffer()) { 185 if (bodyBuffer()) {
243 bodyBuffer()->startLoading(scriptState->getExecutionContext(), FetchData Loader::createLoaderAsString(), new BodyTextConsumer(resolver)); 186 bodyBuffer()->startLoading(FetchDataLoader::createLoaderAsString(), new BodyTextConsumer(resolver));
244 } else { 187 } else {
245 resolver->resolve(String()); 188 resolver->resolve(String());
246 } 189 }
247 return promise; 190 return promise;
248 } 191 }
249 192
250 ReadableByteStream* Body::body() 193 ScriptValue Body::bodyWithUseCounter(ScriptState* scriptState)
251 {
252 return bodyBuffer() ? bodyBuffer()->stream() : nullptr;
253 }
254
255 ReadableByteStream* Body::bodyWithUseCounter()
256 { 194 {
257 UseCounter::count(getExecutionContext(), UseCounter::FetchBodyStream); 195 UseCounter::count(getExecutionContext(), UseCounter::FetchBodyStream);
258 return body(); 196 if (!bodyBuffer())
259 } 197 return ScriptValue::createNull(scriptState);
260 198 ScriptValue stream = bodyBuffer()->stream();
261 ScriptValue Body::v8ExtraStreamBody(ScriptState* scriptState) 199 ASSERT(stream.getScriptState() == scriptState);
262 { 200 return stream;
263 if (bodyUsed() || isBodyLocked() || !bodyBuffer())
264 return ScriptValue(scriptState, v8::Undefined(scriptState->isolate()));
265 OwnPtr<FetchDataConsumerHandle> handle = bodyBuffer()->releaseHandle(scriptS tate->getExecutionContext());
266 return ReadableStreamOperations::createReadableStream(scriptState,
267 new UnderlyingSourceFromDataConsumerHandle(scriptState, handle.release() ),
268 ScriptValue(scriptState, v8::Undefined(scriptState->isolate())));
269 } 201 }
270 202
271 bool Body::bodyUsed() 203 bool Body::bodyUsed()
272 { 204 {
273 return bodyBuffer() && bodyBuffer()->isStreamDisturbed(); 205 return bodyBuffer() && bodyBuffer()->isStreamDisturbed();
274 } 206 }
275 207
276 bool Body::isBodyLocked() 208 bool Body::isBodyLocked()
277 { 209 {
278 return bodyBuffer() && bodyBuffer()->isStreamLocked(); 210 return bodyBuffer() && bodyBuffer()->isStreamLocked();
(...skipping 16 matching lines...) Expand all
295 } 227 }
296 228
297 ScriptPromise Body::rejectInvalidConsumption(ScriptState* scriptState) 229 ScriptPromise Body::rejectInvalidConsumption(ScriptState* scriptState)
298 { 230 {
299 if (isBodyLocked() || bodyUsed()) 231 if (isBodyLocked() || bodyUsed())
300 return ScriptPromise::reject(scriptState, V8ThrowException::createTypeEr ror(scriptState->isolate(), "Already read")); 232 return ScriptPromise::reject(scriptState, V8ThrowException::createTypeEr ror(scriptState->isolate(), "Already read"));
301 return ScriptPromise(); 233 return ScriptPromise();
302 } 234 }
303 235
304 } // namespace blink 236 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698