OLD | NEW |
| (Empty) |
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 "jingle/notifier/base/fake_ssl_client_socket.h" | |
6 | |
7 #include <algorithm> | |
8 #include <vector> | |
9 | |
10 #include "base/basictypes.h" | |
11 #include "base/memory/ref_counted.h" | |
12 #include "base/memory/scoped_ptr.h" | |
13 #include "base/message_loop.h" | |
14 #include "net/base/io_buffer.h" | |
15 #include "net/base/net_log.h" | |
16 #include "net/base/test_completion_callback.h" | |
17 #include "net/socket/socket_test_util.h" | |
18 #include "net/socket/stream_socket.h" | |
19 #include "testing/gmock/include/gmock/gmock.h" | |
20 #include "testing/gtest/include/gtest/gtest.h" | |
21 | |
22 namespace notifier { | |
23 | |
24 namespace { | |
25 | |
26 using ::testing::Return; | |
27 using ::testing::ReturnRef; | |
28 | |
29 // Used by RunUnsuccessfulHandshakeTestHelper. Represents where in | |
30 // the handshake step an error should be inserted. | |
31 enum HandshakeErrorLocation { | |
32 CONNECT_ERROR, | |
33 SEND_CLIENT_HELLO_ERROR, | |
34 VERIFY_SERVER_HELLO_ERROR, | |
35 }; | |
36 | |
37 // Private error codes appended to the net::Error set. | |
38 enum { | |
39 // An error representing a server hello that has been corrupted in | |
40 // transit. | |
41 ERR_MALFORMED_SERVER_HELLO = -15000, | |
42 }; | |
43 | |
44 // Used by PassThroughMethods test. | |
45 class MockClientSocket : public net::StreamSocket { | |
46 public: | |
47 virtual ~MockClientSocket() {} | |
48 | |
49 MOCK_METHOD3(Read, int(net::IOBuffer*, int, | |
50 const net::CompletionCallback&)); | |
51 MOCK_METHOD3(Write, int(net::IOBuffer*, int, | |
52 const net::CompletionCallback&)); | |
53 MOCK_METHOD1(SetReceiveBufferSize, bool(int32)); | |
54 MOCK_METHOD1(SetSendBufferSize, bool(int32)); | |
55 MOCK_METHOD1(Connect, int(const net::CompletionCallback&)); | |
56 MOCK_METHOD0(Disconnect, void()); | |
57 MOCK_CONST_METHOD0(IsConnected, bool()); | |
58 MOCK_CONST_METHOD0(IsConnectedAndIdle, bool()); | |
59 MOCK_CONST_METHOD1(GetPeerAddress, int(net::IPEndPoint*)); | |
60 MOCK_CONST_METHOD1(GetLocalAddress, int(net::IPEndPoint*)); | |
61 MOCK_CONST_METHOD0(NetLog, const net::BoundNetLog&()); | |
62 MOCK_METHOD0(SetSubresourceSpeculation, void()); | |
63 MOCK_METHOD0(SetOmniboxSpeculation, void()); | |
64 MOCK_CONST_METHOD0(WasEverUsed, bool()); | |
65 MOCK_CONST_METHOD0(UsingTCPFastOpen, bool()); | |
66 MOCK_CONST_METHOD0(NumBytesRead, int64()); | |
67 MOCK_CONST_METHOD0(GetConnectTimeMicros, base::TimeDelta()); | |
68 MOCK_CONST_METHOD0(WasNpnNegotiated, bool()); | |
69 MOCK_CONST_METHOD0(GetNegotiatedProtocol, net::NextProto()); | |
70 MOCK_METHOD1(GetSSLInfo, bool(net::SSLInfo*)); | |
71 }; | |
72 | |
73 // Break up |data| into a bunch of chunked MockReads/Writes and push | |
74 // them onto |ops|. | |
75 void AddChunkedOps(base::StringPiece data, size_t chunk_size, net::IoMode mode, | |
76 std::vector<net::MockRead>* ops) { | |
77 DCHECK_GT(chunk_size, 0U); | |
78 size_t offset = 0; | |
79 while (offset < data.size()) { | |
80 size_t bounded_chunk_size = std::min(data.size() - offset, chunk_size); | |
81 // We take advantage of the fact that MockWrite is typedefed to | |
82 // MockRead. | |
83 ops->push_back(net::MockRead(mode, data.data() + offset, | |
84 bounded_chunk_size)); | |
85 offset += bounded_chunk_size; | |
86 } | |
87 } | |
88 | |
89 class FakeSSLClientSocketTest : public testing::Test { | |
90 protected: | |
91 FakeSSLClientSocketTest() {} | |
92 | |
93 virtual ~FakeSSLClientSocketTest() {} | |
94 | |
95 net::StreamSocket* MakeClientSocket() { | |
96 return mock_client_socket_factory_.CreateTransportClientSocket( | |
97 net::AddressList(), NULL, net::NetLog::Source()); | |
98 } | |
99 | |
100 void SetData(const net::MockConnect& mock_connect, | |
101 std::vector<net::MockRead>* reads, | |
102 std::vector<net::MockWrite>* writes) { | |
103 static_socket_data_provider_.reset( | |
104 new net::StaticSocketDataProvider( | |
105 reads->empty() ? NULL : &*reads->begin(), reads->size(), | |
106 writes->empty() ? NULL : &*writes->begin(), writes->size())); | |
107 static_socket_data_provider_->set_connect_data(mock_connect); | |
108 mock_client_socket_factory_.AddSocketDataProvider( | |
109 static_socket_data_provider_.get()); | |
110 } | |
111 | |
112 void ExpectStatus( | |
113 net::IoMode mode, int expected_status, int immediate_status, | |
114 net::TestCompletionCallback* test_completion_callback) { | |
115 if (mode == net::ASYNC) { | |
116 EXPECT_EQ(net::ERR_IO_PENDING, immediate_status); | |
117 int status = test_completion_callback->WaitForResult(); | |
118 EXPECT_EQ(expected_status, status); | |
119 } else { | |
120 EXPECT_EQ(expected_status, immediate_status); | |
121 } | |
122 } | |
123 | |
124 // Sets up the mock socket to generate a successful handshake | |
125 // (sliced up according to the parameters) and makes sure the | |
126 // FakeSSLClientSocket behaves as expected. | |
127 void RunSuccessfulHandshakeTest( | |
128 net::IoMode mode, size_t read_chunk_size, size_t write_chunk_size, | |
129 int num_resets) { | |
130 base::StringPiece ssl_client_hello = | |
131 FakeSSLClientSocket::GetSslClientHello(); | |
132 base::StringPiece ssl_server_hello = | |
133 FakeSSLClientSocket::GetSslServerHello(); | |
134 | |
135 net::MockConnect mock_connect(mode, net::OK); | |
136 std::vector<net::MockRead> reads; | |
137 std::vector<net::MockWrite> writes; | |
138 static const char kReadTestData[] = "read test data"; | |
139 static const char kWriteTestData[] = "write test data"; | |
140 for (int i = 0; i < num_resets + 1; ++i) { | |
141 SCOPED_TRACE(i); | |
142 AddChunkedOps(ssl_server_hello, read_chunk_size, mode, &reads); | |
143 AddChunkedOps(ssl_client_hello, write_chunk_size, mode, &writes); | |
144 reads.push_back( | |
145 net::MockRead(mode, kReadTestData, arraysize(kReadTestData))); | |
146 writes.push_back( | |
147 net::MockWrite(mode, kWriteTestData, arraysize(kWriteTestData))); | |
148 } | |
149 SetData(mock_connect, &reads, &writes); | |
150 | |
151 FakeSSLClientSocket fake_ssl_client_socket(MakeClientSocket()); | |
152 | |
153 for (int i = 0; i < num_resets + 1; ++i) { | |
154 SCOPED_TRACE(i); | |
155 net::TestCompletionCallback test_completion_callback; | |
156 int status = fake_ssl_client_socket.Connect( | |
157 test_completion_callback.callback()); | |
158 if (mode == net::ASYNC) { | |
159 EXPECT_FALSE(fake_ssl_client_socket.IsConnected()); | |
160 } | |
161 ExpectStatus(mode, net::OK, status, &test_completion_callback); | |
162 if (fake_ssl_client_socket.IsConnected()) { | |
163 int read_len = arraysize(kReadTestData); | |
164 int read_buf_len = 2 * read_len; | |
165 scoped_refptr<net::IOBuffer> read_buf( | |
166 new net::IOBuffer(read_buf_len)); | |
167 int read_status = fake_ssl_client_socket.Read( | |
168 read_buf, read_buf_len, test_completion_callback.callback()); | |
169 ExpectStatus(mode, read_len, read_status, &test_completion_callback); | |
170 | |
171 scoped_refptr<net::IOBuffer> write_buf( | |
172 new net::StringIOBuffer(kWriteTestData)); | |
173 int write_status = fake_ssl_client_socket.Write( | |
174 write_buf, arraysize(kWriteTestData), | |
175 test_completion_callback.callback()); | |
176 ExpectStatus(mode, arraysize(kWriteTestData), write_status, | |
177 &test_completion_callback); | |
178 } else { | |
179 ADD_FAILURE(); | |
180 } | |
181 fake_ssl_client_socket.Disconnect(); | |
182 EXPECT_FALSE(fake_ssl_client_socket.IsConnected()); | |
183 } | |
184 } | |
185 | |
186 // Sets up the mock socket to generate an unsuccessful handshake | |
187 // FakeSSLClientSocket fails as expected. | |
188 void RunUnsuccessfulHandshakeTestHelper( | |
189 net::IoMode mode, int error, HandshakeErrorLocation location) { | |
190 DCHECK_NE(error, net::OK); | |
191 base::StringPiece ssl_client_hello = | |
192 FakeSSLClientSocket::GetSslClientHello(); | |
193 base::StringPiece ssl_server_hello = | |
194 FakeSSLClientSocket::GetSslServerHello(); | |
195 | |
196 net::MockConnect mock_connect(mode, net::OK); | |
197 std::vector<net::MockRead> reads; | |
198 std::vector<net::MockWrite> writes; | |
199 const size_t kChunkSize = 1; | |
200 AddChunkedOps(ssl_server_hello, kChunkSize, mode, &reads); | |
201 AddChunkedOps(ssl_client_hello, kChunkSize, mode, &writes); | |
202 switch (location) { | |
203 case CONNECT_ERROR: | |
204 mock_connect.result = error; | |
205 writes.clear(); | |
206 reads.clear(); | |
207 break; | |
208 case SEND_CLIENT_HELLO_ERROR: { | |
209 // Use a fixed index for repeatability. | |
210 size_t index = 100 % writes.size(); | |
211 writes[index].result = error; | |
212 writes[index].data = NULL; | |
213 writes[index].data_len = 0; | |
214 writes.resize(index + 1); | |
215 reads.clear(); | |
216 break; | |
217 } | |
218 case VERIFY_SERVER_HELLO_ERROR: { | |
219 // Use a fixed index for repeatability. | |
220 size_t index = 50 % reads.size(); | |
221 if (error == ERR_MALFORMED_SERVER_HELLO) { | |
222 static const char kBadData[] = "BAD_DATA"; | |
223 reads[index].data = kBadData; | |
224 reads[index].data_len = arraysize(kBadData); | |
225 } else { | |
226 reads[index].result = error; | |
227 reads[index].data = NULL; | |
228 reads[index].data_len = 0; | |
229 } | |
230 reads.resize(index + 1); | |
231 if (error == | |
232 net::ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ) { | |
233 static const char kDummyData[] = "DUMMY"; | |
234 reads.push_back(net::MockRead(mode, kDummyData)); | |
235 } | |
236 break; | |
237 } | |
238 } | |
239 SetData(mock_connect, &reads, &writes); | |
240 | |
241 FakeSSLClientSocket fake_ssl_client_socket(MakeClientSocket()); | |
242 | |
243 // The two errors below are interpreted by FakeSSLClientSocket as | |
244 // an unexpected event. | |
245 int expected_status = | |
246 ((error == net::ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ) || | |
247 (error == ERR_MALFORMED_SERVER_HELLO)) ? | |
248 net::ERR_UNEXPECTED : error; | |
249 | |
250 net::TestCompletionCallback test_completion_callback; | |
251 int status = fake_ssl_client_socket.Connect( | |
252 test_completion_callback.callback()); | |
253 EXPECT_FALSE(fake_ssl_client_socket.IsConnected()); | |
254 ExpectStatus(mode, expected_status, status, &test_completion_callback); | |
255 EXPECT_FALSE(fake_ssl_client_socket.IsConnected()); | |
256 } | |
257 | |
258 void RunUnsuccessfulHandshakeTest( | |
259 int error, HandshakeErrorLocation location) { | |
260 RunUnsuccessfulHandshakeTestHelper(net::SYNCHRONOUS, error, location); | |
261 RunUnsuccessfulHandshakeTestHelper(net::ASYNC, error, location); | |
262 } | |
263 | |
264 // MockTCPClientSocket needs a message loop. | |
265 MessageLoop message_loop_; | |
266 | |
267 net::MockClientSocketFactory mock_client_socket_factory_; | |
268 scoped_ptr<net::StaticSocketDataProvider> static_socket_data_provider_; | |
269 }; | |
270 | |
271 TEST_F(FakeSSLClientSocketTest, PassThroughMethods) { | |
272 MockClientSocket* mock_client_socket = new MockClientSocket(); | |
273 const int kReceiveBufferSize = 10; | |
274 const int kSendBufferSize = 20; | |
275 net::IPEndPoint ip_endpoint(net::IPAddressNumber(net::kIPv4AddressSize), 80); | |
276 const int kPeerAddress = 30; | |
277 net::BoundNetLog net_log; | |
278 EXPECT_CALL(*mock_client_socket, SetReceiveBufferSize(kReceiveBufferSize)); | |
279 EXPECT_CALL(*mock_client_socket, SetSendBufferSize(kSendBufferSize)); | |
280 EXPECT_CALL(*mock_client_socket, GetPeerAddress(&ip_endpoint)). | |
281 WillOnce(Return(kPeerAddress)); | |
282 EXPECT_CALL(*mock_client_socket, NetLog()).WillOnce(ReturnRef(net_log)); | |
283 EXPECT_CALL(*mock_client_socket, SetSubresourceSpeculation()); | |
284 EXPECT_CALL(*mock_client_socket, SetOmniboxSpeculation()); | |
285 | |
286 // Takes ownership of |mock_client_socket|. | |
287 FakeSSLClientSocket fake_ssl_client_socket(mock_client_socket); | |
288 fake_ssl_client_socket.SetReceiveBufferSize(kReceiveBufferSize); | |
289 fake_ssl_client_socket.SetSendBufferSize(kSendBufferSize); | |
290 EXPECT_EQ(kPeerAddress, | |
291 fake_ssl_client_socket.GetPeerAddress(&ip_endpoint)); | |
292 EXPECT_EQ(&net_log, &fake_ssl_client_socket.NetLog()); | |
293 fake_ssl_client_socket.SetSubresourceSpeculation(); | |
294 fake_ssl_client_socket.SetOmniboxSpeculation(); | |
295 } | |
296 | |
297 TEST_F(FakeSSLClientSocketTest, SuccessfulHandshakeSync) { | |
298 for (size_t i = 1; i < 100; i += 3) { | |
299 SCOPED_TRACE(i); | |
300 for (size_t j = 1; j < 100; j += 5) { | |
301 SCOPED_TRACE(j); | |
302 RunSuccessfulHandshakeTest(net::SYNCHRONOUS, i, j, 0); | |
303 } | |
304 } | |
305 } | |
306 | |
307 TEST_F(FakeSSLClientSocketTest, SuccessfulHandshakeAsync) { | |
308 for (size_t i = 1; i < 100; i += 7) { | |
309 SCOPED_TRACE(i); | |
310 for (size_t j = 1; j < 100; j += 9) { | |
311 SCOPED_TRACE(j); | |
312 RunSuccessfulHandshakeTest(net::ASYNC, i, j, 0); | |
313 } | |
314 } | |
315 } | |
316 | |
317 TEST_F(FakeSSLClientSocketTest, ResetSocket) { | |
318 RunSuccessfulHandshakeTest(net::ASYNC, 1, 2, 3); | |
319 } | |
320 | |
321 TEST_F(FakeSSLClientSocketTest, UnsuccessfulHandshakeConnectError) { | |
322 RunUnsuccessfulHandshakeTest(net::ERR_ACCESS_DENIED, CONNECT_ERROR); | |
323 } | |
324 | |
325 TEST_F(FakeSSLClientSocketTest, UnsuccessfulHandshakeWriteError) { | |
326 RunUnsuccessfulHandshakeTest(net::ERR_OUT_OF_MEMORY, | |
327 SEND_CLIENT_HELLO_ERROR); | |
328 } | |
329 | |
330 TEST_F(FakeSSLClientSocketTest, UnsuccessfulHandshakeReadError) { | |
331 RunUnsuccessfulHandshakeTest(net::ERR_CONNECTION_CLOSED, | |
332 VERIFY_SERVER_HELLO_ERROR); | |
333 } | |
334 | |
335 TEST_F(FakeSSLClientSocketTest, PeerClosedDuringHandshake) { | |
336 RunUnsuccessfulHandshakeTest( | |
337 net::ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ, | |
338 VERIFY_SERVER_HELLO_ERROR); | |
339 } | |
340 | |
341 TEST_F(FakeSSLClientSocketTest, MalformedServerHello) { | |
342 RunUnsuccessfulHandshakeTest(ERR_MALFORMED_SERVER_HELLO, | |
343 VERIFY_SERVER_HELLO_ERROR); | |
344 } | |
345 | |
346 } // namespace | |
347 | |
348 } // namespace notifier | |
OLD | NEW |