1 // Copyright (c) 2012 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 "ppapi/tests/test_websocket.h" 6 7 #include <stdio.h> 8 #include <string.h> 9 10 #include <algorithm> 11 #include <memory> 12 #include <string> 13 #include <vector> 14 15 #include "ppapi/c/pp_bool.h" 16 #include "ppapi/c/pp_completion_callback.h" 17 #include "ppapi/c/pp_errors.h" 18 #include "ppapi/c/pp_instance.h" 19 #include "ppapi/c/pp_resource.h" 20 #include "ppapi/c/pp_var.h" 21 #include "ppapi/c/ppb_core.h" 22 #include "ppapi/c/ppb_var.h" 23 #include "ppapi/c/ppb_var_array_buffer.h" 24 #include "ppapi/c/ppb_websocket.h" 25 #include "ppapi/c/private/ppb_testing_private.h" 26 #include "ppapi/cpp/instance.h" 27 #include "ppapi/cpp/module.h" 28 #include "ppapi/cpp/var_array_buffer.h" 29 #include "ppapi/cpp/websocket.h" 30 #include "ppapi/tests/test_utils.h" 31 #include "ppapi/tests/testing_instance.h" 32 #include "ppapi/utility/websocket/websocket_api.h" 33 34 // net::SpawnedTestServer serves WebSocket service for testing. 35 // Following URLs are handled by pywebsocket handlers in 36 // net/data/websocket/*_wsh.py. 37 const char kEchoServerURL[] = "echo-with-no-extension"; 38 const char kCloseServerURL[] = "close"; 39 const char kCloseWithCodeAndReasonServerURL[] = "close-code-and-reason"; 40 const char kProtocolTestServerURL[] = "protocol-test?protocol="; 41 42 const char* const kInvalidURLs[] = { 43 "http://www.google.com/invalid_scheme", 44 "ws://www.google.com/invalid#fragment", 45 "ws://www.google.com:65535/invalid_port", 46 NULL 47 }; 48 49 // Internal packet sizes. 50 const uint64_t kMessageFrameOverhead = 6; 51 52 namespace { 53 54 struct WebSocketEvent { 55 enum EventType { 56 EVENT_OPEN, 57 EVENT_MESSAGE, 58 EVENT_ERROR, 59 EVENT_CLOSE 60 }; 61 62 WebSocketEvent(EventType type, 63 bool was_clean, 64 uint16_t close_code, 65 const pp::Var& var) 66 : event_type(type), 67 was_clean(was_clean), 68 close_code(close_code), 69 var(var) { 70 } 71 EventType event_type; 72 bool was_clean; 73 uint16_t close_code; 74 pp::Var var; 75 }; 76 77 class ReleaseResourceDelegate : public TestCompletionCallback::Delegate { 78 public: 79 explicit ReleaseResourceDelegate(const PPB_Core* core_interface, 80 PP_Resource resource) 81 : core_interface_(core_interface), 82 resource_(resource) { 83 } 84 85 // TestCompletionCallback::Delegate implementation. 86 virtual void OnCallback(void* user_data, int32_t result) { 87 if (resource_) 88 core_interface_->ReleaseResource(resource_); 89 } 90 91 private: 92 const PPB_Core* core_interface_; 93 PP_Resource resource_; 94 }; 95 96 class TestWebSocketAPI : public pp::WebSocketAPI { 97 public: 98 explicit TestWebSocketAPI(pp::Instance* instance) 99 : pp::WebSocketAPI(instance), 100 connected_(false), 101 received_(false), 102 closed_(false), 103 wait_for_connected_(false), 104 wait_for_received_(false), 105 wait_for_closed_(false), 106 instance_(instance->pp_instance()) { 107 } 108 109 virtual void WebSocketDidOpen() { 110 events_.push_back( 111 WebSocketEvent(WebSocketEvent::EVENT_OPEN, true, 0U, pp::Var())); 112 connected_ = true; 113 if (wait_for_connected_) { 114 GetTestingInterface()->QuitMessageLoop(instance_); 115 wait_for_connected_ = false; 116 } 117 } 118 119 virtual void WebSocketDidClose( 120 bool was_clean, uint16_t code, const pp::Var& reason) { 121 events_.push_back( 122 WebSocketEvent(WebSocketEvent::EVENT_CLOSE, was_clean, code, reason)); 123 connected_ = true; 124 closed_ = true; 125 if (wait_for_connected_ || wait_for_closed_) { 126 GetTestingInterface()->QuitMessageLoop(instance_); 127 wait_for_connected_ = false; 128 wait_for_closed_ = false; 129 } 130 } 131 132 virtual void HandleWebSocketMessage(const pp::Var &message) { 133 events_.push_back( 134 WebSocketEvent(WebSocketEvent::EVENT_MESSAGE, true, 0U, message)); 135 received_ = true; 136 if (wait_for_received_) { 137 GetTestingInterface()->QuitMessageLoop(instance_); 138 wait_for_received_ = false; 139 received_ = false; 140 } 141 } 142 143 virtual void HandleWebSocketError() { 144 events_.push_back( 145 WebSocketEvent(WebSocketEvent::EVENT_ERROR, true, 0U, pp::Var())); 146 } 147 148 void WaitForConnected() { 149 if (!connected_) { 150 wait_for_connected_ = true; 151 GetTestingInterface()->RunMessageLoop(instance_); 152 } 153 } 154 155 void WaitForReceived() { 156 if (!received_) { 157 wait_for_received_ = true; 158 GetTestingInterface()->RunMessageLoop(instance_); 159 } 160 } 161 162 void WaitForClosed() { 163 if (!closed_) { 164 wait_for_closed_ = true; 165 GetTestingInterface()->RunMessageLoop(instance_); 166 } 167 } 168 169 const std::vector<WebSocketEvent>& GetSeenEvents() const { 170 return events_; 171 } 172 173 private: 174 std::vector<WebSocketEvent> events_; 175 bool connected_; 176 bool received_; 177 bool closed_; 178 bool wait_for_connected_; 179 bool wait_for_received_; 180 bool wait_for_closed_; 181 PP_Instance instance_; 182 }; 183 184 } // namespace 185 186 REGISTER_TEST_CASE(WebSocket); 187 188 bool TestWebSocket::Init() { 189 websocket_interface_ = static_cast<const PPB_WebSocket*>( 190 pp::Module::Get()->GetBrowserInterface(PPB_WEBSOCKET_INTERFACE)); 191 var_interface_ = static_cast<const PPB_Var*>( 192 pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE)); 193 arraybuffer_interface_ = static_cast<const PPB_VarArrayBuffer*>( 194 pp::Module::Get()->GetBrowserInterface( 195 PPB_VAR_ARRAY_BUFFER_INTERFACE)); 196 core_interface_ = static_cast<const PPB_Core*>( 197 pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE)); 198 if (!websocket_interface_ || !var_interface_ || !arraybuffer_interface_ || 199 !core_interface_) 200 return false; 201 202 return CheckTestingInterface(); 203 } 204 205 void TestWebSocket::RunTests(const std::string& filter) { 206 RUN_TEST_WITH_REFERENCE_CHECK(IsWebSocket, filter); 207 RUN_TEST_WITH_REFERENCE_CHECK(UninitializedPropertiesAccess, filter); 208 RUN_TEST_WITH_REFERENCE_CHECK(InvalidConnect, filter); 209 RUN_TEST_WITH_REFERENCE_CHECK(Protocols, filter); 210 RUN_TEST_WITH_REFERENCE_CHECK(GetURL, filter); 211 RUN_TEST_WITH_REFERENCE_CHECK(ValidConnect, filter); 212 RUN_TEST_WITH_REFERENCE_CHECK(InvalidClose, filter); 213 RUN_TEST_WITH_REFERENCE_CHECK(ValidClose, filter); 214 RUN_TEST_WITH_REFERENCE_CHECK(GetProtocol, filter); 215 RUN_TEST_WITH_REFERENCE_CHECK(TextSendReceive, filter); 216 RUN_TEST_BACKGROUND(TestWebSocket, TextSendReceiveTwice, filter); 217 RUN_TEST_WITH_REFERENCE_CHECK(BinarySendReceive, filter); 218 RUN_TEST_WITH_REFERENCE_CHECK(StressedSendReceive, filter); 219 RUN_TEST_WITH_REFERENCE_CHECK(BufferedAmount, filter); 220 // PP_Resource for WebSocket may be released later because of an internal 221 // reference for asynchronous IPC handling. So, suppress reference check on 222 // the following AbortCallsWithCallback test. 223 RUN_TEST(AbortCallsWithCallback, filter); 224 RUN_TEST_WITH_REFERENCE_CHECK(AbortSendMessageCall, filter); 225 RUN_TEST_WITH_REFERENCE_CHECK(AbortCloseCall, filter); 226 RUN_TEST_WITH_REFERENCE_CHECK(AbortReceiveMessageCall, filter); 227 RUN_TEST_WITH_REFERENCE_CHECK(ClosedFromServerWhileSending, filter); 228 229 RUN_TEST_WITH_REFERENCE_CHECK(CcInterfaces, filter); 230 231 RUN_TEST_WITH_REFERENCE_CHECK(UtilityInvalidConnect, filter); 232 RUN_TEST_WITH_REFERENCE_CHECK(UtilityProtocols, filter); 233 RUN_TEST_WITH_REFERENCE_CHECK(UtilityGetURL, filter); 234 RUN_TEST_WITH_REFERENCE_CHECK(UtilityValidConnect, filter); 235 RUN_TEST_WITH_REFERENCE_CHECK(UtilityInvalidClose, filter); 236 RUN_TEST_WITH_REFERENCE_CHECK(UtilityValidClose, filter); 237 RUN_TEST_WITH_REFERENCE_CHECK(UtilityGetProtocol, filter); 238 RUN_TEST_WITH_REFERENCE_CHECK(UtilityTextSendReceive, filter); 239 RUN_TEST_WITH_REFERENCE_CHECK(UtilityBinarySendReceive, filter); 240 RUN_TEST_WITH_REFERENCE_CHECK(UtilityBufferedAmount, filter); 241 } 242 243 std::string TestWebSocket::GetFullURL(const char* url) { 244 std::string rv = "ws://"; 245 // Some WebSocket tests don't start the server so there'll be no host and 246 // port. 247 if (instance_->websocket_host().empty()) 248 rv += "127.0.0.1"; 249 else 250 rv += instance_->websocket_host(); 251 if (instance_->websocket_port() != -1) { 252 char buffer[10]; 253 sprintf(buffer, ":%d", instance_->websocket_port()); 254 rv += std::string(buffer); 255 } 256 rv += "/"; 257 rv += url; 258 return rv; 259 } 260 261 PP_Var TestWebSocket::CreateVarString(const std::string& string) { 262 return var_interface_->VarFromUtf8(string.c_str(), string.size()); 263 } 264 265 PP_Var TestWebSocket::CreateVarBinary(const std::vector<uint8_t>& binary) { 266 PP_Var var = arraybuffer_interface_->Create(binary.size()); 267 uint8_t* var_data = static_cast<uint8_t*>(arraybuffer_interface_->Map(var)); 268 std::copy(binary.begin(), binary.end(), var_data); 269 return var; 270 } 271 272 void TestWebSocket::ReleaseVar(const PP_Var& var) { 273 var_interface_->Release(var); 274 } 275 276 bool TestWebSocket::AreEqualWithString(const PP_Var& var, 277 const std::string& string) { 278 if (var.type != PP_VARTYPE_STRING) 279 return false; 280 uint32_t utf8_length; 281 const char* utf8 = var_interface_->VarToUtf8(var, &utf8_length); 282 if (utf8_length != string.size()) 283 return false; 284 if (string.compare(utf8)) 285 return false; 286 return true; 287 } 288 289 bool TestWebSocket::AreEqualWithBinary(const PP_Var& var, 290 const std::vector<uint8_t>& binary) { 291 uint32_t buffer_size = 0; 292 PP_Bool success = arraybuffer_interface_->ByteLength(var, &buffer_size); 293 if (!success || buffer_size != binary.size()) 294 return false; 295 if (!std::equal(binary.begin(), binary.end(), 296 static_cast<uint8_t*>(arraybuffer_interface_->Map(var)))) 297 return false; 298 return true; 299 } 300 301 PP_Resource TestWebSocket::Connect(const std::string& url, 302 int32_t* result, 303 const std::string& protocol) { 304 PP_Var protocols[] = { PP_MakeUndefined() }; 305 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance()); 306 if (!ws) 307 return 0; 308 PP_Var url_var = CreateVarString(url); 309 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 310 uint32_t protocol_count = 0U; 311 if (protocol.size()) { 312 protocols[0] = CreateVarString(protocol); 313 protocol_count = 1U; 314 } 315 callback.WaitForResult(websocket_interface_->Connect( 316 ws, url_var, protocols, protocol_count, 317 callback.GetCallback().pp_completion_callback())); 318 ReleaseVar(url_var); 319 if (protocol.size()) 320 ReleaseVar(protocols[0]); 321 *result = callback.result(); 322 return ws; 323 } 324 325 void TestWebSocket::Send(int32_t /* result */, PP_Resource ws, 326 const std::string& message) { 327 PP_Var message_var = CreateVarString(message); 328 websocket_interface_->SendMessage(ws, message_var); 329 ReleaseVar(message_var); 330 } 331 332 std::string TestWebSocket::TestIsWebSocket() { 333 // Test that a NULL resource isn't a websocket. 334 pp::Resource null_resource; 335 PP_Bool result = 336 websocket_interface_->IsWebSocket(null_resource.pp_resource()); 337 ASSERT_FALSE(result); 338 339 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance()); 340 ASSERT_TRUE(ws); 341 342 result = websocket_interface_->IsWebSocket(ws); 343 ASSERT_TRUE(result); 344 345 core_interface_->ReleaseResource(ws); 346 347 PASS(); 348 } 349 350 std::string TestWebSocket::TestUninitializedPropertiesAccess() { 351 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance()); 352 ASSERT_TRUE(ws); 353 354 uint64_t bufferedAmount = websocket_interface_->GetBufferedAmount(ws); 355 ASSERT_EQ(0U, bufferedAmount); 356 357 uint16_t close_code = websocket_interface_->GetCloseCode(ws); 358 ASSERT_EQ(0U, close_code); 359 360 PP_Var close_reason = websocket_interface_->GetCloseReason(ws); 361 ASSERT_TRUE(AreEqualWithString(close_reason, std::string())); 362 ReleaseVar(close_reason); 363 364 PP_Bool close_was_clean = websocket_interface_->GetCloseWasClean(ws); 365 ASSERT_EQ(PP_FALSE, close_was_clean); 366 367 PP_Var extensions = websocket_interface_->GetExtensions(ws); 368 ASSERT_TRUE(AreEqualWithString(extensions, std::string())); 369 ReleaseVar(extensions); 370 371 PP_Var protocol = websocket_interface_->GetProtocol(ws); 372 ASSERT_TRUE(AreEqualWithString(protocol, std::string())); 373 ReleaseVar(protocol); 374 375 PP_WebSocketReadyState ready_state = 376 websocket_interface_->GetReadyState(ws); 377 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID, ready_state); 378 379 PP_Var url = websocket_interface_->GetURL(ws); 380 ASSERT_TRUE(AreEqualWithString(url, std::string())); 381 ReleaseVar(url); 382 383 core_interface_->ReleaseResource(ws); 384 385 PASS(); 386 } 387 388 std::string TestWebSocket::TestInvalidConnect() { 389 PP_Var protocols[] = { PP_MakeUndefined() }; 390 391 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance()); 392 ASSERT_TRUE(ws); 393 394 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 395 callback.WaitForResult(websocket_interface_->Connect( 396 ws, PP_MakeUndefined(), protocols, 1U, 397 callback.GetCallback().pp_completion_callback())); 398 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); 399 400 callback.WaitForResult(websocket_interface_->Connect( 401 ws, PP_MakeUndefined(), protocols, 1U, 402 callback.GetCallback().pp_completion_callback())); 403 ASSERT_EQ(PP_ERROR_INPROGRESS, callback.result()); 404 405 core_interface_->ReleaseResource(ws); 406 407 for (int i = 0; kInvalidURLs[i]; ++i) { 408 int32_t result; 409 ws = Connect(kInvalidURLs[i], &result, std::string()); 410 ASSERT_TRUE(ws); 411 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); 412 413 core_interface_->ReleaseResource(ws); 414 } 415 416 PASS(); 417 } 418 419 std::string TestWebSocket::TestProtocols() { 420 PP_Var url = CreateVarString(GetFullURL(kEchoServerURL).c_str()); 421 PP_Var bad_protocols[] = { 422 CreateVarString("x-test"), 423 CreateVarString("x-test") 424 }; 425 PP_Var good_protocols[] = { 426 CreateVarString("x-test"), 427 CreateVarString("x-yatest") 428 }; 429 430 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance()); 431 ASSERT_TRUE(ws); 432 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 433 callback.WaitForResult(websocket_interface_->Connect( 434 ws, url, bad_protocols, 2U, 435 callback.GetCallback().pp_completion_callback())); 436 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); 437 core_interface_->ReleaseResource(ws); 438 439 ws = websocket_interface_->Create(instance_->pp_instance()); 440 ASSERT_TRUE(ws); 441 int32_t result = websocket_interface_->Connect( 442 ws, url, good_protocols, 2U, PP_BlockUntilComplete()); 443 ASSERT_EQ(PP_ERROR_BLOCKS_MAIN_THREAD, result); 444 core_interface_->ReleaseResource(ws); 445 446 ReleaseVar(url); 447 for (int i = 0; i < 2; ++i) { 448 ReleaseVar(bad_protocols[i]); 449 ReleaseVar(good_protocols[i]); 450 } 451 core_interface_->ReleaseResource(ws); 452 453 PASS(); 454 } 455 456 std::string TestWebSocket::TestGetURL() { 457 for (int i = 0; kInvalidURLs[i]; ++i) { 458 int32_t result; 459 PP_Resource ws = Connect(kInvalidURLs[i], &result, std::string()); 460 ASSERT_TRUE(ws); 461 PP_Var url = websocket_interface_->GetURL(ws); 462 ASSERT_TRUE(AreEqualWithString(url, kInvalidURLs[i])); 463 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); 464 465 ReleaseVar(url); 466 core_interface_->ReleaseResource(ws); 467 } 468 469 PASS(); 470 } 471 472 std::string TestWebSocket::TestValidConnect() { 473 int32_t result; 474 PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 475 ASSERT_TRUE(ws); 476 ASSERT_EQ(PP_OK, result); 477 PP_Var extensions = websocket_interface_->GetExtensions(ws); 478 ASSERT_TRUE(AreEqualWithString(extensions, std::string())); 479 core_interface_->ReleaseResource(ws); 480 ReleaseVar(extensions); 481 482 PASS(); 483 } 484 485 std::string TestWebSocket::TestInvalidClose() { 486 PP_Var reason = CreateVarString("close for test"); 487 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 488 TestCompletionCallback async_callback(instance_->pp_instance(), PP_REQUIRED); 489 490 // Close before connect. 491 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance()); 492 callback.WaitForResult(websocket_interface_->Close( 493 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 494 callback.GetCallback().pp_completion_callback())); 495 ASSERT_EQ(PP_ERROR_FAILED, callback.result()); 496 core_interface_->ReleaseResource(ws); 497 498 // Close with bad arguments. 499 int32_t result; 500 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 501 ASSERT_TRUE(ws); 502 ASSERT_EQ(PP_OK, result); 503 callback.WaitForResult(websocket_interface_->Close( 504 ws, 1U, reason, callback.GetCallback().pp_completion_callback())); 505 ASSERT_EQ(PP_ERROR_NOACCESS, callback.result()); 506 core_interface_->ReleaseResource(ws); 507 508 // Close with PP_VARTYPE_NULL. 509 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 510 ASSERT_TRUE(ws); 511 ASSERT_EQ(PP_OK, result); 512 callback.WaitForResult(websocket_interface_->Close( 513 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeNull(), 514 callback.GetCallback().pp_completion_callback())); 515 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); 516 core_interface_->ReleaseResource(ws); 517 518 // Close with PP_VARTYPE_NULL and ongoing receive message. 519 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 520 ASSERT_TRUE(ws); 521 ASSERT_EQ(PP_OK, result); 522 PP_Var receive_message_var; 523 result = websocket_interface_->ReceiveMessage( 524 ws, &receive_message_var, 525 async_callback.GetCallback().pp_completion_callback()); 526 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 527 callback.WaitForResult(websocket_interface_->Close( 528 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeNull(), 529 callback.GetCallback().pp_completion_callback())); 530 ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result()); 531 const char* send_message = "hi"; 532 PP_Var send_message_var = CreateVarString(send_message); 533 result = websocket_interface_->SendMessage(ws, send_message_var); 534 ReleaseVar(send_message_var); 535 ASSERT_EQ(PP_OK, result); 536 async_callback.WaitForResult(PP_OK_COMPLETIONPENDING); 537 ASSERT_EQ(PP_OK, async_callback.result()); 538 ASSERT_TRUE(AreEqualWithString(receive_message_var, send_message)); 539 ReleaseVar(receive_message_var); 540 core_interface_->ReleaseResource(ws); 541 542 // Close twice. 543 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 544 ASSERT_TRUE(ws); 545 ASSERT_EQ(PP_OK, result); 546 result = websocket_interface_->Close( 547 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 548 async_callback.GetCallback().pp_completion_callback()); 549 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 550 // Call another Close() before previous one is in progress. 551 result = websocket_interface_->Close( 552 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 553 callback.GetCallback().pp_completion_callback()); 554 ASSERT_EQ(PP_ERROR_INPROGRESS, result); 555 async_callback.WaitForResult(PP_OK_COMPLETIONPENDING); 556 ASSERT_EQ(PP_OK, async_callback.result()); 557 // Call another Close() after previous one is completed. 558 // This Close() must do nothing and reports no error. 559 callback.WaitForResult(websocket_interface_->Close( 560 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 561 callback.GetCallback().pp_completion_callback())); 562 ASSERT_EQ(PP_OK, callback.result()); 563 core_interface_->ReleaseResource(ws); 564 565 ReleaseVar(reason); 566 567 PASS(); 568 } 569 570 // TODO(tyoshino): Consider splitting this test into smaller ones. 571 // http://crbug.com/397035 572 std::string TestWebSocket::TestValidClose() { 573 PP_Var reason = CreateVarString("close for test"); 574 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 575 TestCompletionCallback another_callback( 576 instance_->pp_instance(), callback_type()); 577 578 // Close. 579 int32_t result; 580 PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 581 ASSERT_TRUE(ws); 582 ASSERT_EQ(PP_OK, result); 583 callback.WaitForResult(websocket_interface_->Close( 584 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 585 callback.GetCallback().pp_completion_callback())); 586 CHECK_CALLBACK_BEHAVIOR(callback); 587 ASSERT_EQ(PP_OK, callback.result()); 588 core_interface_->ReleaseResource(ws); 589 590 // Close without code and reason. 591 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 592 ASSERT_TRUE(ws); 593 ASSERT_EQ(PP_OK, result); 594 callback.WaitForResult(websocket_interface_->Close( 595 ws, PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED, reason, 596 callback.GetCallback().pp_completion_callback())); 597 CHECK_CALLBACK_BEHAVIOR(callback); 598 ASSERT_EQ(PP_OK, callback.result()); 599 core_interface_->ReleaseResource(ws); 600 601 // Close with PP_VARTYPE_UNDEFINED. 602 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 603 ASSERT_TRUE(ws); 604 ASSERT_EQ(PP_OK, result); 605 callback.WaitForResult(websocket_interface_->Close( 606 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(), 607 callback.GetCallback().pp_completion_callback())); 608 CHECK_CALLBACK_BEHAVIOR(callback); 609 ASSERT_EQ(PP_OK, callback.result()); 610 core_interface_->ReleaseResource(ws); 611 612 // Close in CONNECTING state. 613 // The ongoing Connect() fails with PP_ERROR_ABORTED, then the Close() 614 // completes successfully. 615 ws = websocket_interface_->Create(instance_->pp_instance()); 616 PP_Var url = CreateVarString(GetFullURL(kEchoServerURL).c_str()); 617 PP_Var protocols[] = { PP_MakeUndefined() }; 618 result = websocket_interface_->Connect( 619 ws, url, protocols, 0U, callback.GetCallback().pp_completion_callback()); 620 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 621 result = websocket_interface_->Close( 622 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 623 another_callback.GetCallback().pp_completion_callback()); 624 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 625 callback.WaitForResult(PP_OK_COMPLETIONPENDING); 626 ASSERT_EQ(PP_ERROR_ABORTED, callback.result()); 627 another_callback.WaitForResult(PP_OK_COMPLETIONPENDING); 628 ASSERT_EQ(PP_OK, another_callback.result()); 629 core_interface_->ReleaseResource(ws); 630 ReleaseVar(url); 631 632 // Close while already closing. 633 // The first Close will succeed, and the second one will synchronously fail 634 // with PP_ERROR_INPROGRESS. 635 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 636 ASSERT_TRUE(ws); 637 ASSERT_EQ(PP_OK, result); 638 result = websocket_interface_->Close( 639 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 640 callback.GetCallback().pp_completion_callback()); 641 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 642 result = websocket_interface_->Close( 643 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 644 another_callback.GetCallback().pp_completion_callback()); 645 ASSERT_EQ(PP_ERROR_INPROGRESS, result); 646 callback.WaitForResult(PP_OK_COMPLETIONPENDING); 647 ASSERT_EQ(PP_OK, callback.result()); 648 core_interface_->ReleaseResource(ws); 649 650 // Close with ongoing ReceiveMessage. 651 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 652 ASSERT_TRUE(ws); 653 ASSERT_EQ(PP_OK, result); 654 PP_Var receive_message_var; 655 result = websocket_interface_->ReceiveMessage( 656 ws, &receive_message_var, 657 callback.GetCallback().pp_completion_callback()); 658 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 659 result = websocket_interface_->Close( 660 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 661 another_callback.GetCallback().pp_completion_callback()); 662 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 663 callback.WaitForResult(PP_OK_COMPLETIONPENDING); 664 ASSERT_EQ(PP_ERROR_ABORTED, callback.result()); 665 another_callback.WaitForResult(PP_OK_COMPLETIONPENDING); 666 ASSERT_EQ(PP_OK, another_callback.result()); 667 core_interface_->ReleaseResource(ws); 668 669 // Close with PP_VARTYPE_UNDEFINED for reason and ongoing ReceiveMessage. 670 ws = Connect(GetFullURL(kEchoServerURL), &result, std::string()); 671 ASSERT_TRUE(ws); 672 ASSERT_EQ(PP_OK, result); 673 result = websocket_interface_->ReceiveMessage( 674 ws, &receive_message_var, 675 callback.GetCallback().pp_completion_callback()); 676 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 677 result = websocket_interface_->Close( 678 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(), 679 another_callback.GetCallback().pp_completion_callback()); 680 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 681 callback.WaitForResult(PP_OK_COMPLETIONPENDING); 682 ASSERT_EQ(PP_ERROR_ABORTED, callback.result()); 683 another_callback.WaitForResult(PP_OK_COMPLETIONPENDING); 684 ASSERT_EQ(PP_OK, another_callback.result()); 685 core_interface_->ReleaseResource(ws); 686 687 // Server initiated closing handshake. 688 ws = Connect( 689 GetFullURL(kCloseWithCodeAndReasonServerURL), &result, std::string()); 690 ASSERT_TRUE(ws); 691 ASSERT_EQ(PP_OK, result); 692 // Text messsage "1000 bye" requests the server to initiate closing handshake 693 // with code being 1000 and reason being "bye". 694 PP_Var close_request_var = CreateVarString("1000 bye"); 695 result = websocket_interface_->SendMessage(ws, close_request_var); 696 ReleaseVar(close_request_var); 697 callback.WaitForResult(websocket_interface_->ReceiveMessage( 698 ws, &receive_message_var, 699 callback.GetCallback().pp_completion_callback())); 700 ASSERT_EQ(PP_ERROR_FAILED, callback.result()); 701 core_interface_->ReleaseResource(ws); 702 703 ReleaseVar(reason); 704 705 PASS(); 706 } 707 708 std::string TestWebSocket::TestGetProtocol() { 709 const char* expected_protocols[] = { 710 "x-chat", 711 "hoehoe", 712 NULL 713 }; 714 for (int i = 0; expected_protocols[i]; ++i) { 715 std::string url(GetFullURL(kProtocolTestServerURL)); 716 url += expected_protocols[i]; 717 int32_t result; 718 PP_Resource ws = Connect(url.c_str(), &result, expected_protocols[i]); 719 ASSERT_TRUE(ws); 720 ASSERT_EQ(PP_OK, result); 721 722 PP_Var protocol = websocket_interface_->GetProtocol(ws); 723 ASSERT_TRUE(AreEqualWithString(protocol, expected_protocols[i])); 724 725 ReleaseVar(protocol); 726 core_interface_->ReleaseResource(ws); 727 } 728 729 PASS(); 730 } 731 732 std::string TestWebSocket::TestTextSendReceive() { 733 // Connect to test echo server. 734 int32_t connect_result; 735 PP_Resource ws = 736 Connect(GetFullURL(kEchoServerURL), &connect_result, std::string()); 737 ASSERT_TRUE(ws); 738 ASSERT_EQ(PP_OK, connect_result); 739 740 // Send 'hello pepper' text message. 741 const char* message = "hello pepper"; 742 PP_Var message_var = CreateVarString(message); 743 int32_t result = websocket_interface_->SendMessage(ws, message_var); 744 ReleaseVar(message_var); 745 ASSERT_EQ(PP_OK, result); 746 747 // Receive echoed 'hello pepper'. 748 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 749 PP_Var received_message; 750 callback.WaitForResult(websocket_interface_->ReceiveMessage( 751 ws, &received_message, callback.GetCallback().pp_completion_callback())); 752 ASSERT_EQ(PP_OK, callback.result()); 753 ASSERT_TRUE(AreEqualWithString(received_message, message)); 754 ReleaseVar(received_message); 755 core_interface_->ReleaseResource(ws); 756 757 PASS(); 758 } 759 760 // Run as a BACKGROUND test. 761 std::string TestWebSocket::TestTextSendReceiveTwice() { 762 // Connect to test echo server. 763 int32_t connect_result; 764 PP_Resource ws = 765 Connect(GetFullURL(kEchoServerURL), &connect_result, std::string()); 766 ASSERT_TRUE(ws); 767 ASSERT_EQ(PP_OK, connect_result); 768 pp::MessageLoop message_loop = pp::MessageLoop::GetCurrent(); 769 pp::CompletionCallbackFactory<TestWebSocket> factory(this); 770 771 message_loop.PostWork(factory.NewCallback(&TestWebSocket::Send, 772 ws, std::string("hello"))); 773 // When the server receives 'Goodbye', it closes the session. 774 message_loop.PostWork(factory.NewCallback(&TestWebSocket::Send, 775 ws, std::string("Goodbye"))); 776 message_loop.PostQuit(false); 777 message_loop.Run(); 778 779 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 780 PP_Var received_message; 781 int32_t result = websocket_interface_->ReceiveMessage( 782 ws, &received_message, callback.GetCallback().pp_completion_callback()); 783 ASSERT_EQ(PP_OK, result); 784 // Since we don't run the message loop, the callback will stay 785 // "pending and scheduled to run" state. 786 787 // Waiting for the connection close which will be done by the server. 788 while (true) { 789 PP_WebSocketReadyState ready_state = 790 websocket_interface_->GetReadyState(ws); 791 if (ready_state != PP_WEBSOCKETREADYSTATE_CONNECTING && 792 ready_state != PP_WEBSOCKETREADYSTATE_OPEN) { 793 break; 794 } 795 PlatformSleep(100); // 100ms 796 } 797 798 // Cleanup the message loop 799 message_loop.PostQuit(false); 800 message_loop.Run(); 801 802 ASSERT_EQ(PP_OK, callback.result()); 803 ASSERT_TRUE(AreEqualWithString(received_message, "hello")); 804 ReleaseVar(received_message); 805 core_interface_->ReleaseResource(ws); 806 PASS(); 807 } 808 809 std::string TestWebSocket::TestBinarySendReceive() { 810 // Connect to test echo server. 811 int32_t connect_result; 812 PP_Resource ws = 813 Connect(GetFullURL(kEchoServerURL), &connect_result, std::string()); 814 ASSERT_TRUE(ws); 815 ASSERT_EQ(PP_OK, connect_result); 816 817 // Send binary message. 818 std::vector<uint8_t> binary(256); 819 for (uint32_t i = 0; i < binary.size(); ++i) 820 binary[i] = i; 821 PP_Var message_var = CreateVarBinary(binary); 822 int32_t result = websocket_interface_->SendMessage(ws, message_var); 823 ReleaseVar(message_var); 824 ASSERT_EQ(PP_OK, result); 825 826 // Receive echoed binary. 827 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 828 PP_Var received_message; 829 callback.WaitForResult(websocket_interface_->ReceiveMessage( 830 ws, &received_message, callback.GetCallback().pp_completion_callback())); 831 ASSERT_EQ(PP_OK, callback.result()); 832 ASSERT_TRUE(AreEqualWithBinary(received_message, binary)); 833 ReleaseVar(received_message); 834 core_interface_->ReleaseResource(ws); 835 836 PASS(); 837 } 838 839 std::string TestWebSocket::TestStressedSendReceive() { 840 // Connect to test echo server. 841 int32_t connect_result; 842 PP_Resource ws = 843 Connect(GetFullURL(kEchoServerURL), &connect_result, std::string()); 844 ASSERT_TRUE(ws); 845 ASSERT_EQ(PP_OK, connect_result); 846 847 // Prepare PP_Var objects to send. 848 const char* text = "hello pepper"; 849 PP_Var text_var = CreateVarString(text); 850 std::vector<uint8_t> binary(256); 851 for (uint32_t i = 0; i < binary.size(); ++i) 852 binary[i] = i; 853 PP_Var binary_var = CreateVarBinary(binary); 854 // Prepare very large binary data over 64KiB. Object serializer in 855 // ppapi_proxy has a limitation of 64KiB as maximum return PP_Var data size 856 // to SRPC. In case received data over 64KiB exists, a specific code handles 857 // this large data via asynchronous callback from main thread. This data 858 // intends to test the code. 859 std::vector<uint8_t> large_binary(65 * 1024); 860 for (uint32_t i = 0; i < large_binary.size(); ++i) 861 large_binary[i] = i & 0xff; 862 PP_Var large_binary_var = CreateVarBinary(large_binary); 863 864 // Send many messages. 865 int32_t result; 866 for (int i = 0; i < 256; ++i) { 867 result = websocket_interface_->SendMessage(ws, text_var); 868 ASSERT_EQ(PP_OK, result); 869 result = websocket_interface_->SendMessage(ws, binary_var); 870 ASSERT_EQ(PP_OK, result); 871 } 872 result = websocket_interface_->SendMessage(ws, large_binary_var); 873 ASSERT_EQ(PP_OK, result); 874 ReleaseVar(text_var); 875 ReleaseVar(binary_var); 876 ReleaseVar(large_binary_var); 877 878 // Receive echoed data. 879 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 880 for (int i = 0; i <= 512; ++i) { 881 PP_Var received_message; 882 callback.WaitForResult(websocket_interface_->ReceiveMessage( 883 ws, &received_message, 884 callback.GetCallback().pp_completion_callback())); 885 ASSERT_EQ(PP_OK, callback.result()); 886 if (i == 512) { 887 ASSERT_TRUE(AreEqualWithBinary(received_message, large_binary)); 888 } else if (i & 1) { 889 ASSERT_TRUE(AreEqualWithBinary(received_message, binary)); 890 } else { 891 ASSERT_TRUE(AreEqualWithString(received_message, text)); 892 } 893 ReleaseVar(received_message); 894 } 895 core_interface_->ReleaseResource(ws); 896 897 PASS(); 898 } 899 900 std::string TestWebSocket::TestBufferedAmount() { 901 // Connect to test echo server. 902 int32_t connect_result; 903 PP_Resource ws = 904 Connect(GetFullURL(kEchoServerURL), &connect_result, std::string()); 905 ASSERT_TRUE(ws); 906 ASSERT_EQ(PP_OK, connect_result); 907 908 // Prepare a large message that is not aligned with the internal buffer 909 // sizes. 910 std::string message(8193, 'x'); 911 PP_Var message_var = CreateVarString(message); 912 913 uint64_t buffered_amount = 0; 914 int32_t result; 915 for (int i = 0; i < 100; i++) { 916 result = websocket_interface_->SendMessage(ws, message_var); 917 ASSERT_EQ(PP_OK, result); 918 buffered_amount = websocket_interface_->GetBufferedAmount(ws); 919 // Buffered amount size 262144 is too big for the internal buffer size. 920 if (buffered_amount > 262144) 921 break; 922 } 923 924 // Close connection. 925 std::string reason_str = "close while busy"; 926 PP_Var reason = CreateVarString(reason_str.c_str()); 927 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 928 result = websocket_interface_->Close( 929 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason, 930 callback.GetCallback().pp_completion_callback()); 931 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 932 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING, 933 websocket_interface_->GetReadyState(ws)); 934 935 callback.WaitForResult(result); 936 ASSERT_EQ(PP_OK, callback.result()); 937 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED, 938 websocket_interface_->GetReadyState(ws)); 939 940 uint64_t base_buffered_amount = websocket_interface_->GetBufferedAmount(ws); 941 942 // After connection closure, all sending requests fail and just increase 943 // the bufferedAmount property. 944 PP_Var empty_string = CreateVarString(std::string()); 945 result = websocket_interface_->SendMessage(ws, empty_string); 946 ASSERT_EQ(PP_ERROR_FAILED, result); 947 buffered_amount = websocket_interface_->GetBufferedAmount(ws); 948 ASSERT_EQ(base_buffered_amount + kMessageFrameOverhead, buffered_amount); 949 base_buffered_amount = buffered_amount; 950 951 result = websocket_interface_->SendMessage(ws, reason); 952 ASSERT_EQ(PP_ERROR_FAILED, result); 953 buffered_amount = websocket_interface_->GetBufferedAmount(ws); 954 uint64_t reason_frame_size = kMessageFrameOverhead + reason_str.length(); 955 ASSERT_EQ(base_buffered_amount + reason_frame_size, buffered_amount); 956 957 ReleaseVar(message_var); 958 ReleaseVar(reason); 959 ReleaseVar(empty_string); 960 core_interface_->ReleaseResource(ws); 961 962 PASS(); 963 } 964 965 // Test abort behaviors where a WebSocket PP_Resource is released while each 966 // function is in-flight on the WebSocket PP_Resource. 967 std::string TestWebSocket::TestAbortCallsWithCallback() { 968 // Following tests make sure the behavior for functions which require a 969 // callback. The callback must get a PP_ERROR_ABORTED. 970 971 // Test the behavior for Connect(). 972 PP_Resource ws = websocket_interface_->Create(instance_->pp_instance()); 973 ASSERT_TRUE(ws); 974 std::string url = GetFullURL(kEchoServerURL); 975 PP_Var url_var = CreateVarString(url); 976 TestCompletionCallback connect_callback( 977 instance_->pp_instance(), callback_type()); 978 int32_t result = websocket_interface_->Connect( 979 ws, url_var, NULL, 0, 980 connect_callback.GetCallback().pp_completion_callback()); 981 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 982 core_interface_->ReleaseResource(ws); 983 connect_callback.WaitForResult(result); 984 ASSERT_EQ(PP_ERROR_ABORTED, connect_callback.result()); 985 986 // Test the behavior for Close(). 987 ws = Connect(url, &result, std::string()); 988 ASSERT_TRUE(ws); 989 ASSERT_EQ(PP_OK, result); 990 PP_Var reason_var = CreateVarString("abort"); 991 TestCompletionCallback close_callback( 992 instance_->pp_instance(), callback_type()); 993 result = websocket_interface_->Close( 994 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason_var, 995 close_callback.GetCallback().pp_completion_callback()); 996 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 997 core_interface_->ReleaseResource(ws); 998 close_callback.WaitForResult(result); 999 ASSERT_EQ(PP_ERROR_ABORTED, close_callback.result()); 1000 ReleaseVar(reason_var); 1001 1002 // Test the behavior for ReceiveMessage(). 1003 // Make sure the simplest case to wait for data which never arrives, here. 1004 ws = Connect(url, &result, std::string()); 1005 ASSERT_TRUE(ws); 1006 ASSERT_EQ(PP_OK, result); 1007 PP_Var receive_var; 1008 TestCompletionCallback receive_callback( 1009 instance_->pp_instance(), callback_type()); 1010 result = websocket_interface_->ReceiveMessage( 1011 ws, &receive_var, 1012 receive_callback.GetCallback().pp_completion_callback()); 1013 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1014 core_interface_->ReleaseResource(ws); 1015 receive_callback.WaitForResult(result); 1016 ASSERT_EQ(PP_ERROR_ABORTED, receive_callback.result()); 1017 1018 // Release the resource in the aborting receive completion callback which is 1019 // introduced by calling Close(). 1020 ws = Connect(url, &result, std::string()); 1021 ASSERT_TRUE(ws); 1022 ASSERT_EQ(PP_OK, result); 1023 result = websocket_interface_->ReceiveMessage( 1024 ws, &receive_var, 1025 receive_callback.GetCallback().pp_completion_callback()); 1026 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1027 ReleaseResourceDelegate receive_delegate(core_interface_, ws); 1028 receive_callback.SetDelegate(&receive_delegate); 1029 result = websocket_interface_->Close( 1030 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(), 1031 close_callback.GetCallback().pp_completion_callback()); 1032 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1033 receive_callback.WaitForResult(result); 1034 CHECK_CALLBACK_BEHAVIOR(receive_callback); 1035 ASSERT_EQ(PP_ERROR_ABORTED, receive_callback.result()); 1036 close_callback.WaitForResult(result); 1037 CHECK_CALLBACK_BEHAVIOR(close_callback); 1038 ASSERT_EQ(PP_ERROR_ABORTED, close_callback.result()); 1039 1040 ReleaseVar(url_var); 1041 1042 PASS(); 1043 } 1044 1045 std::string TestWebSocket::TestAbortSendMessageCall() { 1046 // Test the behavior for SendMessage(). 1047 // This function doesn't require a callback, but operation will be done 1048 // asynchronously in WebKit and browser process. 1049 std::vector<uint8_t> large_binary(65 * 1024); 1050 PP_Var large_var = CreateVarBinary(large_binary); 1051 1052 int32_t result; 1053 std::string url = GetFullURL(kEchoServerURL); 1054 PP_Resource ws = Connect(url, &result, std::string()); 1055 ASSERT_TRUE(ws); 1056 ASSERT_EQ(PP_OK, result); 1057 result = websocket_interface_->SendMessage(ws, large_var); 1058 ASSERT_EQ(PP_OK, result); 1059 core_interface_->ReleaseResource(ws); 1060 ReleaseVar(large_var); 1061 1062 PASS(); 1063 } 1064 1065 std::string TestWebSocket::TestAbortCloseCall() { 1066 // Release the resource in the close completion callback. 1067 int32_t result; 1068 std::string url = GetFullURL(kEchoServerURL); 1069 PP_Resource ws = Connect(url, &result, std::string()); 1070 ASSERT_TRUE(ws); 1071 ASSERT_EQ(PP_OK, result); 1072 TestCompletionCallback close_callback( 1073 instance_->pp_instance(), callback_type()); 1074 result = websocket_interface_->Close( 1075 ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(), 1076 close_callback.GetCallback().pp_completion_callback()); 1077 ReleaseResourceDelegate close_delegate(core_interface_, ws); 1078 close_callback.SetDelegate(&close_delegate); 1079 close_callback.WaitForResult(result); 1080 CHECK_CALLBACK_BEHAVIOR(close_callback); 1081 ASSERT_EQ(PP_OK, close_callback.result()); 1082 1083 PASS(); 1084 } 1085 1086 std::string TestWebSocket::TestAbortReceiveMessageCall() { 1087 // Test the behavior where receive process might be in-flight. 1088 std::vector<uint8_t> large_binary(65 * 1024); 1089 PP_Var large_var = CreateVarBinary(large_binary); 1090 const char* text = "yukarin"; 1091 PP_Var text_var = CreateVarString(text); 1092 1093 std::string url = GetFullURL(kEchoServerURL); 1094 int32_t result; 1095 PP_Resource ws; 1096 1097 // Each trial sends |trial_count| + 1 messages and receives just |trial| 1098 // number of message(s) before releasing the WebSocket. The WebSocket is 1099 // released while the next message is going to be received. 1100 const int trial_count = 8; 1101 for (int trial = 1; trial <= trial_count; trial++) { 1102 ws = Connect(url, &result, std::string()); 1103 ASSERT_TRUE(ws); 1104 ASSERT_EQ(PP_OK, result); 1105 for (int i = 0; i <= trial_count; ++i) { 1106 result = websocket_interface_->SendMessage(ws, text_var); 1107 ASSERT_EQ(PP_OK, result); 1108 } 1109 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 1110 PP_Var var; 1111 for (int i = 0; i < trial; ++i) { 1112 callback.WaitForResult(websocket_interface_->ReceiveMessage( 1113 ws, &var, callback.GetCallback().pp_completion_callback())); 1114 ASSERT_EQ(PP_OK, callback.result()); 1115 ASSERT_TRUE(AreEqualWithString(var, text)); 1116 ReleaseVar(var); 1117 } 1118 result = websocket_interface_->ReceiveMessage( 1119 ws, &var, callback.GetCallback().pp_completion_callback()); 1120 core_interface_->ReleaseResource(ws); 1121 if (result != PP_OK) { 1122 callback.WaitForResult(result); 1123 ASSERT_EQ(PP_ERROR_ABORTED, callback.result()); 1124 } 1125 } 1126 // Same test, but the last receiving message is large message over 64KiB. 1127 for (int trial = 1; trial <= trial_count; trial++) { 1128 ws = Connect(url, &result, std::string()); 1129 ASSERT_TRUE(ws); 1130 ASSERT_EQ(PP_OK, result); 1131 for (int i = 0; i <= trial_count; ++i) { 1132 if (i == trial) 1133 result = websocket_interface_->SendMessage(ws, large_var); 1134 else 1135 result = websocket_interface_->SendMessage(ws, text_var); 1136 ASSERT_EQ(PP_OK, result); 1137 } 1138 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 1139 PP_Var var; 1140 for (int i = 0; i < trial; ++i) { 1141 callback.WaitForResult(websocket_interface_->ReceiveMessage( 1142 ws, &var, callback.GetCallback().pp_completion_callback())); 1143 ASSERT_EQ(PP_OK, callback.result()); 1144 ASSERT_TRUE(AreEqualWithString(var, text)); 1145 ReleaseVar(var); 1146 } 1147 result = websocket_interface_->ReceiveMessage( 1148 ws, &var, callback.GetCallback().pp_completion_callback()); 1149 core_interface_->ReleaseResource(ws); 1150 if (result != PP_OK) { 1151 callback.WaitForResult(result); 1152 ASSERT_EQ(PP_ERROR_ABORTED, callback.result()); 1153 } 1154 } 1155 1156 ReleaseVar(large_var); 1157 ReleaseVar(text_var); 1158 1159 PASS(); 1160 } 1161 1162 std::string TestWebSocket::TestClosedFromServerWhileSending() { 1163 // Connect to test echo server. 1164 const pp::Var protocols[] = { pp::Var() }; 1165 TestWebSocketAPI websocket(instance_); 1166 int32_t result = 1167 websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U); 1168 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1169 websocket.WaitForConnected(); 1170 1171 result = websocket.Send(pp::Var("hello")); 1172 ASSERT_EQ(PP_OK, result); 1173 result = websocket.Send(pp::Var("Goodbye")); 1174 // We send many messages so that PepperWebSocketHost::SendText is called 1175 // after PepperWebSocketHost::didClose is called. 1176 // Note: We must not wait for CLOSED event here because 1177 // WebSocketResource::SendMessage doesn't call PepperWebSocketHost::SendText 1178 // when its internal state is CLOSING or CLOSED. We want to test if the 1179 // pepper WebSocket works well when WebSocketResource is OPEN and 1180 // PepperWebSocketHost is CLOSED. 1181 for (size_t i = 0; i < 10000; ++i) { 1182 result = websocket.Send(pp::Var("")); 1183 ASSERT_EQ(PP_OK, result); 1184 } 1185 1186 PASS(); 1187 } 1188 1189 std::string TestWebSocket::TestCcInterfaces() { 1190 // C++ bindings is simple straightforward, then just verifies interfaces work 1191 // as a interface bridge fine. 1192 pp::WebSocket ws(instance_); 1193 1194 // Check uninitialized properties access. 1195 ASSERT_EQ(0, ws.GetBufferedAmount()); 1196 ASSERT_EQ(0, ws.GetCloseCode()); 1197 ASSERT_TRUE(AreEqualWithString(ws.GetCloseReason().pp_var(), std::string())); 1198 ASSERT_FALSE(ws.GetCloseWasClean()); 1199 ASSERT_TRUE(AreEqualWithString(ws.GetExtensions().pp_var(), std::string())); 1200 ASSERT_TRUE(AreEqualWithString(ws.GetProtocol().pp_var(), std::string())); 1201 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID, ws.GetReadyState()); 1202 ASSERT_TRUE(AreEqualWithString(ws.GetURL().pp_var(), std::string())); 1203 1204 // Check communication interfaces (connect, send, receive, and close). 1205 TestCompletionCallback connect_callback( 1206 instance_->pp_instance(), callback_type()); 1207 connect_callback.WaitForResult(ws.Connect( 1208 pp::Var(GetFullURL(kCloseServerURL)), NULL, 0U, 1209 connect_callback.GetCallback())); 1210 CHECK_CALLBACK_BEHAVIOR(connect_callback); 1211 ASSERT_EQ(PP_OK, connect_callback.result()); 1212 1213 std::string text_message("hello C++"); 1214 int32_t result = ws.SendMessage(pp::Var(text_message)); 1215 ASSERT_EQ(PP_OK, result); 1216 1217 std::vector<uint8_t> binary(256); 1218 for (uint32_t i = 0; i < binary.size(); ++i) 1219 binary[i] = i; 1220 result = ws.SendMessage( 1221 pp::Var(pp::PASS_REF, CreateVarBinary(binary))); 1222 ASSERT_EQ(PP_OK, result); 1223 1224 pp::Var text_receive_var; 1225 TestCompletionCallback text_receive_callback( 1226 instance_->pp_instance(), callback_type()); 1227 text_receive_callback.WaitForResult( 1228 ws.ReceiveMessage(&text_receive_var, 1229 text_receive_callback.GetCallback())); 1230 ASSERT_EQ(PP_OK, text_receive_callback.result()); 1231 ASSERT_TRUE( 1232 AreEqualWithString(text_receive_var.pp_var(), text_message.c_str())); 1233 1234 pp::Var binary_receive_var; 1235 TestCompletionCallback binary_receive_callback( 1236 instance_->pp_instance(), callback_type()); 1237 binary_receive_callback.WaitForResult( 1238 ws.ReceiveMessage(&binary_receive_var, 1239 binary_receive_callback.GetCallback())); 1240 ASSERT_EQ(PP_OK, binary_receive_callback.result()); 1241 ASSERT_TRUE(AreEqualWithBinary(binary_receive_var.pp_var(), binary)); 1242 1243 TestCompletionCallback close_callback( 1244 instance_->pp_instance(), callback_type()); 1245 std::string reason("bye"); 1246 close_callback.WaitForResult(ws.Close( 1247 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason), 1248 close_callback.GetCallback())); 1249 CHECK_CALLBACK_BEHAVIOR(close_callback); 1250 ASSERT_EQ(PP_OK, close_callback.result()); 1251 1252 // Check initialized properties access. 1253 ASSERT_EQ(0, ws.GetBufferedAmount()); 1254 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, ws.GetCloseCode()); 1255 ASSERT_TRUE( 1256 AreEqualWithString(ws.GetCloseReason().pp_var(), reason.c_str())); 1257 ASSERT_EQ(true, ws.GetCloseWasClean()); 1258 ASSERT_TRUE(AreEqualWithString(ws.GetProtocol().pp_var(), std::string())); 1259 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED, ws.GetReadyState()); 1260 ASSERT_TRUE(AreEqualWithString( 1261 ws.GetURL().pp_var(), GetFullURL(kCloseServerURL).c_str())); 1262 1263 PASS(); 1264 } 1265 1266 std::string TestWebSocket::TestUtilityInvalidConnect() { 1267 const pp::Var protocols[] = { pp::Var() }; 1268 1269 TestWebSocketAPI websocket(instance_); 1270 int32_t result = websocket.Connect(pp::Var(), protocols, 1U); 1271 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); 1272 ASSERT_EQ(0U, websocket.GetSeenEvents().size()); 1273 1274 result = websocket.Connect(pp::Var(), protocols, 1U); 1275 ASSERT_EQ(PP_ERROR_INPROGRESS, result); 1276 ASSERT_EQ(0U, websocket.GetSeenEvents().size()); 1277 1278 for (int i = 0; kInvalidURLs[i]; ++i) { 1279 TestWebSocketAPI ws(instance_); 1280 result = ws.Connect(pp::Var(std::string(kInvalidURLs[i])), protocols, 0U); 1281 if (result == PP_OK_COMPLETIONPENDING) { 1282 ws.WaitForClosed(); 1283 const std::vector<WebSocketEvent>& events = ws.GetSeenEvents(); 1284 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type); 1285 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type); 1286 ASSERT_EQ(2U, ws.GetSeenEvents().size()); 1287 } else { 1288 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); 1289 ASSERT_EQ(0U, ws.GetSeenEvents().size()); 1290 } 1291 } 1292 1293 PASS(); 1294 } 1295 1296 std::string TestWebSocket::TestUtilityProtocols() { 1297 const pp::Var bad_protocols[] = { 1298 pp::Var(std::string("x-test")), pp::Var(std::string("x-test")) }; 1299 const pp::Var good_protocols[] = { 1300 pp::Var(std::string("x-test")), pp::Var(std::string("x-yatest")) }; 1301 1302 { 1303 TestWebSocketAPI websocket(instance_); 1304 int32_t result = websocket.Connect( 1305 pp::Var(GetFullURL(kEchoServerURL)), bad_protocols, 2U); 1306 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); 1307 ASSERT_EQ(0U, websocket.GetSeenEvents().size()); 1308 } 1309 1310 { 1311 TestWebSocketAPI websocket(instance_); 1312 int32_t result = websocket.Connect( 1313 pp::Var(GetFullURL(kEchoServerURL)), good_protocols, 2U); 1314 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1315 websocket.WaitForConnected(); 1316 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1317 // Protocol arguments are valid, but this test run without a WebSocket 1318 // server. As a result, OnError() and OnClose() are invoked because of 1319 // a connection establishment failure. 1320 ASSERT_EQ(2U, events.size()); 1321 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type); 1322 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type); 1323 ASSERT_FALSE(events[1].was_clean); 1324 } 1325 1326 PASS(); 1327 } 1328 1329 std::string TestWebSocket::TestUtilityGetURL() { 1330 const pp::Var protocols[] = { pp::Var() }; 1331 1332 for (int i = 0; kInvalidURLs[i]; ++i) { 1333 TestWebSocketAPI websocket(instance_); 1334 int32_t result = websocket.Connect( 1335 pp::Var(std::string(kInvalidURLs[i])), protocols, 0U); 1336 if (result == PP_OK_COMPLETIONPENDING) { 1337 websocket.WaitForClosed(); 1338 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1339 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type); 1340 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type); 1341 ASSERT_EQ(2U, events.size()); 1342 } else { 1343 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); 1344 ASSERT_EQ(0U, websocket.GetSeenEvents().size()); 1345 } 1346 pp::Var url = websocket.GetURL(); 1347 ASSERT_TRUE(AreEqualWithString(url.pp_var(), kInvalidURLs[i])); 1348 } 1349 1350 PASS(); 1351 } 1352 1353 std::string TestWebSocket::TestUtilityValidConnect() { 1354 const pp::Var protocols[] = { pp::Var() }; 1355 TestWebSocketAPI websocket(instance_); 1356 int32_t result = websocket.Connect( 1357 pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U); 1358 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1359 websocket.WaitForConnected(); 1360 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1361 ASSERT_EQ(1U, events.size()); 1362 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); 1363 ASSERT_TRUE( 1364 AreEqualWithString(websocket.GetExtensions().pp_var(), std::string())); 1365 1366 PASS(); 1367 } 1368 1369 std::string TestWebSocket::TestUtilityInvalidClose() { 1370 const pp::Var reason = pp::Var(std::string("close for test")); 1371 1372 // Close before connect. 1373 { 1374 TestWebSocketAPI websocket(instance_); 1375 int32_t result = websocket.Close( 1376 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason); 1377 ASSERT_EQ(PP_ERROR_FAILED, result); 1378 ASSERT_EQ(0U, websocket.GetSeenEvents().size()); 1379 } 1380 1381 // Close with bad arguments. 1382 { 1383 TestWebSocketAPI websocket(instance_); 1384 int32_t result = websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), 1385 NULL, 0); 1386 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1387 websocket.WaitForConnected(); 1388 result = websocket.Close(1U, reason); 1389 ASSERT_EQ(PP_ERROR_NOACCESS, result); 1390 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1391 ASSERT_EQ(1U, events.size()); 1392 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); 1393 } 1394 1395 PASS(); 1396 } 1397 1398 std::string TestWebSocket::TestUtilityValidClose() { 1399 std::string reason("close for test"); 1400 pp::Var url = pp::Var(GetFullURL(kCloseServerURL)); 1401 1402 // Close. 1403 { 1404 TestWebSocketAPI websocket(instance_); 1405 int32_t result = websocket.Connect(url, NULL, 0U); 1406 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1407 websocket.WaitForConnected(); 1408 result = websocket.Close( 1409 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason)); 1410 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1411 websocket.WaitForClosed(); 1412 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1413 ASSERT_EQ(2U, events.size()); 1414 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); 1415 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type); 1416 ASSERT_TRUE(events[1].was_clean); 1417 ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, events[1].close_code); 1418 ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), reason.c_str())); 1419 } 1420 1421 // Close in connecting. 1422 // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done 1423 // successfully. 1424 { 1425 TestWebSocketAPI websocket(instance_); 1426 int32_t result = websocket.Connect(url, NULL, 0U); 1427 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1428 result = websocket.Close( 1429 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason)); 1430 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1431 websocket.WaitForClosed(); 1432 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1433 ASSERT_TRUE(events.size() == 2 || events.size() == 3); 1434 int index = 0; 1435 if (events.size() == 3) 1436 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[index++].event_type); 1437 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[index++].event_type); 1438 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[index].event_type); 1439 ASSERT_FALSE(events[index].was_clean); 1440 } 1441 1442 // Close in closing. 1443 // The first close will be done successfully, then the second one failed with 1444 // with PP_ERROR_INPROGRESS immediately. 1445 { 1446 TestWebSocketAPI websocket(instance_); 1447 int32_t result = websocket.Connect(url, NULL, 0U); 1448 result = websocket.Close( 1449 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason)); 1450 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1451 result = websocket.Close( 1452 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason)); 1453 ASSERT_EQ(PP_ERROR_INPROGRESS, result); 1454 websocket.WaitForClosed(); 1455 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1456 ASSERT_TRUE(events.size() == 2 || events.size() == 3); 1457 int index = 0; 1458 if (events.size() == 3) 1459 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[index++].event_type); 1460 ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[index++].event_type); 1461 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[index].event_type); 1462 ASSERT_FALSE(events[index].was_clean); 1463 } 1464 1465 PASS(); 1466 } 1467 1468 std::string TestWebSocket::TestUtilityGetProtocol() { 1469 const std::string protocol("x-chat"); 1470 const pp::Var protocols[] = { pp::Var(protocol) }; 1471 std::string url(GetFullURL(kProtocolTestServerURL)); 1472 url += protocol; 1473 TestWebSocketAPI websocket(instance_); 1474 int32_t result = websocket.Connect(pp::Var(url), protocols, 1U); 1475 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1476 websocket.WaitForReceived(); 1477 ASSERT_TRUE(AreEqualWithString( 1478 websocket.GetProtocol().pp_var(), protocol.c_str())); 1479 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1480 // The server to which this test connect returns the decided protocol as a 1481 // text frame message. So the WebSocketEvent records EVENT_MESSAGE event 1482 // after EVENT_OPEN event. 1483 ASSERT_EQ(2U, events.size()); 1484 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); 1485 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type); 1486 ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), protocol.c_str())); 1487 1488 PASS(); 1489 } 1490 1491 std::string TestWebSocket::TestUtilityTextSendReceive() { 1492 const pp::Var protocols[] = { pp::Var() }; 1493 TestWebSocketAPI websocket(instance_); 1494 int32_t result = 1495 websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U); 1496 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1497 websocket.WaitForConnected(); 1498 1499 // Send 'hello pepper'. 1500 std::string message1("hello pepper"); 1501 result = websocket.Send(pp::Var(std::string(message1))); 1502 ASSERT_EQ(PP_OK, result); 1503 1504 // Receive echoed 'hello pepper'. 1505 websocket.WaitForReceived(); 1506 1507 // Send 'goodbye pepper'. 1508 std::string message2("goodbye pepper"); 1509 result = websocket.Send(pp::Var(std::string(message2))); 1510 1511 // Receive echoed 'goodbye pepper'. 1512 websocket.WaitForReceived(); 1513 1514 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1515 ASSERT_EQ(3U, events.size()); 1516 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); 1517 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type); 1518 ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), message1.c_str())); 1519 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[2].event_type); 1520 ASSERT_TRUE(AreEqualWithString(events[2].var.pp_var(), message2.c_str())); 1521 1522 PASS(); 1523 } 1524 1525 std::string TestWebSocket::TestUtilityBinarySendReceive() { 1526 const pp::Var protocols[] = { pp::Var() }; 1527 TestWebSocketAPI websocket(instance_); 1528 int32_t result = 1529 websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U); 1530 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1531 websocket.WaitForConnected(); 1532 1533 // Send binary message. 1534 uint32_t len = 256; 1535 std::vector<uint8_t> binary(len); 1536 for (uint32_t i = 0; i < len; ++i) 1537 binary[i] = i; 1538 pp::VarArrayBuffer message(len); 1539 uint8_t* var_data = static_cast<uint8_t*>(message.Map()); 1540 std::copy(binary.begin(), binary.end(), var_data); 1541 result = websocket.Send(message); 1542 ASSERT_EQ(PP_OK, result); 1543 1544 // Receive echoed binary message. 1545 websocket.WaitForReceived(); 1546 1547 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1548 ASSERT_EQ(2U, events.size()); 1549 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); 1550 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type); 1551 ASSERT_TRUE(AreEqualWithBinary(events[1].var.pp_var(), binary)); 1552 1553 PASS(); 1554 } 1555 1556 std::string TestWebSocket::TestUtilityBufferedAmount() { 1557 // Connect to test echo server. 1558 const pp::Var protocols[] = { pp::Var() }; 1559 TestWebSocketAPI websocket(instance_); 1560 int32_t result = 1561 websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U); 1562 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); 1563 websocket.WaitForConnected(); 1564 1565 // Prepare a large message that is not aligned with the internal buffer 1566 // sizes. 1567 std::string message(8193, 'x'); 1568 uint64_t buffered_amount = 0; 1569 uint32_t sent; 1570 for (sent = 0; sent < 100; sent++) { 1571 result = websocket.Send(pp::Var(message)); 1572 ASSERT_EQ(PP_OK, result); 1573 buffered_amount = websocket.GetBufferedAmount(); 1574 // Buffered amount size 262144 is too big for the internal buffer size. 1575 if (buffered_amount > 262144) 1576 break; 1577 } 1578 1579 // Close connection. 1580 std::string reason = "close while busy"; 1581 result = websocket.Close( 1582 PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason)); 1583 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING, websocket.GetReadyState()); 1584 websocket.WaitForClosed(); 1585 ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED, websocket.GetReadyState()); 1586 1587 uint64_t base_buffered_amount = websocket.GetBufferedAmount(); 1588 size_t events_on_closed = websocket.GetSeenEvents().size(); 1589 1590 // After connection closure, all sending requests fail and just increase 1591 // the bufferedAmount property. 1592 result = websocket.Send(pp::Var(std::string())); 1593 ASSERT_EQ(PP_ERROR_FAILED, result); 1594 buffered_amount = websocket.GetBufferedAmount(); 1595 ASSERT_EQ(base_buffered_amount + kMessageFrameOverhead, buffered_amount); 1596 base_buffered_amount = buffered_amount; 1597 1598 result = websocket.Send(pp::Var(reason)); 1599 ASSERT_EQ(PP_ERROR_FAILED, result); 1600 buffered_amount = websocket.GetBufferedAmount(); 1601 uint64_t reason_frame_size = kMessageFrameOverhead + reason.length(); 1602 ASSERT_EQ(base_buffered_amount + reason_frame_size, buffered_amount); 1603 1604 const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents(); 1605 ASSERT_EQ(events_on_closed, events.size()); 1606 ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); 1607 size_t last_event = events_on_closed - 1; 1608 for (uint32_t i = 1; i < last_event; ++i) { 1609 ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[i].event_type); 1610 ASSERT_TRUE(AreEqualWithString(events[i].var.pp_var(), message)); 1611 } 1612 ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[last_event].event_type); 1613 ASSERT_TRUE(events[last_event].was_clean); 1614 1615 PASS(); 1616 } 1617