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_tcp_socket_private.h" 6 7 #include <stdlib.h> 8 9 #include <new> 10 11 #include "ppapi/cpp/private/tcp_socket_private.h" 12 #include "ppapi/tests/test_utils.h" 13 #include "ppapi/tests/testing_instance.h" 14 15 namespace { 16 17 // Validates the first line of an HTTP response. 18 bool ValidateHttpResponse(const std::string& s) { 19 // Just check that it begins with "HTTP/" and ends with a "\r\n". 20 return s.size() >= 5 && 21 s.substr(0, 5) == "HTTP/" && 22 s.substr(s.size() - 2) == "\r\n"; 23 } 24 25 } // namespace 26 27 REGISTER_TEST_CASE(TCPSocketPrivate); 28 29 TestTCPSocketPrivate::TestTCPSocketPrivate(TestingInstance* instance) 30 : TestCase(instance) { 31 } 32 33 bool TestTCPSocketPrivate::Init() { 34 if (!pp::TCPSocketPrivate::IsAvailable()) 35 return false; 36 37 // We need something to connect to, so we connect to the HTTP server whence we 38 // came. Grab the host and port. 39 if (!EnsureRunningOverHTTP()) 40 return false; 41 42 if (!GetLocalHostPort(instance_->pp_instance(), &host_, &port_)) 43 return false; 44 45 // Get the port for the SSL server. 46 ssl_port_ = instance_->ssl_server_port(); 47 48 return true; 49 } 50 51 void TestTCPSocketPrivate::RunTests(const std::string& filter) { 52 RUN_CALLBACK_TEST(TestTCPSocketPrivate, Basic, filter); 53 RUN_CALLBACK_TEST(TestTCPSocketPrivate, ReadWrite, filter); 54 RUN_CALLBACK_TEST(TestTCPSocketPrivate, ReadWriteSSL, filter); 55 RUN_CALLBACK_TEST(TestTCPSocketPrivate, ConnectAddress, filter); 56 RUN_CALLBACK_TEST(TestTCPSocketPrivate, SetOption, filter); 57 RUN_CALLBACK_TEST(TestTCPSocketPrivate, LargeRead, filter); 58 } 59 60 std::string TestTCPSocketPrivate::TestBasic() { 61 pp::TCPSocketPrivate socket(instance_); 62 TestCompletionCallback cb(instance_->pp_instance(), callback_type()); 63 64 cb.WaitForResult(socket.Connect(host_.c_str(), port_, cb.GetCallback())); 65 CHECK_CALLBACK_BEHAVIOR(cb); 66 ASSERT_EQ(PP_OK, cb.result()); 67 68 PP_NetAddress_Private unused; 69 // TODO(viettrungluu): check the values somehow. 70 ASSERT_TRUE(socket.GetLocalAddress(&unused)); 71 ASSERT_TRUE(socket.GetRemoteAddress(&unused)); 72 73 socket.Disconnect(); 74 75 PASS(); 76 } 77 78 std::string TestTCPSocketPrivate::TestReadWrite() { 79 pp::TCPSocketPrivate socket(instance_); 80 TestCompletionCallback cb(instance_->pp_instance(), callback_type()); 81 82 cb.WaitForResult(socket.Connect(host_.c_str(), port_, cb.GetCallback())); 83 CHECK_CALLBACK_BEHAVIOR(cb); 84 ASSERT_EQ(PP_OK, cb.result()); 85 86 ASSERT_EQ(PP_OK, WriteStringToSocket(&socket, "GET / HTTP/1.0\r\n\r\n")); 87 88 // Read up to the first \n and check that it looks like valid HTTP response. 89 std::string s; 90 ASSERT_EQ(PP_OK, ReadFirstLineFromSocket(&socket, &s)); 91 ASSERT_TRUE(ValidateHttpResponse(s)); 92 93 socket.Disconnect(); 94 95 PASS(); 96 } 97 98 std::string TestTCPSocketPrivate::TestReadWriteSSL() { 99 pp::TCPSocketPrivate socket(instance_); 100 TestCompletionCallback cb(instance_->pp_instance(), callback_type()); 101 102 cb.WaitForResult(socket.Connect(host_.c_str(), ssl_port_, cb.GetCallback())); 103 CHECK_CALLBACK_BEHAVIOR(cb); 104 ASSERT_EQ(PP_OK, cb.result()); 105 106 cb.WaitForResult( 107 socket.SSLHandshake(host_.c_str(), ssl_port_, cb.GetCallback())); 108 CHECK_CALLBACK_BEHAVIOR(cb); 109 ASSERT_EQ(PP_OK, cb.result()); 110 111 ASSERT_EQ(PP_OK, WriteStringToSocket(&socket, "GET / HTTP/1.0\r\n\r\n")); 112 113 // Read up to the first \n and check that it looks like valid HTTP response. 114 std::string s; 115 ASSERT_EQ(PP_OK, ReadFirstLineFromSocket(&socket, &s)); 116 ASSERT_TRUE(ValidateHttpResponse(s)); 117 118 socket.Disconnect(); 119 120 PASS(); 121 } 122 123 std::string TestTCPSocketPrivate::TestConnectAddress() { 124 PP_NetAddress_Private address; 125 126 // First, bring up a connection and grab the address. 127 { 128 pp::TCPSocketPrivate socket(instance_); 129 TestCompletionCallback cb(instance_->pp_instance(), callback_type()); 130 cb.WaitForResult(socket.Connect(host_.c_str(), port_, cb.GetCallback())); 131 CHECK_CALLBACK_BEHAVIOR(cb); 132 ASSERT_EQ(PP_OK, cb.result()); 133 ASSERT_TRUE(socket.GetRemoteAddress(&address)); 134 // Omit the |Disconnect()| here to make sure we don't crash if we just let 135 // the resource be destroyed. 136 } 137 138 // Connect to that address. 139 pp::TCPSocketPrivate socket(instance_); 140 TestCompletionCallback cb(instance_->pp_instance(), callback_type()); 141 cb.WaitForResult(socket.ConnectWithNetAddress(&address, cb.GetCallback())); 142 CHECK_CALLBACK_BEHAVIOR(cb); 143 ASSERT_EQ(PP_OK, cb.result()); 144 145 // Make sure we can read/write to it properly (see |TestReadWrite()|). 146 ASSERT_EQ(PP_OK, WriteStringToSocket(&socket, "GET / HTTP/1.0\r\n\r\n")); 147 std::string s; 148 ASSERT_EQ(PP_OK, ReadFirstLineFromSocket(&socket, &s)); 149 ASSERT_TRUE(ValidateHttpResponse(s)); 150 151 socket.Disconnect(); 152 153 PASS(); 154 } 155 156 std::string TestTCPSocketPrivate::TestSetOption() { 157 pp::TCPSocketPrivate socket(instance_); 158 TestCompletionCallback cb(instance_->pp_instance(), callback_type()); 159 160 cb.WaitForResult( 161 socket.SetOption(PP_TCPSOCKETOPTION_PRIVATE_NO_DELAY, true, 162 cb.GetCallback())); 163 CHECK_CALLBACK_BEHAVIOR(cb); 164 ASSERT_EQ(PP_ERROR_FAILED, cb.result()); 165 166 cb.WaitForResult(socket.Connect(host_.c_str(), port_, cb.GetCallback())); 167 CHECK_CALLBACK_BEHAVIOR(cb); 168 ASSERT_EQ(PP_OK, cb.result()); 169 170 cb.WaitForResult( 171 socket.SetOption(PP_TCPSOCKETOPTION_PRIVATE_NO_DELAY, true, 172 cb.GetCallback())); 173 CHECK_CALLBACK_BEHAVIOR(cb); 174 ASSERT_EQ(PP_OK, cb.result()); 175 176 cb.WaitForResult( 177 socket.SetOption(PP_TCPSOCKETOPTION_PRIVATE_INVALID, true, 178 cb.GetCallback())); 179 CHECK_CALLBACK_BEHAVIOR(cb); 180 ASSERT_EQ(PP_ERROR_BADARGUMENT, cb.result()); 181 182 socket.Disconnect(); 183 184 PASS(); 185 } 186 187 std::string TestTCPSocketPrivate::TestLargeRead() { 188 pp::TCPSocketPrivate socket(instance_); 189 { 190 TestCompletionCallback cb(instance_->pp_instance(), callback_type()); 191 192 cb.WaitForResult(socket.Connect(host_.c_str(), port_, cb.GetCallback())); 193 CHECK_CALLBACK_BEHAVIOR(cb); 194 ASSERT_EQ(PP_OK, cb.result()); 195 } 196 197 ASSERT_EQ(PP_OK, WriteStringToSocket(&socket, "GET / HTTP/1.0\r\n\r\n")); 198 199 const size_t kReadSize = 1024 * 1024 + 32; 200 // Create large buffer in heap to prevent run-time errors related to 201 // limits on stack size. 202 char* buffer = new (std::nothrow) char[kReadSize]; 203 ASSERT_TRUE(buffer != NULL); 204 205 TestCompletionCallback cb(instance_->pp_instance(), callback_type()); 206 cb.WaitForResult(socket.Read(buffer, kReadSize * sizeof(*buffer), 207 cb.GetCallback())); 208 CHECK_CALLBACK_BEHAVIOR(cb); 209 ASSERT_LE(0, cb.result()); 210 211 delete [] buffer; 212 213 PASS(); 214 } 215 216 int32_t TestTCPSocketPrivate::ReadFirstLineFromSocket( 217 pp::TCPSocketPrivate* socket, 218 std::string* s) { 219 char buffer[10000]; 220 221 s->clear(); 222 // Make sure we don't just hang if |Read()| spews. 223 while (s->size() < 1000000) { 224 TestCompletionCallback cb(instance_->pp_instance(), callback_type()); 225 int32_t rv = socket->Read(buffer, sizeof(buffer), cb.GetCallback()); 226 if (callback_type() == PP_REQUIRED && rv != PP_OK_COMPLETIONPENDING) 227 return PP_ERROR_FAILED; 228 cb.WaitForResult(rv); 229 if (cb.result() < 0) 230 return cb.result(); 231 if (cb.result() == 0) 232 return PP_ERROR_FAILED; // Didn't get a \n-terminated line. 233 s->reserve(s->size() + cb.result()); 234 for (int32_t i = 0; i < cb.result(); i++) { 235 s->push_back(buffer[i]); 236 if (buffer[i] == '\n') 237 return PP_OK; 238 } 239 } 240 return PP_ERROR_FAILED; 241 } 242 243 int32_t TestTCPSocketPrivate::WriteStringToSocket(pp::TCPSocketPrivate* socket, 244 const std::string& s) { 245 const char* buffer = s.data(); 246 size_t written = 0; 247 while (written < s.size()) { 248 TestCompletionCallback cb(instance_->pp_instance(), callback_type()); 249 int32_t rv = socket->Write(buffer + written, s.size() - written, 250 cb.GetCallback()); 251 if (callback_type() == PP_REQUIRED && rv != PP_OK_COMPLETIONPENDING) 252 return PP_ERROR_FAILED; 253 cb.WaitForResult(rv); 254 if (cb.result() < 0) 255 return cb.result(); 256 if (cb.result() == 0) 257 return PP_ERROR_FAILED; 258 written += cb.result(); 259 } 260 if (written != s.size()) 261 return PP_ERROR_FAILED; 262 return PP_OK; 263 } 264