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

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 <algorithm>
26 #include <string.h>
27 #include <v8.h>
28
29 namespace blink {
30
31 using Result = WebDataConsumerHandle::Result;
32 using Flags = WebDataConsumerHandle::Flags;
33
34 // This context is not yet thread-safe.
35 class ReadableStreamDataConsumerHandle::Context final : public RefCounted<Contex t> {
36 WTF_MAKE_NONCOPYABLE(Context);
37 public:
38 class OnFulfilled final : public ScriptFunction {
39 public:
40 static v8::Local<v8::Function> createFunction(ScriptState* scriptState, PassRefPtr<Context> context)
41 {
42 return (new OnFulfilled(scriptState, context))->bindToV8Function();
43 }
44
45 ScriptValue call(ScriptValue v) override
46 {
47 bool done;
48 v8::Local<v8::Value> value;
49 v8::Local<v8::Value> item = v.v8Value();
50 if (!item->IsObject() || !v8Call(v8UnpackIteratorResult(v.scriptStat e(), item.As<v8::Object>(), &done), value)) {
domenic 2015/12/14 02:18:02 Could these be asserts instead? They should never
yhirano 2015/12/14 03:42:54 Done.
51 m_context->onRejected();
52 return ScriptValue();
53 }
54 if (done) {
55 m_context->onReadDone();
56 return v;
57 }
58 if (!V8Uint8Array::hasInstance(value, v.isolate())) {
59 m_context->onRejected();
60 return ScriptValue();
61 }
62 m_context->onRead(V8Uint8Array::toImpl(value.As<v8::Object>()));
63 return v;
64 }
65
66 private:
67 OnFulfilled(ScriptState* scriptState, PassRefPtr<Context> context)
68 : ScriptFunction(scriptState), m_context(context) {}
69
70 RefPtr<Context> m_context;
71 };
72
73 class OnRejected final : public ScriptFunction {
74 public:
75 static v8::Local<v8::Function> createFunction(ScriptState* scriptState, PassRefPtr<Context> context)
76 {
77 return (new OnRejected(scriptState, context))->bindToV8Function();
78 }
79
80 ScriptValue call(ScriptValue v) override
81 {
82 m_context->onRejected();
83 return v;
84 }
85
86 private:
87 OnRejected(ScriptState* scriptState, PassRefPtr<Context> context)
88 : ScriptFunction(scriptState), m_context(context) {}
89
90 RefPtr<Context> m_context;
91 };
92
93 class ReaderImpl final : public FetchDataConsumerHandle::Reader {
94 public:
95 ReaderImpl(PassRefPtr<Context> context, Client* client)
96 : m_context(context)
97 {
98 m_context->attachReader(client);
99 }
100 ~ReaderImpl() override
101 {
102 m_context->detachReader();
103 }
104
105 Result read(void* buffer, size_t size, Flags flags, size_t* readSize) ov erride
106 {
107 *readSize = 0;
108 const void* src = nullptr;
109 size_t available;
110 Result r = beginRead(&src, flags, &available);
111 if (r != WebDataConsumerHandle::Ok)
112 return r;
113 *readSize = std::min(available, size);
114 memcpy(buffer, src, *readSize);
115 return endRead(*readSize);
116 }
117
118 Result beginRead(const void** buffer, Flags, size_t* available) override
119 {
120 return m_context->beginRead(buffer, available);
121 }
122
123 Result endRead(size_t readSize) override
124 {
125 return m_context->endRead(readSize);
126 }
127
128 private:
129 RefPtr<Context> m_context;
130 };
131
132 static PassRefPtr<Context> create(ScriptState* scriptState, v8::Local<v8::Va lue> stream)
133 {
134 return adoptRef(new Context(scriptState, stream));
135 }
136
137 void attachReader(WebDataConsumerHandle::Client* client)
138 {
139 m_client = client;
140 notifyLater();
141 }
142
143 void detachReader()
144 {
145 m_client = nullptr;
146 }
147
148 Result beginRead(const void** buffer, size_t* available)
149 {
150 *buffer = nullptr;
151 *available = 0;
152 if (m_hasError)
153 return WebDataConsumerHandle::UnexpectedError;
154 if (m_isDone)
155 return WebDataConsumerHandle::Done;
156
157 if (m_pendingBuffer) {
158 ASSERT(m_pendingOffset < m_pendingBuffer->length());
159 *buffer = m_pendingBuffer->data() + m_pendingOffset;
160 *available = m_pendingBuffer->length() - m_pendingOffset;
161 return WebDataConsumerHandle::Ok;
162 }
163 ASSERT(!m_reader.isEmpty());
164 m_isInRecursion = true;
165 if (!m_isReading) {
166 m_isReading = true;
167 ScriptState::Scope scope(m_reader.scriptState());
168 V8RecursionScope recursionScope(m_reader.isolate());
169 ReadableStreamOperations::read(m_reader.scriptState(), m_reader.v8Va lue()).then(
170 OnFulfilled::createFunction(m_reader.scriptState(), this),
171 OnRejected::createFunction(m_reader.scriptState(), this));
172 // Note: Microtasks may run here.
173 }
174 m_isInRecursion = false;
175 return WebDataConsumerHandle::ShouldWait;
176 }
177
178 Result endRead(size_t readSize)
179 {
180 ASSERT(m_pendingBuffer);
181 ASSERT(m_pendingOffset + readSize <= m_pendingBuffer->length());
182 m_pendingOffset += readSize;
183 if (m_pendingOffset == m_pendingBuffer->length()) {
184 m_pendingBuffer = nullptr;
185 m_pendingOffset = 0;
186 }
187 return WebDataConsumerHandle::Ok;
188 }
189
190 void onRead(DOMUint8Array* buffer)
191 {
192 ASSERT(m_isReading);
193 ASSERT(buffer);
194 ASSERT(!m_pendingBuffer);
195 ASSERT(!m_pendingOffset);
196 m_isReading = false;
197 m_pendingBuffer = buffer;
198 notify();
199 }
200
201 void onReadDone()
202 {
203 ASSERT(m_isReading);
204 ASSERT(!m_pendingBuffer);
205 m_isReading = false;
206 m_isDone = true;
207 m_reader.clear();
208 notify();
209 }
210
211 void onRejected()
212 {
213 ASSERT(m_isReading);
214 ASSERT(!m_pendingBuffer);
215 m_hasError = true;
216 m_isReading = false;
217 m_reader.clear();
218 notify();
219 }
220
221 void notify()
222 {
223 if (!m_client)
224 return;
225 if (m_isInRecursion) {
226 notifyLater();
227 return;
228 }
229 m_client->didGetReadable();
230 }
231
232 void notifyLater()
233 {
234 ASSERT(m_client);
235 Platform::current()->currentThread()->taskRunner()->postTask(BLINK_FROM_ HERE, bind(&Context::notify, this));
236 }
237
238 private:
239 Context(ScriptState* scriptState, v8::Local<v8::Value> stream)
domenic 2015/12/14 02:18:02 Context was a confusing name for me because it is
yhirano 2015/12/14 03:42:54 Done.
240 : m_client(nullptr)
241 , m_pendingOffset(0)
242 , m_isReading(false)
243 , m_isDone(false)
244 , m_hasError(false)
245 , m_isInRecursion(false)
246 {
247 if (!ReadableStreamOperations::isLocked(scriptState, stream)) {
248 // Here the stream implementation must not throw an exception.
249 NonThrowableExceptionState es;
250 m_reader = ReadableStreamOperations::getReader(scriptState, stream, es);
251 }
252 m_hasError = m_reader.isEmpty();
253 }
254
255 // This ScriptValue is leaky because it stores a strong reference to a
256 // JavaScript object.
257 // TODO(yhirano): Fix it.
258 //
259 // Holding a ScriptValue here is safe in terms of cross-world wrapper
260 // leakage because we read only Uint8Array chunks from the reader.
261 ScriptValue m_reader;
262 WebDataConsumerHandle::Client* m_client;
263 RefPtr<DOMUint8Array> m_pendingBuffer;
264 size_t m_pendingOffset;
265 bool m_isReading;
266 bool m_isDone;
267 bool m_hasError;
268 bool m_isInRecursion;
269 };
270
271 ReadableStreamDataConsumerHandle::ReadableStreamDataConsumerHandle(ScriptState* scriptState, v8::Local<v8::Value> stream)
272 : m_context(Context::create(scriptState, stream))
273 {
274 }
275 ReadableStreamDataConsumerHandle::~ReadableStreamDataConsumerHandle() = default;
276
277 FetchDataConsumerHandle::Reader* ReadableStreamDataConsumerHandle::obtainReaderI nternal(Client* client)
278 {
279 return new Context::ReaderImpl(m_context, client);
280 }
281
282 } // namespace blink
283
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698