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.
ValidateHttpResponse(const std::string & s)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
TestTCPSocketPrivate(TestingInstance * instance)29 TestTCPSocketPrivate::TestTCPSocketPrivate(TestingInstance* instance)
30 : TestCase(instance) {
31 }
32
Init()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
RunTests(const std::string & filter)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
TestBasic()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
TestReadWrite()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
TestReadWriteSSL()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
TestConnectAddress()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
TestSetOption()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
TestLargeRead()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
ReadFirstLineFromSocket(pp::TCPSocketPrivate * socket,std::string * s)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
WriteStringToSocket(pp::TCPSocketPrivate * socket,const std::string & s)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