OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 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 "config.h" | 5 #include "config.h" |
6 #include "core/streams/ReadableStreamReader.h" | 6 #include "core/streams/ReadableStreamReader.h" |
7 | 7 |
8 #include "bindings/core/v8/ExceptionState.h" | 8 #include "bindings/core/v8/ExceptionState.h" |
9 #include "bindings/core/v8/ScriptPromiseResolver.h" | 9 #include "bindings/core/v8/ScriptPromiseResolver.h" |
| 10 #include "bindings/core/v8/ToV8.h" |
10 #include "bindings/core/v8/V8IteratorResultValue.h" | 11 #include "bindings/core/v8/V8IteratorResultValue.h" |
11 #include "core/dom/DOMException.h" | 12 #include "core/dom/DOMException.h" |
12 #include "core/dom/ExceptionCode.h" | 13 #include "core/dom/ExceptionCode.h" |
13 #include "core/streams/ReadableStream.h" | 14 #include "core/streams/ReadableStream.h" |
14 | 15 |
15 namespace blink { | 16 namespace blink { |
16 | 17 |
17 ReadableStreamReader::ReadableStreamReader(ExecutionContext* executionContext, R
eadableStream* stream) | 18 ReadableStreamReader::ReadableStreamReader(ExecutionContext* executionContext, R
eadableStream* stream) |
18 : ActiveDOMObject(executionContext) | 19 : ActiveDOMObject(executionContext) |
19 , m_stream(stream) | 20 , m_stream(stream) |
20 , m_stateAfterRelease(ReadableStream::Closed) | |
21 , m_closed(new ClosedPromise(executionContext, this, ClosedPromise::Closed)) | 21 , m_closed(new ClosedPromise(executionContext, this, ClosedPromise::Closed)) |
22 { | 22 { |
23 suspendIfNeeded(); | 23 suspendIfNeeded(); |
24 ASSERT(m_stream->isLockedTo(nullptr)); | 24 ASSERT(m_stream->isLockedTo(nullptr)); |
25 m_stream->setReader(this); | 25 m_stream->setReader(this); |
26 | 26 |
27 if (m_stream->stateInternal() == ReadableStream::Closed || m_stream->stateIn
ternal() == ReadableStream::Errored) { | 27 if (m_stream->stateInternal() == ReadableStream::Closed) |
28 // If the stream is already closed or errored the created reader | 28 m_closed->resolve(ToV8UndefinedGenerator()); |
29 // should be closed or errored respectively. | 29 if (m_stream->stateInternal() == ReadableStream::Errored) |
30 releaseLock(); | 30 m_closed->reject(m_stream->storedException()); |
31 } | |
32 } | 31 } |
33 | 32 |
34 ScriptPromise ReadableStreamReader::closed(ScriptState* scriptState) | 33 ScriptPromise ReadableStreamReader::closed(ScriptState* scriptState) |
35 { | 34 { |
36 return m_closed->promise(scriptState->world()); | 35 return m_closed->promise(scriptState->world()); |
37 } | 36 } |
38 | 37 |
39 bool ReadableStreamReader::isActive() const | 38 bool ReadableStreamReader::isActive() const |
40 { | 39 { |
41 return m_stream->isLockedTo(this); | 40 return m_stream->isLockedTo(this); |
42 } | 41 } |
43 | 42 |
44 ScriptPromise ReadableStreamReader::cancel(ScriptState* scriptState) | 43 ScriptPromise ReadableStreamReader::cancel(ScriptState* scriptState) |
45 { | 44 { |
46 return cancel(scriptState, ScriptValue(scriptState, v8::Undefined(scriptStat
e->isolate()))); | 45 return cancel(scriptState, ScriptValue(scriptState, v8::Undefined(scriptStat
e->isolate()))); |
47 } | 46 } |
48 | 47 |
49 ScriptPromise ReadableStreamReader::cancel(ScriptState* scriptState, ScriptValue
reason) | 48 ScriptPromise ReadableStreamReader::cancel(ScriptState* scriptState, ScriptValue
reason) |
50 { | 49 { |
51 if (isActive()) | 50 if (isActive()) |
52 return m_stream->cancelInternal(scriptState, reason); | 51 return m_stream->cancelInternal(scriptState, reason); |
53 | 52 |
54 // A method should return a different promise on each call. | 53 return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(
scriptState->isolate(), "the reader is already released")); |
55 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; | |
56 ScriptPromise promise = resolver->promise(); | |
57 resolver->resolve(closed(scriptState).v8Value()); | |
58 return promise; | |
59 } | 54 } |
60 | 55 |
61 ScriptPromise ReadableStreamReader::read(ScriptState* scriptState) | 56 ScriptPromise ReadableStreamReader::read(ScriptState* scriptState) |
62 { | 57 { |
63 if (!isActive()) { | 58 if (!isActive()) |
64 ASSERT(m_stateAfterRelease == ReadableStream::Closed || m_stateAfterRele
ase == ReadableStream::Errored); | 59 return ScriptPromise::reject(scriptState, V8ThrowException::createTypeEr
ror(scriptState->isolate(), "the reader is already released")); |
65 if (m_stateAfterRelease == ReadableStream::Closed) { | |
66 // {value: undefined, done: true} | |
67 return ScriptPromise::cast(scriptState, v8IteratorResultDone(scriptS
tate)); | |
68 } | |
69 // A method should return a different promise on each call. | |
70 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptSt
ate); | |
71 ScriptPromise promise = resolver->promise(); | |
72 resolver->resolve(closed(scriptState).v8Value()); | |
73 return promise; | |
74 } | |
75 | 60 |
76 return m_stream->read(scriptState); | 61 return m_stream->read(scriptState); |
77 } | 62 } |
78 | 63 |
79 void ReadableStreamReader::releaseLock(ExceptionState& es) | 64 void ReadableStreamReader::releaseLock(ExceptionState& es) |
80 { | 65 { |
81 if (!isActive()) | 66 if (!isActive()) |
82 return; | 67 return; |
83 if (m_stream->hasPendingReads()) { | 68 if (m_stream->hasPendingReads()) { |
84 es.throwTypeError("The stream has pending read operations."); | 69 es.throwTypeError("The stream has pending read operations."); |
85 return; | 70 return; |
86 } | 71 } |
87 | 72 |
88 releaseLock(); | 73 releaseLock(); |
89 } | 74 } |
90 | 75 |
91 void ReadableStreamReader::releaseLock() | 76 void ReadableStreamReader::releaseLock() |
92 { | 77 { |
93 if (!isActive()) | 78 if (!isActive()) |
94 return; | 79 return; |
95 | 80 |
96 ASSERT(!m_stream->hasPendingReads()); | 81 ASSERT(!m_stream->hasPendingReads()); |
97 if (m_stream->stateInternal() == ReadableStream::Closed) { | 82 if (m_stream->stateInternal() != ReadableStream::Readable) |
98 m_stateAfterRelease = ReadableStream::Closed; | 83 m_closed->reset(); |
99 m_closed->resolve(ToV8UndefinedGenerator()); | 84 // Note: It is generally a bad idea to store world-dependent values |
100 } else if (m_stream->stateInternal() == ReadableStream::Errored) { | 85 // (e.g. v8::Object) in a ScriptPromiseProperty, so we use DOMException |
101 m_stateAfterRelease = ReadableStream::Errored; | 86 // though the spec says the promise should be rejected with a TypeError. |
102 m_closed->reject(m_stream->storedException()); | 87 m_closed->reject(DOMException::create(AbortError, "the reader is already rel
eased")); |
103 } else { | |
104 m_stateAfterRelease = ReadableStream::Closed; | |
105 m_closed->resolve(ToV8UndefinedGenerator()); | |
106 } | |
107 | 88 |
108 // We call setReader(nullptr) after resolving / rejecting |m_closed| | 89 // We call setReader(nullptr) after resolving / rejecting |m_closed| |
109 // because it affects hasPendingActivity. | 90 // because it affects hasPendingActivity. |
110 m_stream->setReader(nullptr); | 91 m_stream->setReader(nullptr); |
111 ASSERT(!isActive()); | 92 ASSERT(!isActive()); |
112 } | 93 } |
113 | 94 |
| 95 void ReadableStreamReader::close() |
| 96 { |
| 97 ASSERT(isActive()); |
| 98 m_closed->resolve(ToV8UndefinedGenerator()); |
| 99 } |
| 100 |
| 101 void ReadableStreamReader::error() |
| 102 { |
| 103 ASSERT(isActive()); |
| 104 m_closed->reject(m_stream->storedException()); |
| 105 } |
| 106 |
114 bool ReadableStreamReader::hasPendingActivity() const | 107 bool ReadableStreamReader::hasPendingActivity() const |
115 { | 108 { |
116 // We need to extend ReadableStreamReader's wrapper's life while it is | 109 // We need to extend ReadableStreamReader's wrapper's life while it is |
117 // active in order to call resolve / reject on ScriptPromiseProperties. | 110 // active in order to call resolve / reject on ScriptPromiseProperties. |
118 return isActive(); | 111 return isActive() && m_stream->stateInternal() == ReadableStream::Readable; |
119 } | 112 } |
120 | 113 |
121 void ReadableStreamReader::stop() | 114 void ReadableStreamReader::stop() |
122 { | 115 { |
123 if (isActive()) { | 116 if (isActive()) { |
124 // Calling |error| will release the lock. | 117 // Calling |error| will release the lock. |
125 m_stream->error(DOMException::create(AbortError, "The frame stops workin
g.")); | 118 m_stream->error(DOMException::create(AbortError, "The frame stops workin
g.")); |
126 } | 119 } |
127 ActiveDOMObject::stop(); | 120 ActiveDOMObject::stop(); |
128 } | 121 } |
129 | 122 |
130 DEFINE_TRACE(ReadableStreamReader) | 123 DEFINE_TRACE(ReadableStreamReader) |
131 { | 124 { |
132 visitor->trace(m_stream); | 125 visitor->trace(m_stream); |
133 visitor->trace(m_closed); | 126 visitor->trace(m_closed); |
134 ActiveDOMObject::trace(visitor); | 127 ActiveDOMObject::trace(visitor); |
135 } | 128 } |
136 | 129 |
137 } // namespace blink | 130 } // namespace blink |
OLD | NEW |