• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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