OLD | NEW |
| (Empty) |
1 // Copyright 2016 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 "core/page/EventSource.h" | |
6 | |
7 #include "bindings/core/v8/ExceptionState.h" | |
8 #include "bindings/core/v8/ScriptState.h" | |
9 #include "bindings/core/v8/ScriptValue.h" | |
10 #include "bindings/core/v8/SerializedScriptValue.h" | |
11 #include "bindings/core/v8/V8Binding.h" | |
12 #include "core/dom/ExecutionContext.h" | |
13 #include "core/dom/MessagePort.h" | |
14 #include "core/events/Event.h" | |
15 #include "core/events/EventListener.h" | |
16 #include "core/events/MessageEvent.h" | |
17 #include "core/page/EventSourceInit.h" | |
18 #include "core/testing/DummyPageHolder.h" | |
19 #include "testing/gtest/include/gtest/gtest.h" | |
20 | |
21 #include <string.h> | |
22 #include <v8.h> | |
23 | |
24 namespace blink { | |
25 | |
26 namespace { | |
27 | |
28 String dataAsString(ScriptState* scriptState, MessageEvent* event) | |
29 { | |
30 ScriptState::Scope scope(scriptState); | |
31 v8::Isolate* isolate = scriptState->isolate(); | |
32 ASSERT(MessageEvent::DataTypeSerializedScriptValue == event->dataType()); | |
33 if (!event->dataAsSerializedScriptValue()) | |
34 return String(); | |
35 MessagePortArray ports = event->ports(); | |
36 NonThrowableExceptionState es; | |
37 return toUSVString(isolate, event->dataAsSerializedScriptValue()->deserializ
e(isolate, &ports), es); | |
38 } | |
39 | |
40 class FakeEventListener : public EventListener { | |
41 public: | |
42 static PassRefPtrWillBeRawPtr<FakeEventListener> create() | |
43 { | |
44 return adoptRefWillBeNoop(new FakeEventListener()); | |
45 } | |
46 bool operator==(const EventListener& x) const override { return &x == this;
} | |
47 const WillBeHeapVector<RefPtrWillBeMember<Event>>& events() { return m_event
s; } | |
48 void handleEvent(ExecutionContext* executionContext, Event* event) | |
49 { | |
50 m_events.append(event); | |
51 } | |
52 DEFINE_INLINE_TRACE() | |
53 { | |
54 visitor->trace(m_events); | |
55 EventListener::trace(visitor); | |
56 } | |
57 | |
58 protected: | |
59 FakeEventListener() : EventListener(EventListener::CPPEventListenerType) {} | |
60 WillBeHeapVector<RefPtrWillBeMember<Event>> m_events; | |
61 }; | |
62 | |
63 class EventSourceTest : public ::testing::Test { | |
64 protected: | |
65 EventSourceTest() | |
66 : m_page(DummyPageHolder::create()) | |
67 , m_source(EventSource::create(&document(), "https://localhost/", EventS
ourceInit(), m_exceptionState)) | |
68 { | |
69 source()->setStateForTest(EventSource::OPEN); | |
70 source()->setRequestInFlightForTest(true); | |
71 } | |
72 ~EventSourceTest() override | |
73 { | |
74 source()->setRequestInFlightForTest(false); | |
75 source()->close(); | |
76 | |
77 // We need this because there is | |
78 // listener -> event -> source -> listener | |
79 // reference cycle on non-oilpan build. | |
80 m_source->removeAllEventListeners(); | |
81 m_source = nullptr; | |
82 } | |
83 | |
84 void enqueue(const char* data) { client()->didReceiveData(data, strlen(data)
); } | |
85 void enqueueOneByOne(const char* data) | |
86 { | |
87 const char*p = data; | |
88 while (*p != '\0') | |
89 client()->didReceiveData(p++, 1); | |
90 } | |
91 | |
92 Document& document() { return m_page->document(); } | |
93 ScriptState* scriptState() { return ScriptState::forMainWorld(document().fra
me()); } | |
94 EventSource* source() { return m_source; } | |
95 ThreadableLoaderClient* client() { return m_source->asThreadableLoaderClient
ForTest(); } | |
96 | |
97 private: | |
98 OwnPtr<DummyPageHolder> m_page; | |
99 NonThrowableExceptionState m_exceptionState; | |
100 Persistent<EventSource> m_source; | |
101 }; | |
102 | |
103 TEST_F(EventSourceTest, EmptyMessageEventShouldNotBeDispatched) | |
104 { | |
105 RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create()
; | |
106 | |
107 source()->addEventListener("message", listener); | |
108 enqueue("\n"); | |
109 | |
110 EXPECT_EQ(0u, listener->events().size()); | |
111 } | |
112 | |
113 TEST_F(EventSourceTest, DispatchSimpleMessageEvent) | |
114 { | |
115 RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create()
; | |
116 | |
117 source()->addEventListener("message", listener); | |
118 enqueue("data:hello\n\n"); | |
119 | |
120 ASSERT_EQ(1u, listener->events().size()); | |
121 ASSERT_EQ("message", listener->events()[0]->type()); | |
122 RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(listener
->events()[0].get()); | |
123 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType()); | |
124 EXPECT_EQ("hello", dataAsString(scriptState(), event.get())); | |
125 EXPECT_EQ(String(), event->lastEventId()); | |
126 } | |
127 | |
128 TEST_F(EventSourceTest, DispatchMessageEventWithLastEventId) | |
129 { | |
130 RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create()
; | |
131 | |
132 source()->addEventListener("message", listener); | |
133 enqueue("id:99\ndata:hello\n\n"); | |
134 | |
135 ASSERT_EQ(1u, listener->events().size()); | |
136 ASSERT_EQ("message", listener->events()[0]->type()); | |
137 RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(listener
->events()[0].get()); | |
138 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType()); | |
139 EXPECT_EQ("hello", dataAsString(scriptState(), event.get())); | |
140 EXPECT_EQ("99", event->lastEventId()); | |
141 } | |
142 | |
143 TEST_F(EventSourceTest, DispatchMessageEventWithCustomEventType) | |
144 { | |
145 RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create()
; | |
146 | |
147 source()->addEventListener("foo", listener); | |
148 enqueue("event:foo\ndata:hello\n\n"); | |
149 | |
150 ASSERT_EQ(1u, listener->events().size()); | |
151 ASSERT_EQ("foo", listener->events()[0]->type()); | |
152 RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(listener
->events()[0].get()); | |
153 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType()); | |
154 EXPECT_EQ("hello", dataAsString(scriptState(), event.get())); | |
155 } | |
156 | |
157 TEST_F(EventSourceTest, RetryTakesEffectEvenWhenNotDispatching) | |
158 { | |
159 RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create()
; | |
160 | |
161 source()->addEventListener("message", listener); | |
162 ASSERT_NE(999u, EventSource::defaultReconnectDelay); | |
163 | |
164 EXPECT_EQ(EventSource::defaultReconnectDelay, source()->reconnectDelayForTes
t()); | |
165 enqueue("retry:999\n"); | |
166 EXPECT_EQ(999u, source()->reconnectDelayForTest()); | |
167 EXPECT_EQ(0u, listener->events().size()); | |
168 } | |
169 | |
170 TEST_F(EventSourceTest, EventTypeShouldBeReset) | |
171 { | |
172 RefPtrWillBeRawPtr<FakeEventListener> fooListener = FakeEventListener::creat
e(); | |
173 RefPtrWillBeRawPtr<FakeEventListener> messageListener = FakeEventListener::c
reate(); | |
174 | |
175 source()->addEventListener("foo", fooListener); | |
176 source()->addEventListener("message", messageListener); | |
177 enqueue("event:foo\ndata:hello\n\ndata:bye\n\n"); | |
178 | |
179 ASSERT_EQ(1u, fooListener->events().size()); | |
180 ASSERT_EQ("foo", fooListener->events()[0]->type()); | |
181 RefPtrWillBeRawPtr<MessageEvent> fooEvent = static_cast<MessageEvent*>(fooLi
stener->events()[0].get()); | |
182 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, fooEvent->dataType())
; | |
183 EXPECT_EQ("hello", dataAsString(scriptState(), fooEvent.get())); | |
184 | |
185 ASSERT_EQ(1u, messageListener->events().size()); | |
186 ASSERT_EQ("message", messageListener->events()[0]->type()); | |
187 RefPtrWillBeRawPtr<MessageEvent> messageEvent = static_cast<MessageEvent*>(m
essageListener->events()[0].get()); | |
188 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, messageEvent->dataTyp
e()); | |
189 EXPECT_EQ("bye", dataAsString(scriptState(), messageEvent.get())); | |
190 } | |
191 | |
192 TEST_F(EventSourceTest, DataShouldBeReset) | |
193 { | |
194 RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create()
; | |
195 | |
196 source()->addEventListener("message", listener); | |
197 enqueue("data:hello\n\n\n"); | |
198 | |
199 ASSERT_EQ(1u, listener->events().size()); | |
200 ASSERT_EQ("message", listener->events()[0]->type()); | |
201 RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(listener
->events()[0].get()); | |
202 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType()); | |
203 EXPECT_EQ("hello", dataAsString(scriptState(), event.get())); | |
204 } | |
205 | |
206 TEST_F(EventSourceTest, LastEventIdShouldNotBeReset) | |
207 { | |
208 RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create()
; | |
209 | |
210 source()->addEventListener("message", listener); | |
211 enqueue("id:99\ndata:hello\n\ndata:bye\n\n"); | |
212 | |
213 ASSERT_EQ(2u, listener->events().size()); | |
214 | |
215 ASSERT_EQ("message", listener->events()[0]->type()); | |
216 RefPtrWillBeRawPtr<MessageEvent> event0 = static_cast<MessageEvent*>(listene
r->events()[0].get()); | |
217 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event0->dataType()); | |
218 EXPECT_EQ("hello", dataAsString(scriptState(), event0.get())); | |
219 EXPECT_EQ("99", event0->lastEventId()); | |
220 | |
221 ASSERT_EQ("message", listener->events()[1]->type()); | |
222 RefPtrWillBeRawPtr<MessageEvent> event1 = static_cast<MessageEvent*>(listene
r->events()[1].get()); | |
223 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event1->dataType()); | |
224 EXPECT_EQ("bye", dataAsString(scriptState(), event1.get())); | |
225 EXPECT_EQ("99", event1->lastEventId()); | |
226 } | |
227 | |
228 TEST_F(EventSourceTest, VariousNewLinesShouldBeAllowed) | |
229 { | |
230 RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create()
; | |
231 | |
232 source()->addEventListener("message", listener); | |
233 enqueueOneByOne("data:hello\r\n\rdata:bye\r\r"); | |
234 | |
235 ASSERT_EQ(2u, listener->events().size()); | |
236 | |
237 ASSERT_EQ("message", listener->events()[0]->type()); | |
238 RefPtrWillBeRawPtr<MessageEvent> event0 = static_cast<MessageEvent*>(listene
r->events()[0].get()); | |
239 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event0->dataType()); | |
240 EXPECT_EQ("hello", dataAsString(scriptState(), event0.get())); | |
241 | |
242 ASSERT_EQ("message", listener->events()[1]->type()); | |
243 RefPtrWillBeRawPtr<MessageEvent> event1 = static_cast<MessageEvent*>(listene
r->events()[1].get()); | |
244 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event1->dataType()); | |
245 EXPECT_EQ("bye", dataAsString(scriptState(), event1.get())); | |
246 } | |
247 | |
248 TEST_F(EventSourceTest, RetryWithEmptyValueShouldRestoreDefaultValue) | |
249 { | |
250 // TODO(yhirano): This is unspecified in the spec. We need to update | |
251 // the implementation or the spec. | |
252 EXPECT_EQ(EventSource::defaultReconnectDelay, source()->reconnectDelayForTes
t()); | |
253 enqueue("retry: 12\n"); | |
254 EXPECT_NE(EventSource::defaultReconnectDelay, source()->reconnectDelayForTes
t()); | |
255 enqueue("retry\n"); | |
256 EXPECT_EQ(EventSource::defaultReconnectDelay, source()->reconnectDelayForTes
t()); | |
257 } | |
258 | |
259 TEST_F(EventSourceTest, NonDigitRetryShouldBeIgnored) | |
260 { | |
261 RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create()
; | |
262 | |
263 source()->addEventListener("message", listener); | |
264 | |
265 EXPECT_EQ(EventSource::defaultReconnectDelay, source()->reconnectDelayForTes
t()); | |
266 enqueue("retry:123\n"); | |
267 EXPECT_NE(EventSource::defaultReconnectDelay, source()->reconnectDelayForTes
t()); | |
268 EXPECT_EQ(123u, source()->reconnectDelayForTest()); | |
269 | |
270 enqueue("retry:a0\n"); | |
271 EXPECT_EQ(123u, source()->reconnectDelayForTest()); | |
272 enqueue("retry:xi\n"); | |
273 EXPECT_EQ(123u, source()->reconnectDelayForTest()); | |
274 | |
275 enqueue("retry:2a\n"); | |
276 EXPECT_EQ(123u, source()->reconnectDelayForTest()); | |
277 | |
278 enqueue("retry:09a\n"); | |
279 EXPECT_EQ(123u, source()->reconnectDelayForTest()); | |
280 | |
281 enqueue("retry:1\b\n"); | |
282 EXPECT_EQ(123u, source()->reconnectDelayForTest()); | |
283 | |
284 enqueue("retry: 1234\n"); | |
285 EXPECT_EQ(123u, source()->reconnectDelayForTest()); | |
286 | |
287 enqueue("retry:456 \n"); | |
288 EXPECT_EQ(123u, source()->reconnectDelayForTest()); | |
289 | |
290 EXPECT_EQ(0u, listener->events().size()); | |
291 } | |
292 | |
293 TEST_F(EventSourceTest, UnrecognizedFieldShouldBeIgnored) | |
294 { | |
295 RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create()
; | |
296 | |
297 source()->addEventListener("message", listener); | |
298 enqueue("data:hello\nhoge:fuga\npiyo\n\n"); | |
299 | |
300 ASSERT_EQ(1u, listener->events().size()); | |
301 ASSERT_EQ("message", listener->events()[0]->type()); | |
302 RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(listener
->events()[0].get()); | |
303 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType()); | |
304 EXPECT_EQ("hello", dataAsString(scriptState(), event.get())); | |
305 } | |
306 | |
307 TEST_F(EventSourceTest, CommentShouldBeIgnored) | |
308 { | |
309 RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create()
; | |
310 | |
311 source()->addEventListener("message", listener); | |
312 enqueue("data:hello\n:event:a\n\n"); | |
313 | |
314 ASSERT_EQ(1u, listener->events().size()); | |
315 | |
316 ASSERT_EQ("message", listener->events()[0]->type()); | |
317 RefPtrWillBeRawPtr<MessageEvent> event0 = static_cast<MessageEvent*>(listene
r->events()[0].get()); | |
318 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event0->dataType()); | |
319 EXPECT_EQ("hello", dataAsString(scriptState(), event0.get())); | |
320 } | |
321 | |
322 TEST_F(EventSourceTest, BOMShouldBeIgnored) | |
323 { | |
324 RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create()
; | |
325 | |
326 source()->addEventListener("message", listener); | |
327 enqueue("\xef\xbb\xbf" "data:hello\n\n"); | |
328 | |
329 ASSERT_EQ(1u, listener->events().size()); | |
330 | |
331 ASSERT_EQ("message", listener->events()[0]->type()); | |
332 RefPtrWillBeRawPtr<MessageEvent> event0 = static_cast<MessageEvent*>(listene
r->events()[0].get()); | |
333 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event0->dataType()); | |
334 EXPECT_EQ("hello", dataAsString(scriptState(), event0.get())); | |
335 } | |
336 | |
337 TEST_F(EventSourceTest, ColonlessLineShouldBeTreatedAsNameOnlyField) | |
338 { | |
339 RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create()
; | |
340 | |
341 source()->addEventListener("message", listener); | |
342 enqueue("data:hello\nevent:a\nevent\n\n"); | |
343 | |
344 ASSERT_EQ(1u, listener->events().size()); | |
345 | |
346 ASSERT_EQ("message", listener->events()[0]->type()); | |
347 RefPtrWillBeRawPtr<MessageEvent> event0 = static_cast<MessageEvent*>(listene
r->events()[0].get()); | |
348 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event0->dataType()); | |
349 EXPECT_EQ("hello", dataAsString(scriptState(), event0.get())); | |
350 } | |
351 | |
352 TEST_F(EventSourceTest, AtMostOneLeadingSpaceCanBeSkipped) | |
353 { | |
354 RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create()
; | |
355 | |
356 source()->addEventListener(" type ", listener); | |
357 enqueue("data: hello \nevent: type \n\n"); | |
358 | |
359 ASSERT_EQ(1u, listener->events().size()); | |
360 ASSERT_EQ(" type ", listener->events()[0]->type()); | |
361 RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(listener
->events()[0].get()); | |
362 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType()); | |
363 EXPECT_EQ(" hello ", dataAsString(scriptState(), event.get())); | |
364 } | |
365 | |
366 TEST_F(EventSourceTest, DataShouldAccumulate) | |
367 { | |
368 RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create()
; | |
369 | |
370 source()->addEventListener("message", listener); | |
371 enqueue("data:hello\ndata: world\ndata\n\n"); | |
372 | |
373 ASSERT_EQ(1u, listener->events().size()); | |
374 ASSERT_EQ("message", listener->events()[0]->type()); | |
375 RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(listener
->events()[0].get()); | |
376 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType()); | |
377 EXPECT_EQ("hello\nworld\n", dataAsString(scriptState(), event.get())); | |
378 } | |
379 | |
380 TEST_F(EventSourceTest, EventShouldNotAccumulate) | |
381 { | |
382 RefPtrWillBeRawPtr<FakeEventListener> aListener = FakeEventListener::create(
); | |
383 RefPtrWillBeRawPtr<FakeEventListener> bListener = FakeEventListener::create(
); | |
384 | |
385 source()->addEventListener("a", aListener); | |
386 source()->addEventListener("b", bListener); | |
387 enqueue("data:hello\nevent:a\nevent:b\n\n"); | |
388 | |
389 ASSERT_EQ(0u, aListener->events().size()); | |
390 ASSERT_EQ(1u, bListener->events().size()); | |
391 ASSERT_EQ("b", bListener->events()[0]->type()); | |
392 RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(bListene
r->events()[0].get()); | |
393 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType()); | |
394 EXPECT_EQ("hello", dataAsString(scriptState(), event.get())); | |
395 } | |
396 | |
397 TEST_F(EventSourceTest, FeedDataOneByOne) | |
398 { | |
399 RefPtrWillBeRawPtr<FakeEventListener> aListener = FakeEventListener::create(
); | |
400 RefPtrWillBeRawPtr<FakeEventListener> bListener = FakeEventListener::create(
); | |
401 RefPtrWillBeRawPtr<FakeEventListener> messageListener = FakeEventListener::c
reate(); | |
402 | |
403 source()->addEventListener("a", aListener); | |
404 source()->addEventListener("b", bListener); | |
405 source()->addEventListener("message", messageListener); | |
406 enqueueOneByOne("data:hello\r\ndata:world\revent:a\revent:b\nid:4\n\nid:8\nd
ata:bye\r\n\r"); | |
407 | |
408 ASSERT_EQ(0u, aListener->events().size()); | |
409 | |
410 ASSERT_EQ(1u, bListener->events().size()); | |
411 ASSERT_EQ("b", bListener->events()[0]->type()); | |
412 RefPtrWillBeRawPtr<MessageEvent> bEvent = static_cast<MessageEvent*>(bListen
er->events()[0].get()); | |
413 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, bEvent->dataType()); | |
414 EXPECT_EQ("hello\nworld", dataAsString(scriptState(), bEvent.get())); | |
415 EXPECT_EQ("4", bEvent->lastEventId()); | |
416 | |
417 ASSERT_EQ(1u, messageListener->events().size()); | |
418 ASSERT_EQ("message", messageListener->events()[0]->type()); | |
419 RefPtrWillBeRawPtr<MessageEvent> messageEvent = static_cast<MessageEvent*>(m
essageListener->events()[0].get()); | |
420 ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, messageEvent->dataTyp
e()); | |
421 EXPECT_EQ("bye", dataAsString(scriptState(), messageEvent.get())); | |
422 EXPECT_EQ("8", messageEvent->lastEventId()); | |
423 } | |
424 | |
425 } // namespace | |
426 | |
427 } // namespace blink | |
OLD | NEW |