1 // Copyright 2013 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_tcp_socket.h" 6 7 #include "ppapi/cpp/tcp_socket.h" 8 #include "ppapi/tests/test_utils.h" 9 #include "ppapi/tests/testing_instance.h" 10 11 namespace { 12 13 // Validates the first line of an HTTP response. 14 bool ValidateHttpResponse(const std::string& s) { 15 // Just check that it begins with "HTTP/" and ends with a "\r\n". 16 return s.size() >= 5 && 17 s.substr(0, 5) == "HTTP/" && 18 s.substr(s.size() - 2) == "\r\n"; 19 } 20 21 } // namespace 22 23 REGISTER_TEST_CASE(TCPSocket); 24 25 TestTCPSocket::TestTCPSocket(TestingInstance* instance) : TestCase(instance) { 26 } 27 28 bool TestTCPSocket::Init() { 29 if (!pp::TCPSocket::IsAvailable()) 30 return false; 31 32 // We need something to connect to, so we connect to the HTTP server whence we 33 // came. Grab the host and port. 34 if (!EnsureRunningOverHTTP()) 35 return false; 36 37 std::string host; 38 uint16_t port = 0; 39 if (!GetLocalHostPort(instance_->pp_instance(), &host, &port)) 40 return false; 41 42 if (!ResolveHost(instance_->pp_instance(), host, port, &addr_)) 43 return false; 44 45 return true; 46 } 47 48 void TestTCPSocket::RunTests(const std::string& filter) { 49 RUN_CALLBACK_TEST(TestTCPSocket, Connect, filter); 50 RUN_CALLBACK_TEST(TestTCPSocket, ReadWrite, filter); 51 RUN_CALLBACK_TEST(TestTCPSocket, SetOption, filter); 52 } 53 54 std::string TestTCPSocket::TestConnect() { 55 pp::TCPSocket socket(instance_); 56 TestCompletionCallback cb(instance_->pp_instance(), callback_type()); 57 58 cb.WaitForResult(socket.Connect(addr_, cb.GetCallback())); 59 CHECK_CALLBACK_BEHAVIOR(cb); 60 ASSERT_EQ(PP_OK, cb.result()); 61 62 pp::NetAddress local_addr, remote_addr; 63 local_addr = socket.GetLocalAddress(); 64 remote_addr = socket.GetRemoteAddress(); 65 66 ASSERT_NE(0, local_addr.pp_resource()); 67 ASSERT_NE(0, remote_addr.pp_resource()); 68 ASSERT_TRUE(EqualNetAddress(addr_, remote_addr)); 69 70 socket.Close(); 71 72 PASS(); 73 } 74 75 std::string TestTCPSocket::TestReadWrite() { 76 pp::TCPSocket socket(instance_); 77 TestCompletionCallback cb(instance_->pp_instance(), callback_type()); 78 79 cb.WaitForResult(socket.Connect(addr_, cb.GetCallback())); 80 CHECK_CALLBACK_BEHAVIOR(cb); 81 ASSERT_EQ(PP_OK, cb.result()); 82 83 ASSERT_EQ(PP_OK, WriteStringToSocket(&socket, "GET / HTTP/1.0\r\n\r\n")); 84 85 // Read up to the first \n and check that it looks like valid HTTP response. 86 std::string s; 87 ASSERT_EQ(PP_OK, ReadFirstLineFromSocket(&socket, &s)); 88 ASSERT_TRUE(ValidateHttpResponse(s)); 89 90 PASS(); 91 } 92 93 std::string TestTCPSocket::TestSetOption() { 94 pp::TCPSocket socket(instance_); 95 TestCompletionCallback cb_1(instance_->pp_instance(), callback_type()); 96 TestCompletionCallback cb_2(instance_->pp_instance(), callback_type()); 97 TestCompletionCallback cb_3(instance_->pp_instance(), callback_type()); 98 99 // These options cannot be set before the socket is connected. 100 int32_t result_1 = socket.SetOption(PP_TCPSOCKET_OPTION_NO_DELAY, 101 true, cb_1.GetCallback()); 102 int32_t result_2 = socket.SetOption(PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE, 103 256, cb_2.GetCallback()); 104 int32_t result_3 = socket.SetOption(PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE, 105 512, cb_3.GetCallback()); 106 107 cb_1.WaitForResult(result_1); 108 CHECK_CALLBACK_BEHAVIOR(cb_1); 109 ASSERT_EQ(PP_ERROR_FAILED, cb_1.result()); 110 111 cb_2.WaitForResult(result_2); 112 CHECK_CALLBACK_BEHAVIOR(cb_2); 113 ASSERT_EQ(PP_ERROR_FAILED, cb_2.result()); 114 115 cb_3.WaitForResult(result_3); 116 CHECK_CALLBACK_BEHAVIOR(cb_3); 117 ASSERT_EQ(PP_ERROR_FAILED, cb_3.result()); 118 119 cb_1.WaitForResult(socket.Connect(addr_, cb_1.GetCallback())); 120 CHECK_CALLBACK_BEHAVIOR(cb_1); 121 ASSERT_EQ(PP_OK, cb_1.result()); 122 123 result_1 = socket.SetOption(PP_TCPSOCKET_OPTION_NO_DELAY, 124 false, cb_1.GetCallback()); 125 result_2 = socket.SetOption(PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE, 126 512, cb_2.GetCallback()); 127 result_3 = socket.SetOption(PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE, 128 1024, cb_3.GetCallback()); 129 130 cb_1.WaitForResult(result_1); 131 CHECK_CALLBACK_BEHAVIOR(cb_1); 132 ASSERT_EQ(PP_OK, cb_1.result()); 133 134 cb_2.WaitForResult(result_2); 135 CHECK_CALLBACK_BEHAVIOR(cb_2); 136 ASSERT_EQ(PP_OK, cb_2.result()); 137 138 cb_3.WaitForResult(result_3); 139 CHECK_CALLBACK_BEHAVIOR(cb_3); 140 ASSERT_EQ(PP_OK, cb_3.result()); 141 142 PASS(); 143 } 144 145 int32_t TestTCPSocket::ReadFirstLineFromSocket(pp::TCPSocket* socket, 146 std::string* s) { 147 char buffer[1000]; 148 149 s->clear(); 150 // Make sure we don't just hang if |Read()| spews. 151 while (s->size() < 10000) { 152 TestCompletionCallback cb(instance_->pp_instance(), callback_type()); 153 int32_t rv = socket->Read(buffer, sizeof(buffer), cb.GetCallback()); 154 if (callback_type() == PP_REQUIRED && rv != PP_OK_COMPLETIONPENDING) 155 return PP_ERROR_FAILED; 156 cb.WaitForResult(rv); 157 if (cb.result() < 0) 158 return cb.result(); 159 if (cb.result() == 0) 160 return PP_ERROR_FAILED; // Didn't get a \n-terminated line. 161 s->reserve(s->size() + cb.result()); 162 for (int32_t i = 0; i < cb.result(); i++) { 163 s->push_back(buffer[i]); 164 if (buffer[i] == '\n') 165 return PP_OK; 166 } 167 } 168 return PP_ERROR_FAILED; 169 } 170 171 int32_t TestTCPSocket::WriteStringToSocket(pp::TCPSocket* socket, 172 const std::string& s) { 173 const char* buffer = s.data(); 174 size_t written = 0; 175 while (written < s.size()) { 176 TestCompletionCallback cb(instance_->pp_instance(), callback_type()); 177 int32_t rv = socket->Write(buffer + written, s.size() - written, 178 cb.GetCallback()); 179 if (callback_type() == PP_REQUIRED && rv != PP_OK_COMPLETIONPENDING) 180 return PP_ERROR_FAILED; 181 cb.WaitForResult(rv); 182 if (cb.result() < 0) 183 return cb.result(); 184 if (cb.result() == 0) 185 return PP_ERROR_FAILED; 186 written += cb.result(); 187 } 188 if (written != s.size()) 189 return PP_ERROR_FAILED; 190 return PP_OK; 191 } 192