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
7#include "modules/websockets/WebSocket.h"
8
9#include "bindings/v8/ExceptionState.h"
10#include "bindings/v8/V8Binding.h"
11#include "core/dom/ExceptionCode.h"
12#include "core/fileapi/Blob.h"
13#include "core/frame/ConsoleTypes.h"
14#include "core/testing/DummyPageHolder.h"
15#include "wtf/ArrayBuffer.h"
16#include "wtf/OwnPtr.h"
17#include "wtf/Uint8Array.h"
18#include "wtf/Vector.h"
19#include "wtf/testing/WTFTestHelpers.h"
20#include "wtf/text/WTFString.h"
21#include <gmock/gmock.h>
22#include <gtest/gtest.h>
23#include <v8.h>
24
25using testing::_;
26using testing::AnyNumber;
27using testing::InSequence;
28using testing::Ref;
29using testing::Return;
30
31namespace WebCore {
32
33namespace {
34
35typedef testing::StrictMock<testing::MockFunction<void(int)> > Checkpoint;  // NOLINT
36
37class MockWebSocketChannel : public WebSocketChannel {
38public:
39    static PassRefPtrWillBeRawPtr<MockWebSocketChannel> create()
40    {
41        return adoptRefWillBeRefCountedGarbageCollected(new testing::StrictMock<MockWebSocketChannel>());
42    }
43
44    virtual ~MockWebSocketChannel()
45    {
46    }
47
48    MOCK_METHOD2(connect, bool(const KURL&, const String&));
49    MOCK_METHOD1(send, SendResult(const String&));
50    MOCK_METHOD3(send, SendResult(const ArrayBuffer&, unsigned, unsigned));
51    MOCK_METHOD1(send, SendResult(PassRefPtr<BlobDataHandle>));
52    MOCK_METHOD1(send, SendResult(PassOwnPtr<Vector<char> >));
53    MOCK_CONST_METHOD0(bufferedAmount, unsigned long());
54    MOCK_METHOD2(close, void(int, const String&));
55    MOCK_METHOD4(fail, void(const String&, MessageLevel, const String&, unsigned));
56    MOCK_METHOD0(disconnect, void());
57    MOCK_METHOD0(suspend, void());
58    MOCK_METHOD0(resume, void());
59
60    MockWebSocketChannel()
61    {
62    }
63};
64
65class WebSocketWithMockChannel FINAL : public WebSocket {
66public:
67    static PassRefPtrWillBeRawPtr<WebSocketWithMockChannel> create(ExecutionContext* context)
68    {
69        RefPtrWillBeRawPtr<WebSocketWithMockChannel> websocket = adoptRefWillBeRefCountedGarbageCollected(new WebSocketWithMockChannel(context));
70        websocket->suspendIfNeeded();
71        return websocket.release();
72    }
73
74    MockWebSocketChannel* channel() { return m_channel.get(); }
75
76    virtual PassRefPtrWillBeRawPtr<WebSocketChannel> createChannel(ExecutionContext*, WebSocketChannelClient*) OVERRIDE
77    {
78        ASSERT(!m_hasCreatedChannel);
79        m_hasCreatedChannel = true;
80        return m_channel.get();
81    }
82
83    virtual void trace(Visitor* visitor) OVERRIDE
84    {
85        visitor->trace(m_channel);
86        WebSocket::trace(visitor);
87    }
88
89private:
90    WebSocketWithMockChannel(ExecutionContext* context)
91        : WebSocket(context)
92        , m_channel(MockWebSocketChannel::create())
93        , m_hasCreatedChannel(false) { }
94
95    RefPtrWillBeMember<MockWebSocketChannel> m_channel;
96    bool m_hasCreatedChannel;
97};
98
99class WebSocketTestBase {
100public:
101    WebSocketTestBase()
102        : m_pageHolder(DummyPageHolder::create())
103        , m_websocket(WebSocketWithMockChannel::create(&m_pageHolder->document()))
104        , m_executionScope(v8::Isolate::GetCurrent())
105        , m_exceptionState(ExceptionState::ConstructionContext, "property", "interface", m_executionScope.scriptState()->context()->Global(), m_executionScope.isolate())
106    {
107    }
108
109    virtual ~WebSocketTestBase()
110    {
111        if (!m_websocket)
112            return;
113        // These statements are needed to clear WebSocket::m_channel to
114        // avoid ASSERTION failure on ~WebSocket.
115        ASSERT(m_websocket->channel());
116        ::testing::Mock::VerifyAndClear(m_websocket->channel());
117        EXPECT_CALL(channel(), disconnect()).Times(AnyNumber());
118
119        m_websocket->didClose(WebSocketChannelClient::ClosingHandshakeIncomplete, 1006, "");
120        m_websocket.clear();
121        Heap::collectAllGarbage();
122    }
123
124    MockWebSocketChannel& channel() { return *m_websocket->channel(); }
125
126    OwnPtr<DummyPageHolder> m_pageHolder;
127    RefPtrWillBePersistent<WebSocketWithMockChannel> m_websocket;
128    V8TestingScope m_executionScope;
129    ExceptionState m_exceptionState;
130};
131
132class WebSocketTest : public WebSocketTestBase, public ::testing::Test {
133public:
134};
135
136TEST_F(WebSocketTest, connectToBadURL)
137{
138    m_websocket->connect("xxx", Vector<String>(), m_exceptionState);
139
140
141    EXPECT_TRUE(m_exceptionState.hadException());
142    EXPECT_EQ(SyntaxError, m_exceptionState.code());
143    EXPECT_EQ("The URL 'xxx' is invalid.", m_exceptionState.message());
144    EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState());
145}
146
147TEST_F(WebSocketTest, connectToNonWsURL)
148{
149    m_websocket->connect("http://example.com/", Vector<String>(), m_exceptionState);
150
151
152    EXPECT_TRUE(m_exceptionState.hadException());
153    EXPECT_EQ(SyntaxError, m_exceptionState.code());
154    EXPECT_EQ("The URL's scheme must be either 'ws' or 'wss'. 'http' is not allowed.", m_exceptionState.message());
155    EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState());
156}
157
158TEST_F(WebSocketTest, connectToURLHavingFragmentIdentifier)
159{
160    m_websocket->connect("ws://example.com/#fragment", Vector<String>(), m_exceptionState);
161
162
163    EXPECT_TRUE(m_exceptionState.hadException());
164    EXPECT_EQ(SyntaxError, m_exceptionState.code());
165    EXPECT_EQ("The URL contains a fragment identifier ('fragment'). Fragment identifiers are not allowed in WebSocket URLs.", m_exceptionState.message());
166    EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState());
167}
168
169TEST_F(WebSocketTest, invalidPort)
170{
171    m_websocket->connect("ws://example.com:7", Vector<String>(), m_exceptionState);
172
173
174    EXPECT_TRUE(m_exceptionState.hadException());
175    EXPECT_EQ(SecurityError, m_exceptionState.code());
176    EXPECT_EQ("The port 7 is not allowed.", m_exceptionState.message());
177    EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState());
178}
179
180// FIXME: Add a test for Content Security Policy.
181
182TEST_F(WebSocketTest, invalidSubprotocols)
183{
184    Vector<String> subprotocols;
185    subprotocols.append("@subprotocol-|'\"x\x01\x02\x03x");
186
187    {
188        InSequence s;
189        EXPECT_CALL(channel(), disconnect());
190    }
191
192    m_websocket->connect("ws://example.com/", subprotocols, m_exceptionState);
193
194    EXPECT_TRUE(m_exceptionState.hadException());
195    EXPECT_EQ(SyntaxError, m_exceptionState.code());
196    EXPECT_EQ("The subprotocol '@subprotocol-|'\"x\\u0001\\u0002\\u0003x' is invalid.", m_exceptionState.message());
197    EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState());
198}
199
200TEST_F(WebSocketTest, channelConnectSuccess)
201{
202    Vector<String> subprotocols;
203    subprotocols.append("aa");
204    subprotocols.append("bb");
205
206    {
207        InSequence s;
208        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/hoge"), String("aa, bb"))).WillOnce(Return(true));
209    }
210
211    m_websocket->connect("ws://example.com/hoge", Vector<String>(subprotocols), m_exceptionState);
212
213
214    EXPECT_FALSE(m_exceptionState.hadException());
215    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
216    EXPECT_EQ(KURL(KURL(), "ws://example.com/hoge"), m_websocket->url());
217}
218
219TEST_F(WebSocketTest, channelConnectFail)
220{
221    Vector<String> subprotocols;
222    subprotocols.append("aa");
223    subprotocols.append("bb");
224
225    {
226        InSequence s;
227        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String("aa, bb"))).WillOnce(Return(false));
228        EXPECT_CALL(channel(), disconnect());
229    }
230
231    m_websocket->connect("ws://example.com/", Vector<String>(subprotocols), m_exceptionState);
232
233
234    EXPECT_TRUE(m_exceptionState.hadException());
235    EXPECT_EQ(SecurityError, m_exceptionState.code());
236    EXPECT_EQ("An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.", m_exceptionState.message());
237    EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState());
238}
239
240TEST_F(WebSocketTest, isValidSubprotocolString)
241{
242    EXPECT_TRUE(WebSocket::isValidSubprotocolString("Helloworld!!"));
243    EXPECT_FALSE(WebSocket::isValidSubprotocolString("Hello, world!!"));
244    EXPECT_FALSE(WebSocket::isValidSubprotocolString(String()));
245    EXPECT_FALSE(WebSocket::isValidSubprotocolString(""));
246
247    const char validCharacters[] = "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~";
248    size_t length = strlen(validCharacters);
249    for (size_t i = 0; i < length; ++i) {
250        String s;
251        s.append(static_cast<UChar>(validCharacters[i]));
252        EXPECT_TRUE(WebSocket::isValidSubprotocolString(s));
253    }
254    for (size_t i = 0; i < 256; ++i) {
255        if (std::find(validCharacters, validCharacters + length, static_cast<char>(i)) != validCharacters + length) {
256            continue;
257        }
258        String s;
259        s.append(static_cast<UChar>(i));
260        EXPECT_FALSE(WebSocket::isValidSubprotocolString(s));
261    }
262}
263
264TEST_F(WebSocketTest, connectSuccess)
265{
266    Vector<String> subprotocols;
267    subprotocols.append("aa");
268    subprotocols.append("bb");
269    {
270        InSequence s;
271        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String("aa, bb"))).WillOnce(Return(true));
272    }
273    m_websocket->connect("ws://example.com/", subprotocols, m_exceptionState);
274
275    EXPECT_FALSE(m_exceptionState.hadException());
276    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
277
278    m_websocket->didConnect("bb", "cc");
279
280    EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState());
281    EXPECT_EQ("bb", m_websocket->protocol());
282    EXPECT_EQ("cc", m_websocket->extensions());
283}
284
285TEST_F(WebSocketTest, didClose)
286{
287    {
288        InSequence s;
289        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
290        EXPECT_CALL(channel(), disconnect());
291    }
292    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
293
294    EXPECT_FALSE(m_exceptionState.hadException());
295    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
296
297    m_websocket->didClose(WebSocketChannelClient::ClosingHandshakeIncomplete, 1006, "");
298
299    EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState());
300}
301
302TEST_F(WebSocketTest, maximumReasonSize)
303{
304    {
305        InSequence s;
306        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
307        EXPECT_CALL(channel(), fail(_, _, _, _));
308    }
309    String reason;
310    for (size_t i = 0; i < 123; ++i)
311        reason.append("a");
312    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
313
314    EXPECT_FALSE(m_exceptionState.hadException());
315    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
316
317    m_websocket->close(1000, reason, m_exceptionState);
318
319    EXPECT_FALSE(m_exceptionState.hadException());
320    EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState());
321}
322
323TEST_F(WebSocketTest, reasonSizeExceeding)
324{
325    {
326        InSequence s;
327        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
328    }
329    String reason;
330    for (size_t i = 0; i < 124; ++i)
331        reason.append("a");
332    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
333
334    EXPECT_FALSE(m_exceptionState.hadException());
335    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
336
337    m_websocket->close(1000, reason, m_exceptionState);
338
339    EXPECT_TRUE(m_exceptionState.hadException());
340    EXPECT_EQ(SyntaxError, m_exceptionState.code());
341    EXPECT_EQ("The message must not be greater than 123 bytes.", m_exceptionState.message());
342    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
343}
344
345TEST_F(WebSocketTest, closeWhenConnecting)
346{
347    {
348        InSequence s;
349        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
350        EXPECT_CALL(channel(), fail(String("WebSocket is closed before the connection is established."), WarningMessageLevel, String(), 0));
351    }
352    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
353
354    EXPECT_FALSE(m_exceptionState.hadException());
355    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
356
357    m_websocket->close(1000, "bye", m_exceptionState);
358
359    EXPECT_FALSE(m_exceptionState.hadException());
360    EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState());
361}
362
363TEST_F(WebSocketTest, close)
364{
365    {
366        InSequence s;
367        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
368        EXPECT_CALL(channel(), close(3005, String("bye")));
369    }
370    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
371
372    EXPECT_FALSE(m_exceptionState.hadException());
373    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
374
375    m_websocket->didConnect("", "");
376    EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState());
377    m_websocket->close(3005, "bye", m_exceptionState);
378
379    EXPECT_FALSE(m_exceptionState.hadException());
380    EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState());
381}
382
383TEST_F(WebSocketTest, closeWithoutReason)
384{
385    {
386        InSequence s;
387        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
388        EXPECT_CALL(channel(), close(3005, String()));
389    }
390    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
391
392    EXPECT_FALSE(m_exceptionState.hadException());
393    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
394
395    m_websocket->didConnect("", "");
396    EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState());
397    m_websocket->close(3005, m_exceptionState);
398
399    EXPECT_FALSE(m_exceptionState.hadException());
400    EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState());
401}
402
403TEST_F(WebSocketTest, closeWithoutCodeAndReason)
404{
405    {
406        InSequence s;
407        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
408        EXPECT_CALL(channel(), close(-1, String()));
409    }
410    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
411
412    EXPECT_FALSE(m_exceptionState.hadException());
413    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
414
415    m_websocket->didConnect("", "");
416    EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState());
417    m_websocket->close(m_exceptionState);
418
419    EXPECT_FALSE(m_exceptionState.hadException());
420    EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState());
421}
422
423TEST_F(WebSocketTest, closeWhenClosing)
424{
425    {
426        InSequence s;
427        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
428        EXPECT_CALL(channel(), close(-1, String()));
429    }
430    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
431
432    EXPECT_FALSE(m_exceptionState.hadException());
433    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
434
435    m_websocket->didConnect("", "");
436    EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState());
437    m_websocket->close(m_exceptionState);
438    EXPECT_FALSE(m_exceptionState.hadException());
439    EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState());
440
441    m_websocket->close(m_exceptionState);
442
443    EXPECT_FALSE(m_exceptionState.hadException());
444    EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState());
445}
446
447TEST_F(WebSocketTest, closeWhenClosed)
448{
449    {
450        InSequence s;
451        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
452        EXPECT_CALL(channel(), close(-1, String()));
453        EXPECT_CALL(channel(), disconnect());
454    }
455    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
456
457    EXPECT_FALSE(m_exceptionState.hadException());
458    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
459
460    m_websocket->didConnect("", "");
461    EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState());
462    m_websocket->close(m_exceptionState);
463    EXPECT_FALSE(m_exceptionState.hadException());
464    EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState());
465
466    m_websocket->didClose(WebSocketChannelClient::ClosingHandshakeComplete, 1000, String());
467    EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState());
468    m_websocket->close(m_exceptionState);
469
470    EXPECT_FALSE(m_exceptionState.hadException());
471    EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState());
472}
473
474TEST_F(WebSocketTest, sendStringWhenConnecting)
475{
476    {
477        InSequence s;
478        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
479    }
480    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
481
482    EXPECT_FALSE(m_exceptionState.hadException());
483
484    m_websocket->send("hello", m_exceptionState);
485
486    EXPECT_TRUE(m_exceptionState.hadException());
487    EXPECT_EQ(InvalidStateError, m_exceptionState.code());
488    EXPECT_EQ("Still in CONNECTING state.", m_exceptionState.message());
489    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
490}
491
492TEST_F(WebSocketTest, sendStringWhenClosing)
493{
494    Checkpoint checkpoint;
495    {
496        InSequence s;
497        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
498        EXPECT_CALL(channel(), fail(_, _, _, _));
499    }
500    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
501
502    EXPECT_FALSE(m_exceptionState.hadException());
503
504    m_websocket->close(m_exceptionState);
505    EXPECT_FALSE(m_exceptionState.hadException());
506
507    m_websocket->send("hello", m_exceptionState);
508
509    EXPECT_FALSE(m_exceptionState.hadException());
510    EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState());
511}
512
513TEST_F(WebSocketTest, sendStringWhenClosed)
514{
515    Checkpoint checkpoint;
516    {
517        InSequence s;
518        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
519        EXPECT_CALL(channel(), disconnect());
520        EXPECT_CALL(checkpoint, Call(1));
521    }
522    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
523
524    EXPECT_FALSE(m_exceptionState.hadException());
525
526    m_websocket->didClose(WebSocketChannelClient::ClosingHandshakeIncomplete, 1006, "");
527    checkpoint.Call(1);
528
529    m_websocket->send("hello", m_exceptionState);
530
531    EXPECT_FALSE(m_exceptionState.hadException());
532    EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState());
533}
534
535TEST_F(WebSocketTest, sendStringSuccess)
536{
537    {
538        InSequence s;
539        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
540        EXPECT_CALL(channel(), send(String("hello"))).WillOnce(Return(WebSocketChannel::SendSuccess));
541    }
542    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
543
544    EXPECT_FALSE(m_exceptionState.hadException());
545
546    m_websocket->didConnect("", "");
547    m_websocket->send("hello", m_exceptionState);
548
549    EXPECT_FALSE(m_exceptionState.hadException());
550    EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState());
551}
552
553TEST_F(WebSocketTest, sendStringFail)
554{
555    {
556        InSequence s;
557        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
558        EXPECT_CALL(channel(), send(String("hello"))).WillOnce(Return(WebSocketChannel::SendFail));
559    }
560    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
561
562    EXPECT_FALSE(m_exceptionState.hadException());
563
564    m_websocket->didConnect("", "");
565    m_websocket->send("hello", m_exceptionState);
566
567    EXPECT_FALSE(m_exceptionState.hadException());
568    EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState());
569}
570
571TEST_F(WebSocketTest, sendStringInvalidMessage)
572{
573    {
574        InSequence s;
575        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
576        EXPECT_CALL(channel(), send(String("hello"))).WillOnce(Return(WebSocketChannel::InvalidMessage));
577    }
578    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
579
580    EXPECT_FALSE(m_exceptionState.hadException());
581
582    m_websocket->didConnect("", "");
583    m_websocket->send("hello", m_exceptionState);
584
585    EXPECT_TRUE(m_exceptionState.hadException());
586    EXPECT_EQ(SyntaxError, m_exceptionState.code());
587    EXPECT_EQ("The message contains invalid characters.", m_exceptionState.message());
588    EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState());
589}
590
591TEST_F(WebSocketTest, sendArrayBufferWhenConnecting)
592{
593    RefPtr<ArrayBufferView> view = Uint8Array::create(8);
594    {
595        InSequence s;
596        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
597    }
598    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
599
600    EXPECT_FALSE(m_exceptionState.hadException());
601
602    m_websocket->send(view->buffer().get(), m_exceptionState);
603
604    EXPECT_TRUE(m_exceptionState.hadException());
605    EXPECT_EQ(InvalidStateError, m_exceptionState.code());
606    EXPECT_EQ("Still in CONNECTING state.", m_exceptionState.message());
607    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
608}
609
610TEST_F(WebSocketTest, sendArrayBufferWhenClosing)
611{
612    RefPtr<ArrayBufferView> view = Uint8Array::create(8);
613    {
614        InSequence s;
615        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
616        EXPECT_CALL(channel(), fail(_, _, _, _));
617    }
618    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
619
620    EXPECT_FALSE(m_exceptionState.hadException());
621
622    m_websocket->close(m_exceptionState);
623    EXPECT_FALSE(m_exceptionState.hadException());
624
625    m_websocket->send(view->buffer().get(), m_exceptionState);
626
627    EXPECT_FALSE(m_exceptionState.hadException());
628    EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState());
629}
630
631TEST_F(WebSocketTest, sendArrayBufferWhenClosed)
632{
633    Checkpoint checkpoint;
634    RefPtr<ArrayBufferView> view = Uint8Array::create(8);
635    {
636        InSequence s;
637        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
638        EXPECT_CALL(channel(), disconnect());
639        EXPECT_CALL(checkpoint, Call(1));
640    }
641    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
642
643    EXPECT_FALSE(m_exceptionState.hadException());
644
645    m_websocket->didClose(WebSocketChannelClient::ClosingHandshakeIncomplete, 1006, "");
646    checkpoint.Call(1);
647
648    m_websocket->send(view->buffer().get(), m_exceptionState);
649
650    EXPECT_FALSE(m_exceptionState.hadException());
651    EXPECT_EQ(WebSocket::CLOSED, m_websocket->readyState());
652}
653
654TEST_F(WebSocketTest, sendArrayBufferSuccess)
655{
656    RefPtr<ArrayBufferView> view = Uint8Array::create(8);
657    {
658        InSequence s;
659        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
660        EXPECT_CALL(channel(), send(Ref(*view->buffer()), 0, 8)).WillOnce(Return(WebSocketChannel::SendSuccess));
661    }
662    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
663
664    EXPECT_FALSE(m_exceptionState.hadException());
665
666    m_websocket->didConnect("", "");
667    m_websocket->send(view->buffer().get(), m_exceptionState);
668
669    EXPECT_FALSE(m_exceptionState.hadException());
670    EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState());
671}
672
673TEST_F(WebSocketTest, sendArrayBufferFail)
674{
675    RefPtr<ArrayBufferView> view = Uint8Array::create(8);
676    {
677        InSequence s;
678        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
679        EXPECT_CALL(channel(), send(Ref(*view->buffer()), 0, 8)).WillOnce(Return(WebSocketChannel::SendFail));
680    }
681    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
682
683    EXPECT_FALSE(m_exceptionState.hadException());
684
685    m_websocket->didConnect("", "");
686    m_websocket->send(view->buffer().get(), m_exceptionState);
687
688    EXPECT_FALSE(m_exceptionState.hadException());
689    EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState());
690}
691
692TEST_F(WebSocketTest, sendArrayBufferInvalidMessage)
693{
694    RefPtr<ArrayBufferView> view = Uint8Array::create(8);
695    {
696        InSequence s;
697        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
698        EXPECT_CALL(channel(), send(Ref(*view->buffer()), 0, 8)).WillOnce(Return(WebSocketChannel::InvalidMessage));
699    }
700    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
701
702    EXPECT_FALSE(m_exceptionState.hadException());
703
704    m_websocket->didConnect("", "");
705    m_websocket->send(view->buffer().get(), m_exceptionState);
706
707    EXPECT_TRUE(m_exceptionState.hadException());
708    EXPECT_EQ(SyntaxError, m_exceptionState.code());
709    EXPECT_EQ("The message contains invalid characters.", m_exceptionState.message());
710    EXPECT_EQ(WebSocket::OPEN, m_websocket->readyState());
711}
712
713// FIXME: We should have Blob tests here.
714// We can't create a Blob because the blob registration cannot be mocked yet.
715
716// FIXME: We should add tests for bufferedAmount.
717
718// FIXME: We should add tests for data receiving.
719
720TEST_F(WebSocketTest, binaryType)
721{
722    EXPECT_EQ("blob", m_websocket->binaryType());
723
724    m_websocket->setBinaryType("hoge");
725
726    EXPECT_EQ("blob", m_websocket->binaryType());
727
728    m_websocket->setBinaryType("arraybuffer");
729
730    EXPECT_EQ("arraybuffer", m_websocket->binaryType());
731
732    m_websocket->setBinaryType("fuga");
733
734    EXPECT_EQ("arraybuffer", m_websocket->binaryType());
735
736    m_websocket->setBinaryType("blob");
737
738    EXPECT_EQ("blob", m_websocket->binaryType());
739}
740
741// FIXME: We should add tests for suspend / resume.
742
743class WebSocketValidClosingCodeTest : public WebSocketTestBase, public ::testing::TestWithParam<unsigned short> {
744public:
745};
746
747TEST_P(WebSocketValidClosingCodeTest, test)
748{
749    {
750        InSequence s;
751        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
752        EXPECT_CALL(channel(), fail(_, _, _, _));
753    }
754    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
755
756    EXPECT_FALSE(m_exceptionState.hadException());
757    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
758
759    m_websocket->close(GetParam(), "bye", m_exceptionState);
760
761    EXPECT_FALSE(m_exceptionState.hadException());
762    EXPECT_EQ(WebSocket::CLOSING, m_websocket->readyState());
763}
764
765INSTANTIATE_TEST_CASE_P(WebSocketValidClosingCode, WebSocketValidClosingCodeTest, ::testing::Values(1000, 3000, 3001, 4998, 4999));
766
767class WebSocketInvalidClosingCodeTest : public WebSocketTestBase, public ::testing::TestWithParam<unsigned short> {
768public:
769};
770
771TEST_P(WebSocketInvalidClosingCodeTest, test)
772{
773    {
774        InSequence s;
775        EXPECT_CALL(channel(), connect(KURL(KURL(), "ws://example.com/"), String())).WillOnce(Return(true));
776    }
777    m_websocket->connect("ws://example.com/", Vector<String>(), m_exceptionState);
778
779    EXPECT_FALSE(m_exceptionState.hadException());
780    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
781
782    m_websocket->close(GetParam(), "bye", m_exceptionState);
783
784    EXPECT_TRUE(m_exceptionState.hadException());
785    EXPECT_EQ(InvalidAccessError, m_exceptionState.code());
786    EXPECT_EQ(String::format("The code must be either 1000, or between 3000 and 4999. %d is neither.", GetParam()), m_exceptionState.message());
787    EXPECT_EQ(WebSocket::CONNECTING, m_websocket->readyState());
788}
789
790INSTANTIATE_TEST_CASE_P(WebSocketInvalidClosingCode, WebSocketInvalidClosingCodeTest, ::testing::Values(0, 1, 998, 999, 1001, 2999, 5000, 9999, 65535));
791
792} // namespace
793
794} // namespace WebCore
795