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