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 // A method should return a different promise on each call. |
55 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; | 54 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; |
56 ScriptPromise promise = resolver->promise(); | 55 ScriptPromise promise = resolver->promise(); |
57 resolver->resolve(closed(scriptState).v8Value()); | 56 resolver->resolve(closed(scriptState).v8Value()); |
tyoshino (SeeGerritForStatus)
2015/10/30 04:50:34
closed may be still pending if this reader has bee
yhirano
2015/10/30 06:00:57
m_closed is rejected when this reader is released.
| |
58 return promise; | 57 return promise; |
59 } | 58 } |
60 | 59 |
61 ScriptPromise ReadableStreamReader::read(ScriptState* scriptState) | 60 ScriptPromise ReadableStreamReader::read(ScriptState* scriptState) |
62 { | 61 { |
63 if (!isActive()) { | 62 if (!isActive()) |
64 ASSERT(m_stateAfterRelease == ReadableStream::Closed || m_stateAfterRele ase == ReadableStream::Errored); | 63 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 | 64 |
76 return m_stream->read(scriptState); | 65 return m_stream->read(scriptState); |
77 } | 66 } |
78 | 67 |
79 void ReadableStreamReader::releaseLock(ExceptionState& es) | 68 void ReadableStreamReader::releaseLock(ExceptionState& es) |
80 { | 69 { |
81 if (!isActive()) | 70 if (!isActive()) |
82 return; | 71 return; |
83 if (m_stream->hasPendingReads()) { | 72 if (m_stream->hasPendingReads()) { |
84 es.throwTypeError("The stream has pending read operations."); | 73 es.throwTypeError("The stream has pending read operations."); |
85 return; | 74 return; |
86 } | 75 } |
87 | 76 |
88 releaseLock(); | 77 releaseLock(); |
89 } | 78 } |
90 | 79 |
91 void ReadableStreamReader::releaseLock() | 80 void ReadableStreamReader::releaseLock() |
92 { | 81 { |
93 if (!isActive()) | 82 if (!isActive()) |
94 return; | 83 return; |
95 | 84 |
96 ASSERT(!m_stream->hasPendingReads()); | 85 ASSERT(!m_stream->hasPendingReads()); |
97 if (m_stream->stateInternal() == ReadableStream::Closed) { | 86 if (m_stream->stateInternal() != ReadableStream::Readable) |
98 m_stateAfterRelease = ReadableStream::Closed; | 87 m_closed->reset(); |
99 m_closed->resolve(ToV8UndefinedGenerator()); | 88 // Note: It is generally a bad idea to store world-dependent values |
100 } else if (m_stream->stateInternal() == ReadableStream::Errored) { | 89 // (e.g. v8::Object) in a ScriptPromiseProperty, so we use DOMException |
101 m_stateAfterRelease = ReadableStream::Errored; | 90 // though the spec says the promise should be rejected with a TypeError. |
102 m_closed->reject(m_stream->storedException()); | 91 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 | 92 |
108 // We call setReader(nullptr) after resolving / rejecting |m_closed| | 93 // We call setReader(nullptr) after resolving / rejecting |m_closed| |
109 // because it affects hasPendingActivity. | 94 // because it affects hasPendingActivity. |
110 m_stream->setReader(nullptr); | 95 m_stream->setReader(nullptr); |
111 ASSERT(!isActive()); | 96 ASSERT(!isActive()); |
112 } | 97 } |
113 | 98 |
99 void ReadableStreamReader::close() | |
100 { | |
101 ASSERT(isActive()); | |
102 m_closed->resolve(ToV8UndefinedGenerator()); | |
103 } | |
104 | |
105 void ReadableStreamReader::error() | |
106 { | |
107 ASSERT(isActive()); | |
108 m_closed->reject(m_stream->storedException()); | |
109 } | |
110 | |
114 bool ReadableStreamReader::hasPendingActivity() const | 111 bool ReadableStreamReader::hasPendingActivity() const |
115 { | 112 { |
116 // We need to extend ReadableStreamReader's wrapper's life while it is | 113 // We need to extend ReadableStreamReader's wrapper's life while it is |
117 // active in order to call resolve / reject on ScriptPromiseProperties. | 114 // active in order to call resolve / reject on ScriptPromiseProperties. |
118 return isActive(); | 115 return isActive() && m_stream->stateInternal() == ReadableStream::Readable; |
119 } | 116 } |
120 | 117 |
121 void ReadableStreamReader::stop() | 118 void ReadableStreamReader::stop() |
122 { | 119 { |
123 if (isActive()) { | 120 if (isActive()) { |
124 // Calling |error| will release the lock. | 121 // Calling |error| will release the lock. |
125 m_stream->error(DOMException::create(AbortError, "The frame stops workin g.")); | 122 m_stream->error(DOMException::create(AbortError, "The frame stops workin g.")); |
126 } | 123 } |
127 ActiveDOMObject::stop(); | 124 ActiveDOMObject::stop(); |
128 } | 125 } |
129 | 126 |
130 DEFINE_TRACE(ReadableStreamReader) | 127 DEFINE_TRACE(ReadableStreamReader) |
131 { | 128 { |
132 visitor->trace(m_stream); | 129 visitor->trace(m_stream); |
133 visitor->trace(m_closed); | 130 visitor->trace(m_closed); |
134 ActiveDOMObject::trace(visitor); | 131 ActiveDOMObject::trace(visitor); |
135 } | 132 } |
136 | 133 |
137 } // namespace blink | 134 } // namespace blink |
OLD | NEW |