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

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

Powered by Google App Engine
This is Rietveld 408576698