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

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

Issue 1506023003: Response construction with a ReadableStream (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years 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
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "modules/fetch/ReadableStreamDataConsumerHandle.h"
7
8 #include "bindings/core/v8/ExceptionState.h"
9 #include "bindings/core/v8/ReadableStreamOperations.h"
10 #include "bindings/core/v8/ScriptFunction.h"
11 #include "bindings/core/v8/ScriptState.h"
12 #include "bindings/core/v8/ScriptValue.h"
13 #include "bindings/core/v8/V8BindingMacros.h"
14 #include "bindings/core/v8/V8IteratorResultValue.h"
15 #include "bindings/core/v8/V8RecursionScope.h"
16 #include "bindings/core/v8/V8Uint8Array.h"
17 #include "core/dom/DOMTypedArray.h"
18 #include "public/platform/Platform.h"
19 #include "public/platform/WebTaskRunner.h"
20 #include "public/platform/WebThread.h"
21 #include "public/platform/WebTraceLocation.h"
22 #include "wtf/Assertions.h"
23 #include "wtf/Functional.h"
24 #include "wtf/RefCounted.h"
25 #include "wtf/WeakPtr.h"
26 #include <algorithm>
27 #include <string.h>
28 #include <v8.h>
29
30 namespace blink {
31
32 using Result = WebDataConsumerHandle::Result;
33 using Flags = WebDataConsumerHandle::Flags;
34
35 // This context is not yet thread-safe.
36 class ReadableStreamDataConsumerHandle::ReadingContext final : public RefCounted <ReadingContext> {
37 WTF_MAKE_NONCOPYABLE(ReadingContext);
38 public:
39 class OnFulfilled final : public ScriptFunction {
40 public:
41 static v8::Local<v8::Function> createFunction(ScriptState* scriptState, WeakPtr<ReadingContext> context)
42 {
43 return (new OnFulfilled(scriptState, context))->bindToV8Function();
44 }
45
46 ScriptValue call(ScriptValue v) override
47 {
48 RefPtr<ReadingContext> readingContext(m_readingContext.get());
49 if (!readingContext)
50 return v;
51 bool done;
52 v8::Local<v8::Value> item = v.v8Value();
53 ASSERT(item->IsObject());
54 v8::Local<v8::Value> value = v8CallOrCrash(v8UnpackIteratorResult(v. scriptState(), item.As<v8::Object>(), &done));
55 if (done) {
56 readingContext->onReadDone();
57 return v;
58 }
59 if (!V8Uint8Array::hasInstance(value, v.isolate())) {
60 readingContext->onRejected();
61 return ScriptValue();
62 }
63 readingContext->onRead(V8Uint8Array::toImpl(value.As<v8::Object>())) ;
64 return v;
65 }
66
67 private:
68 OnFulfilled(ScriptState* scriptState, WeakPtr<ReadingContext> context)
69 : ScriptFunction(scriptState), m_readingContext(context) {}
70
71 WeakPtr<ReadingContext> m_readingContext;
72 };
73
74 class OnRejected final : public ScriptFunction {
75 public:
76 static v8::Local<v8::Function> createFunction(ScriptState* scriptState, WeakPtr<ReadingContext> context)
77 {
78 return (new OnRejected(scriptState, context))->bindToV8Function();
79 }
80
81 ScriptValue call(ScriptValue v) override
82 {
83 RefPtr<ReadingContext> readingContext(m_readingContext.get());
84 if (!readingContext)
85 return v;
86 readingContext->onRejected();
87 return v;
88 }
89
90 private:
91 OnRejected(ScriptState* scriptState, WeakPtr<ReadingContext> context)
92 : ScriptFunction(scriptState), m_readingContext(context) {}
93
94 WeakPtr<ReadingContext> m_readingContext;
95 };
96
97 class ReaderImpl final : public FetchDataConsumerHandle::Reader {
98 public:
99 ReaderImpl(PassRefPtr<ReadingContext> context, Client* client)
100 : m_readingContext(context)
101 {
102 m_readingContext->attachReader(client);
103 }
104 ~ReaderImpl() override
105 {
106 m_readingContext->detachReader();
107 }
108
109 Result read(void* buffer, size_t size, Flags flags, size_t* readSize) ov erride
110 {
111 *readSize = 0;
112 const void* src = nullptr;
113 size_t available;
114 Result r = beginRead(&src, flags, &available);
115 if (r != WebDataConsumerHandle::Ok)
116 return r;
117 *readSize = std::min(available, size);
118 memcpy(buffer, src, *readSize);
119 return endRead(*readSize);
120 }
121
122 Result beginRead(const void** buffer, Flags, size_t* available) override
123 {
124 return m_readingContext->beginRead(buffer, available);
125 }
126
127 Result endRead(size_t readSize) override
128 {
129 return m_readingContext->endRead(readSize);
130 }
131
132 private:
133 RefPtr<ReadingContext> m_readingContext;
134 };
135
136 static PassRefPtr<ReadingContext> create(ScriptState* scriptState, v8::Local <v8::Value> stream)
137 {
138 return adoptRef(new ReadingContext(scriptState, stream));
139 }
140
141 void attachReader(WebDataConsumerHandle::Client* client)
142 {
143 m_client = client;
144 notifyLater();
145 }
146
147 void detachReader()
148 {
149 m_client = nullptr;
150 }
151
152 Result beginRead(const void** buffer, size_t* available)
153 {
154 *buffer = nullptr;
155 *available = 0;
156 if (m_hasError)
157 return WebDataConsumerHandle::UnexpectedError;
158 if (m_isDone)
159 return WebDataConsumerHandle::Done;
160
161 if (m_pendingBuffer) {
162 ASSERT(m_pendingOffset < m_pendingBuffer->length());
163 *buffer = m_pendingBuffer->data() + m_pendingOffset;
164 *available = m_pendingBuffer->length() - m_pendingOffset;
165 return WebDataConsumerHandle::Ok;
166 }
167 ASSERT(!m_reader.isEmpty());
168 m_isInRecursion = true;
169 if (!m_isReading) {
170 m_isReading = true;
171 ScriptState::Scope scope(m_reader.scriptState());
172 V8RecursionScope recursionScope(m_reader.isolate());
173 ReadableStreamOperations::read(m_reader.scriptState(), m_reader.v8Va lue()).then(
174 OnFulfilled::createFunction(m_reader.scriptState(), m_weakPtrFac tory.createWeakPtr()),
175 OnRejected::createFunction(m_reader.scriptState(), m_weakPtrFact ory.createWeakPtr()));
176 // Note: Microtasks may run here.
177 }
178 m_isInRecursion = false;
179 return WebDataConsumerHandle::ShouldWait;
180 }
181
182 Result endRead(size_t readSize)
183 {
184 ASSERT(m_pendingBuffer);
185 ASSERT(m_pendingOffset + readSize <= m_pendingBuffer->length());
186 m_pendingOffset += readSize;
187 if (m_pendingOffset == m_pendingBuffer->length()) {
188 m_pendingBuffer = nullptr;
189 m_pendingOffset = 0;
190 }
191 return WebDataConsumerHandle::Ok;
192 }
193
194 void onRead(DOMUint8Array* buffer)
195 {
196 ASSERT(m_isReading);
197 ASSERT(buffer);
198 ASSERT(!m_pendingBuffer);
199 ASSERT(!m_pendingOffset);
200 m_isReading = false;
201 m_pendingBuffer = buffer;
202 notify();
203 }
204
205 void onReadDone()
206 {
207 ASSERT(m_isReading);
208 ASSERT(!m_pendingBuffer);
209 m_isReading = false;
210 m_isDone = true;
211 m_reader.clear();
212 notify();
213 }
214
215 void onRejected()
216 {
217 ASSERT(m_isReading);
218 ASSERT(!m_pendingBuffer);
219 m_hasError = true;
220 m_isReading = false;
221 m_reader.clear();
222 notify();
223 }
224
225 void notify()
226 {
227 if (!m_client)
228 return;
229 if (m_isInRecursion) {
230 notifyLater();
231 return;
232 }
233 m_client->didGetReadable();
234 }
235
236 void notifyLater()
237 {
238 ASSERT(m_client);
239 Platform::current()->currentThread()->taskRunner()->postTask(BLINK_FROM_ HERE, bind(&ReadingContext::notify, PassRefPtr<ReadingContext>(this)));
240 }
241
242 private:
243 ReadingContext(ScriptState* scriptState, v8::Local<v8::Value> stream)
244 : m_client(nullptr)
245 , m_weakPtrFactory(this)
246 , m_pendingOffset(0)
247 , m_isReading(false)
248 , m_isDone(false)
249 , m_hasError(false)
250 , m_isInRecursion(false)
251 {
252 if (!ReadableStreamOperations::isLocked(scriptState, stream)) {
253 // Here the stream implementation must not throw an exception.
254 NonThrowableExceptionState es;
255 m_reader = ReadableStreamOperations::getReader(scriptState, stream, es);
256 }
257 m_hasError = m_reader.isEmpty();
258 }
259
260 // This ScriptValue is leaky because it stores a strong reference to a
261 // JavaScript object.
262 // TODO(yhirano): Fix it.
263 //
264 // Holding a ScriptValue here is safe in terms of cross-world wrapper
265 // leakage because we read only Uint8Array chunks from the reader.
266 ScriptValue m_reader;
267 WebDataConsumerHandle::Client* m_client;
268 RefPtr<DOMUint8Array> m_pendingBuffer;
269 WeakPtrFactory<ReadingContext> m_weakPtrFactory;
270 size_t m_pendingOffset;
271 bool m_isReading;
272 bool m_isDone;
273 bool m_hasError;
274 bool m_isInRecursion;
275 };
276
277 ReadableStreamDataConsumerHandle::ReadableStreamDataConsumerHandle(ScriptState* scriptState, v8::Local<v8::Value> stream)
278 : m_readingContext(ReadingContext::create(scriptState, stream))
279 {
280 }
281 ReadableStreamDataConsumerHandle::~ReadableStreamDataConsumerHandle() = default;
282
283 FetchDataConsumerHandle::Reader* ReadableStreamDataConsumerHandle::obtainReaderI nternal(Client* client)
284 {
285 return new ReadingContext::ReaderImpl(m_readingContext, client);
286 }
287
288 } // namespace blink
289
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698