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

Side by Side Diff: Source/modules/serviceworkers/Body.cpp

Issue 795323003: Move Fetch API releted code to modules/fetch. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 6 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
« no previous file with comments | « Source/modules/serviceworkers/Body.h ('k') | Source/modules/serviceworkers/Body.idl » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "modules/serviceworkers/Body.h"
7
8 #include "bindings/core/v8/ExceptionState.h"
9 #include "bindings/core/v8/ScriptPromiseResolver.h"
10 #include "bindings/core/v8/ScriptState.h"
11 #include "bindings/core/v8/V8ArrayBuffer.h"
12 #include "bindings/core/v8/V8ThrowException.h"
13 #include "core/dom/DOMArrayBuffer.h"
14 #include "core/fileapi/Blob.h"
15 #include "core/fileapi/FileReaderLoader.h"
16 #include "core/fileapi/FileReaderLoaderClient.h"
17 #include "core/streams/UnderlyingSource.h"
18 #include "modules/serviceworkers/BodyStreamBuffer.h"
19
20 namespace blink {
21
22 class Body::BlobHandleReceiver final : public BodyStreamBuffer::BlobHandleCreato rClient {
23 public:
24 explicit BlobHandleReceiver(Body* body)
25 : m_body(body)
26 {
27 }
28 void didCreateBlobHandle(PassRefPtr<BlobDataHandle> handle) override
29 {
30 ASSERT(m_body);
31 m_body->readAsyncFromBlob(handle);
32 m_body = nullptr;
33 }
34 void didFail(PassRefPtrWillBeRawPtr<DOMException> exception) override
35 {
36 ASSERT(m_body);
37 m_body->didBlobHandleReceiveError(exception);
38 m_body = nullptr;
39 }
40 void trace(Visitor* visitor) override
41 {
42 BodyStreamBuffer::BlobHandleCreatorClient::trace(visitor);
43 visitor->trace(m_body);
44 }
45 private:
46 Member<Body> m_body;
47 };
48
49 class Body::ReadableStreamSource : public GarbageCollectedFinalized<ReadableStre amSource>, public UnderlyingSource {
50 USING_GARBAGE_COLLECTED_MIXIN(ReadableStreamSource);
51 public:
52 ReadableStreamSource(Body* body) : m_body(body) { }
53 ~ReadableStreamSource() override { }
54 void pullSource() override { m_body->pullSource(); }
55
56 ScriptPromise cancelSource(ScriptState* scriptState, ScriptValue reason) ove rride
57 {
58 return ScriptPromise();
59 }
60
61 void trace(Visitor* visitor) override
62 {
63 visitor->trace(m_body);
64 UnderlyingSource::trace(visitor);
65 }
66
67 private:
68 Member<Body> m_body;
69 };
70
71 void Body::pullSource()
72 {
73 if (!m_streamAccessed) {
74 // We do not download data unless the user explicitly uses the
75 // ReadableStream object in order to avoid performance regression,
76 // because currently Chrome cannot handle Streams efficiently
77 // especially with ServiceWorker or Blob.
78 return;
79 }
80 if (m_bodyUsed) {
81 m_stream->error(DOMException::create(InvalidStateError, "The stream is l ocked."));
82 return;
83 }
84 ASSERT(!m_loader);
85 if (buffer()) {
86 // If the body has a body buffer, we read all data from the buffer and
87 // create a blob and then put the data from the blob to |m_stream|.
88 // FIXME: Put the data directry from the buffer.
89 buffer()->readAllAndCreateBlobHandle(contentTypeForBuffer(), new BlobHan dleReceiver(this));
90 return;
91 }
92 RefPtr<BlobDataHandle> blobHandle = blobDataHandle();
93 if (!blobHandle.get()) {
94 blobHandle = BlobDataHandle::create(BlobData::create(), 0);
95 }
96 readAsyncFromBlob(blobHandle);
97 }
98
99 ScriptPromise Body::readAsync(ScriptState* scriptState, ResponseType type)
100 {
101 if (m_bodyUsed)
102 return ScriptPromise::reject(scriptState, V8ThrowException::createTypeEr ror(scriptState->isolate(), "Already read"));
103
104 // When the main thread sends a V8::TerminateExecution() signal to a worker
105 // thread, any V8 API on the worker thread starts returning an empty
106 // handle. This can happen in Body::readAsync. To avoid the situation, we
107 // first check the ExecutionContext and return immediately if it's already
108 // gone (which means that the V8::TerminateExecution() signal has been sent
109 // to this worker thread).
110 ExecutionContext* executionContext = scriptState->executionContext();
111 if (!executionContext)
112 return ScriptPromise();
113
114 m_bodyUsed = true;
115 m_responseType = type;
116
117 ASSERT(!m_resolver);
118 m_resolver = ScriptPromiseResolver::create(scriptState);
119 ScriptPromise promise = m_resolver->promise();
120
121 if (m_streamAccessed) {
122 // 'body' attribute was accessed and the stream source started pulling.
123 switch (m_stream->state()) {
124 case ReadableStream::Readable:
125 readAllFromStream(scriptState);
126 return promise;
127 case ReadableStream::Waiting:
128 // m_loader is working and m_resolver will be resolved when it
129 // ends.
130 return promise;
131 case ReadableStream::Closed:
132 case ReadableStream::Errored:
133 m_resolver->resolve(m_stream->closed(scriptState).v8Value());
134 return promise;
135 break;
136 }
137 ASSERT_NOT_REACHED();
138 return promise;
139 }
140
141 if (buffer()) {
142 buffer()->readAllAndCreateBlobHandle(contentTypeForBuffer(), new BlobHan dleReceiver(this));
143 return promise;
144 }
145 readAsyncFromBlob(blobDataHandle());
146 return promise;
147 }
148
149 void Body::readAsyncFromBlob(PassRefPtr<BlobDataHandle> handle)
150 {
151 if (m_streamAccessed) {
152 FileReaderLoader::ReadType readType = FileReaderLoader::ReadAsArrayBuffe r;
153 m_loader = adoptPtr(new FileReaderLoader(readType, this));
154 m_loader->start(executionContext(), handle);
155 return;
156 }
157 FileReaderLoader::ReadType readType = FileReaderLoader::ReadAsText;
158 RefPtr<BlobDataHandle> blobHandle = handle;
159 if (!blobHandle.get()) {
160 blobHandle = BlobDataHandle::create(BlobData::create(), 0);
161 }
162 switch (m_responseType) {
163 case ResponseAsArrayBuffer:
164 readType = FileReaderLoader::ReadAsArrayBuffer;
165 break;
166 case ResponseAsBlob:
167 if (blobHandle->size() != kuint64max) {
168 // If the size of |blobHandle| is set correctly, creates Blob from
169 // it.
170 m_resolver->resolve(Blob::create(blobHandle));
171 m_resolver.clear();
172 return;
173 }
174 // If the size is not set, read as ArrayBuffer and create a new blob to
175 // get the size.
176 // FIXME: This workaround is not good for performance.
177 // When we will stop using Blob as a base system of Body to support
178 // stream, this problem should be solved.
179 readType = FileReaderLoader::ReadAsArrayBuffer;
180 break;
181 case ResponseAsFormData:
182 // FIXME: Implement this.
183 ASSERT_NOT_REACHED();
184 break;
185 case ResponseAsJSON:
186 case ResponseAsText:
187 break;
188 default:
189 ASSERT_NOT_REACHED();
190 }
191
192 m_loader = adoptPtr(new FileReaderLoader(readType, this));
193 m_loader->start(m_resolver->scriptState()->executionContext(), blobHandle);
194
195 return;
196 }
197
198 void Body::readAllFromStream(ScriptState* scriptState)
199 {
200 // With the current loading mechanism, the data is loaded atomically.
201 ASSERT(m_stream->isDraining());
202 TrackExceptionState es;
203 // FIXME: Implement and use another |read| method that doesn't
204 // need an exception state and V8ArrayBuffer.
205 ScriptValue value = m_stream->read(scriptState, es);
206 ASSERT(!es.hadException());
207 ASSERT(m_stream->state() == ReadableStream::Closed);
208 ASSERT(!value.isEmpty() && V8ArrayBuffer::hasInstance(value.v8Value(), scrip tState->isolate()));
209 DOMArrayBuffer* buffer = V8ArrayBuffer::toImpl(value.v8Value().As<v8::Object >());
210 didFinishLoadingViaStream(buffer);
211 m_resolver.clear();
212 m_stream->close();
213 }
214
215 ScriptPromise Body::arrayBuffer(ScriptState* scriptState)
216 {
217 return readAsync(scriptState, ResponseAsArrayBuffer);
218 }
219
220 ScriptPromise Body::blob(ScriptState* scriptState)
221 {
222 return readAsync(scriptState, ResponseAsBlob);
223 }
224
225 ScriptPromise Body::formData(ScriptState* scriptState)
226 {
227 return readAsync(scriptState, ResponseAsFormData);
228 }
229
230 ScriptPromise Body::json(ScriptState* scriptState)
231 {
232 return readAsync(scriptState, ResponseAsJSON);
233 }
234
235 ScriptPromise Body::text(ScriptState* scriptState)
236 {
237 return readAsync(scriptState, ResponseAsText);
238 }
239
240 ReadableStream* Body::body()
241 {
242 if (!m_streamAccessed) {
243 m_streamAccessed = true;
244 if (m_stream->isPulling()) {
245 // The stream has been pulling, but the source ignored the
246 // instruction because it didn't know the user wanted to use the
247 // ReadableStream interface. Now it knows the user does, so have
248 // the source start pulling.
249 m_streamSource->pullSource();
250 }
251 }
252 return m_stream;
253 }
254
255 bool Body::bodyUsed() const
256 {
257 return m_bodyUsed;
258 }
259
260 void Body::setBodyUsed()
261 {
262 m_bodyUsed = true;
263 }
264
265 bool Body::streamAccessed() const
266 {
267 return m_streamAccessed;
268 }
269
270 void Body::stop()
271 {
272 // Canceling the load will call didFail which will remove the resolver.
273 if (m_loader)
274 m_loader->cancel();
275 }
276
277 bool Body::hasPendingActivity() const
278 {
279 if (m_resolver)
280 return true;
281 if (m_streamAccessed && (m_stream->state() == ReadableStream::Readable || m_ stream->state() == ReadableStream::Waiting))
282 return true;
283 return false;
284 }
285
286 void Body::trace(Visitor* visitor)
287 {
288 visitor->trace(m_stream);
289 visitor->trace(m_streamSource);
290 }
291
292 Body::Body(ExecutionContext* context)
293 : ActiveDOMObject(context)
294 , m_bodyUsed(false)
295 , m_streamAccessed(false)
296 , m_responseType(ResponseType::ResponseUnknown)
297 , m_streamSource(new ReadableStreamSource(this))
298 , m_stream(new ReadableStreamImpl<ReadableStreamChunkTypeTraits<DOMArrayBuff er>>(context, m_streamSource))
299 {
300 m_stream->didSourceStart();
301 }
302
303 Body::Body(const Body& copy_from)
304 : ActiveDOMObject(copy_from.lifecycleContext())
305 , m_bodyUsed(copy_from.bodyUsed())
306 , m_responseType(ResponseType::ResponseUnknown)
307 , m_streamSource(new ReadableStreamSource(this))
308 , m_stream(new ReadableStreamImpl<ReadableStreamChunkTypeTraits<DOMArrayBuff er>>(copy_from.executionContext(), m_streamSource))
309 {
310 m_stream->didSourceStart();
311 }
312
313 void Body::resolveJSON(const String& string)
314 {
315 ASSERT(m_responseType == ResponseAsJSON);
316 ScriptState::Scope scope(m_resolver->scriptState());
317 v8::Isolate* isolate = m_resolver->scriptState()->isolate();
318 v8::Local<v8::String> inputString = v8String(isolate, string);
319 v8::TryCatch trycatch;
320 v8::Local<v8::Value> parsed = v8::JSON::Parse(inputString);
321 if (parsed.IsEmpty()) {
322 if (trycatch.HasCaught())
323 m_resolver->reject(trycatch.Exception());
324 else
325 m_resolver->reject(v8::Exception::Error(v8::String::NewFromUtf8(isol ate, "JSON parse error")));
326 return;
327 }
328 m_resolver->resolve(parsed);
329 }
330
331 // FileReaderLoaderClient functions.
332 void Body::didStartLoading() { }
333 void Body::didReceiveData() { }
334 void Body::didFinishLoading()
335 {
336 if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
337 return;
338
339 if (m_streamAccessed) {
340 didFinishLoadingViaStream(m_loader->arrayBufferResult().get());
341 m_resolver.clear();
342 m_stream->close();
343 return;
344 }
345
346 switch (m_responseType) {
347 case ResponseAsArrayBuffer:
348 m_resolver->resolve(m_loader->arrayBufferResult());
349 break;
350 case ResponseAsBlob: {
351 ASSERT(blobDataHandle()->size() == kuint64max);
352 OwnPtr<BlobData> blobData = BlobData::create();
353 RefPtr<DOMArrayBuffer> buffer = m_loader->arrayBufferResult();
354 blobData->appendBytes(buffer->data(), buffer->byteLength());
355 const size_t length = blobData->length();
356 m_resolver->resolve(Blob::create(BlobDataHandle::create(blobData.release (), length)));
357 break;
358 }
359 case ResponseAsFormData:
360 ASSERT_NOT_REACHED();
361 break;
362 case ResponseAsJSON:
363 resolveJSON(m_loader->stringResult());
364 break;
365 case ResponseAsText:
366 m_resolver->resolve(m_loader->stringResult());
367 break;
368 default:
369 ASSERT_NOT_REACHED();
370 }
371 m_resolver.clear();
372 m_stream->close();
373 }
374
375 void Body::didFinishLoadingViaStream(DOMArrayBuffer* buffer)
376 {
377 if (!m_bodyUsed) {
378 // |m_stream| is pulling.
379 ASSERT(m_streamAccessed);
380 m_stream->enqueue(buffer);
381 return;
382 }
383
384 switch (m_responseType) {
385 case ResponseAsArrayBuffer:
386 m_resolver->resolve(buffer);
387 break;
388 case ResponseAsBlob: {
389 OwnPtr<BlobData> blobData = BlobData::create();
390 blobData->appendBytes(buffer->data(), buffer->byteLength());
391 m_resolver->resolve(Blob::create(BlobDataHandle::create(blobData.release (), blobData->length())));
392 break;
393 }
394 case ResponseAsFormData:
395 ASSERT_NOT_REACHED();
396 break;
397 case ResponseAsJSON: {
398 String s = String::fromUTF8(static_cast<const char*>(buffer->data()), bu ffer->byteLength());
399 if (s.isNull())
400 m_resolver->reject(DOMException::create(NetworkError, "Invalid utf-8 string"));
401 else
402 resolveJSON(s);
403 break;
404 }
405 case ResponseAsText: {
406 String s = String::fromUTF8(static_cast<const char*>(buffer->data()), bu ffer->byteLength());
407 if (s.isNull())
408 m_resolver->reject(DOMException::create(NetworkError, "Invalid utf-8 string"));
409 else
410 m_resolver->resolve(s);
411 break;
412 }
413 default:
414 ASSERT_NOT_REACHED();
415 }
416 }
417
418 void Body::didFail(FileError::ErrorCode code)
419 {
420 if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
421 return;
422
423 if (m_resolver) {
424 // FIXME: We should reject the promise.
425 m_resolver->resolve("");
426 m_resolver.clear();
427 }
428 m_stream->error(DOMException::create(NetworkError, "network error"));
429 }
430
431 void Body::didBlobHandleReceiveError(PassRefPtrWillBeRawPtr<DOMException> except ion)
432 {
433 if (!m_resolver)
434 return;
435 m_resolver->reject(exception);
436 m_resolver.clear();
437 }
438
439 } // namespace blink
OLDNEW
« no previous file with comments | « Source/modules/serviceworkers/Body.h ('k') | Source/modules/serviceworkers/Body.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698