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
15namespace {
16
17// Validates the first line of an HTTP response.
18bool 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
27REGISTER_TEST_CASE(TCPSocketPrivate);
28
29TestTCPSocketPrivate::TestTCPSocketPrivate(TestingInstance* instance)
30    : TestCase(instance) {
31}
32
33bool 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
51void 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
60std::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
78std::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
98std::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
123std::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
156std::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
187std::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
216int32_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
243int32_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