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 "net/spdy/spdy_proxy_client_socket.h" | |
6 | |
7 #include <memory> | |
8 #include <utility> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/bind_helpers.h" | |
12 #include "base/macros.h" | |
13 #include "base/run_loop.h" | |
14 #include "base/strings/utf_string_conversions.h" | |
15 #include "net/base/address_list.h" | |
16 #include "net/base/test_completion_callback.h" | |
17 #include "net/base/winsock_init.h" | |
18 #include "net/dns/mock_host_resolver.h" | |
19 #include "net/http/http_response_headers.h" | |
20 #include "net/http/http_response_info.h" | |
21 #include "net/log/net_log_event_type.h" | |
22 #include "net/log/net_log_source.h" | |
23 #include "net/log/test_net_log.h" | |
24 #include "net/log/test_net_log_entry.h" | |
25 #include "net/log/test_net_log_util.h" | |
26 #include "net/socket/client_socket_factory.h" | |
27 #include "net/socket/socket_test_util.h" | |
28 #include "net/socket/tcp_client_socket.h" | |
29 #include "net/spdy/buffered_spdy_framer.h" | |
30 #include "net/spdy/spdy_http_utils.h" | |
31 #include "net/spdy/spdy_protocol.h" | |
32 #include "net/spdy/spdy_session_pool.h" | |
33 #include "net/spdy/spdy_test_util_common.h" | |
34 #include "net/test/cert_test_util.h" | |
35 #include "net/test/gtest_util.h" | |
36 #include "net/test/test_data_directory.h" | |
37 #include "testing/gmock/include/gmock/gmock.h" | |
38 #include "testing/gtest/include/gtest/gtest.h" | |
39 #include "testing/platform_test.h" | |
40 | |
41 using net::test::IsError; | |
42 using net::test::IsOk; | |
43 | |
44 //----------------------------------------------------------------------------- | |
45 | |
46 namespace { | |
47 | |
48 static const char kRequestUrl[] = "https://www.google.com/"; | |
49 static const char kOriginHost[] = "www.google.com"; | |
50 static const int kOriginPort = 443; | |
51 static const char kOriginHostPort[] = "www.google.com:443"; | |
52 static const char kProxyUrl[] = "https://myproxy:6121/"; | |
53 static const char kProxyHost[] = "myproxy"; | |
54 static const int kProxyPort = 6121; | |
55 static const char kUserAgent[] = "Mozilla/1.0"; | |
56 | |
57 static const int kStreamId = 1; | |
58 | |
59 static const char kMsg1[] = "\0hello!\xff"; | |
60 static const int kLen1 = 8; | |
61 static const char kMsg2[] = "\0a2345678\0"; | |
62 static const int kLen2 = 10; | |
63 static const char kMsg3[] = "bye!"; | |
64 static const int kLen3 = 4; | |
65 static const char kMsg33[] = "bye!bye!"; | |
66 static const int kLen33 = kLen3 + kLen3; | |
67 static const char kMsg333[] = "bye!bye!bye!"; | |
68 static const int kLen333 = kLen3 + kLen3 + kLen3; | |
69 | |
70 static const char kRedirectUrl[] = "https://example.com/"; | |
71 | |
72 } // anonymous namespace | |
73 | |
74 namespace net { | |
75 | |
76 class SpdyProxyClientSocketTest : public PlatformTest { | |
77 public: | |
78 SpdyProxyClientSocketTest(); | |
79 ~SpdyProxyClientSocketTest() override; | |
80 | |
81 void TearDown() override; | |
82 | |
83 protected: | |
84 void Initialize(MockRead* reads, size_t reads_count, MockWrite* writes, | |
85 size_t writes_count); | |
86 void PopulateConnectRequestIR(SpdyHeaderBlock* syn_ir); | |
87 void PopulateConnectReplyIR(SpdyHeaderBlock* block, const char* status); | |
88 SpdySerializedFrame ConstructConnectRequestFrame(); | |
89 SpdySerializedFrame ConstructConnectAuthRequestFrame(); | |
90 SpdySerializedFrame ConstructConnectReplyFrame(); | |
91 SpdySerializedFrame ConstructConnectAuthReplyFrame(); | |
92 SpdySerializedFrame ConstructConnectRedirectReplyFrame(); | |
93 SpdySerializedFrame ConstructConnectErrorReplyFrame(); | |
94 SpdySerializedFrame ConstructBodyFrame(const char* data, int length); | |
95 scoped_refptr<IOBufferWithSize> CreateBuffer(const char* data, int size); | |
96 void AssertConnectSucceeds(); | |
97 void AssertConnectFails(int result); | |
98 void AssertConnectionEstablished(); | |
99 void AssertSyncReadEquals(const char* data, int len); | |
100 void AssertAsyncReadEquals(const char* data, int len); | |
101 void AssertReadStarts(const char* data, int len); | |
102 void AssertReadReturns(const char* data, int len); | |
103 void AssertAsyncWriteSucceeds(const char* data, int len); | |
104 void AssertWriteReturns(const char* data, int len, int rv); | |
105 void AssertWriteLength(int len); | |
106 | |
107 void AddAuthToCache() { | |
108 const base::string16 kFoo(base::ASCIIToUTF16("foo")); | |
109 const base::string16 kBar(base::ASCIIToUTF16("bar")); | |
110 session_->http_auth_cache()->Add(GURL(kProxyUrl), | |
111 "MyRealm1", | |
112 HttpAuth::AUTH_SCHEME_BASIC, | |
113 "Basic realm=MyRealm1", | |
114 AuthCredentials(kFoo, kBar), | |
115 "/"); | |
116 } | |
117 | |
118 void ResumeAndRun() { | |
119 // Run until the pause, if the provider isn't paused yet. | |
120 data_->RunUntilPaused(); | |
121 data_->Resume(); | |
122 base::RunLoop().RunUntilIdle(); | |
123 } | |
124 | |
125 void CloseSpdySession(Error error, const SpdyString& description) { | |
126 spdy_session_->CloseSessionOnError(error, description); | |
127 } | |
128 | |
129 SpdyTestUtil spdy_util_; | |
130 std::unique_ptr<SpdyProxyClientSocket> sock_; | |
131 TestCompletionCallback read_callback_; | |
132 TestCompletionCallback write_callback_; | |
133 std::unique_ptr<SequencedSocketData> data_; | |
134 BoundTestNetLog net_log_; | |
135 | |
136 private: | |
137 std::unique_ptr<HttpNetworkSession> session_; | |
138 scoped_refptr<IOBuffer> read_buf_; | |
139 SpdySessionDependencies session_deps_; | |
140 MockConnect connect_data_; | |
141 base::WeakPtr<SpdySession> spdy_session_; | |
142 SpdyString user_agent_; | |
143 GURL url_; | |
144 HostPortPair proxy_host_port_; | |
145 HostPortPair endpoint_host_port_pair_; | |
146 ProxyServer proxy_; | |
147 SpdySessionKey endpoint_spdy_session_key_; | |
148 | |
149 DISALLOW_COPY_AND_ASSIGN(SpdyProxyClientSocketTest); | |
150 }; | |
151 | |
152 SpdyProxyClientSocketTest::SpdyProxyClientSocketTest() | |
153 : read_buf_(NULL), | |
154 connect_data_(SYNCHRONOUS, OK), | |
155 user_agent_(kUserAgent), | |
156 url_(kRequestUrl), | |
157 proxy_host_port_(kProxyHost, kProxyPort), | |
158 endpoint_host_port_pair_(kOriginHost, kOriginPort), | |
159 proxy_(ProxyServer::SCHEME_HTTPS, proxy_host_port_), | |
160 endpoint_spdy_session_key_(endpoint_host_port_pair_, | |
161 proxy_, | |
162 PRIVACY_MODE_DISABLED) { | |
163 session_deps_.net_log = net_log_.bound().net_log(); | |
164 } | |
165 | |
166 SpdyProxyClientSocketTest::~SpdyProxyClientSocketTest() { | |
167 EXPECT_TRUE(data_->AllWriteDataConsumed()); | |
168 EXPECT_TRUE(data_->AllReadDataConsumed()); | |
169 } | |
170 | |
171 void SpdyProxyClientSocketTest::TearDown() { | |
172 if (session_.get() != NULL) | |
173 session_->spdy_session_pool()->CloseAllSessions(); | |
174 | |
175 // Empty the current queue. | |
176 base::RunLoop().RunUntilIdle(); | |
177 PlatformTest::TearDown(); | |
178 } | |
179 | |
180 void SpdyProxyClientSocketTest::Initialize(MockRead* reads, | |
181 size_t reads_count, | |
182 MockWrite* writes, | |
183 size_t writes_count) { | |
184 data_.reset( | |
185 new SequencedSocketData(reads, reads_count, writes, writes_count)); | |
186 data_->set_connect_data(connect_data_); | |
187 session_deps_.socket_factory->AddSocketDataProvider(data_.get()); | |
188 | |
189 SSLSocketDataProvider ssl(SYNCHRONOUS, OK); | |
190 ssl.cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"); | |
191 ASSERT_TRUE(ssl.cert); | |
192 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
193 | |
194 session_deps_.host_resolver->set_synchronous_mode(true); | |
195 | |
196 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); | |
197 | |
198 // Creates the SPDY session and stream. | |
199 spdy_session_ = CreateSecureSpdySession( | |
200 session_.get(), endpoint_spdy_session_key_, NetLogWithSource()); | |
201 base::WeakPtr<SpdyStream> spdy_stream( | |
202 CreateStreamSynchronously( | |
203 SPDY_BIDIRECTIONAL_STREAM, spdy_session_, url_, LOWEST, | |
204 net_log_.bound())); | |
205 ASSERT_TRUE(spdy_stream.get() != NULL); | |
206 | |
207 // Create the SpdyProxyClientSocket. | |
208 sock_.reset(new SpdyProxyClientSocket( | |
209 spdy_stream, user_agent_, endpoint_host_port_pair_, proxy_host_port_, | |
210 net_log_.bound(), | |
211 new HttpAuthController( | |
212 HttpAuth::AUTH_PROXY, GURL("https://" + proxy_host_port_.ToString()), | |
213 session_->http_auth_cache(), session_->http_auth_handler_factory()))); | |
214 } | |
215 | |
216 scoped_refptr<IOBufferWithSize> SpdyProxyClientSocketTest::CreateBuffer( | |
217 const char* data, int size) { | |
218 scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(size)); | |
219 memcpy(buf->data(), data, size); | |
220 return buf; | |
221 } | |
222 | |
223 void SpdyProxyClientSocketTest::AssertConnectSucceeds() { | |
224 ASSERT_THAT(sock_->Connect(read_callback_.callback()), | |
225 IsError(ERR_IO_PENDING)); | |
226 ASSERT_THAT(read_callback_.WaitForResult(), IsOk()); | |
227 } | |
228 | |
229 void SpdyProxyClientSocketTest::AssertConnectFails(int result) { | |
230 ASSERT_THAT(sock_->Connect(read_callback_.callback()), | |
231 IsError(ERR_IO_PENDING)); | |
232 ASSERT_EQ(result, read_callback_.WaitForResult()); | |
233 } | |
234 | |
235 void SpdyProxyClientSocketTest::AssertConnectionEstablished() { | |
236 const HttpResponseInfo* response = sock_->GetConnectResponseInfo(); | |
237 ASSERT_TRUE(response != NULL); | |
238 ASSERT_EQ(200, response->headers->response_code()); | |
239 } | |
240 | |
241 void SpdyProxyClientSocketTest::AssertSyncReadEquals(const char* data, | |
242 int len) { | |
243 scoped_refptr<IOBuffer> buf(new IOBuffer(len)); | |
244 ASSERT_EQ(len, sock_->Read(buf.get(), len, CompletionCallback())); | |
245 ASSERT_EQ(SpdyString(data, len), SpdyString(buf->data(), len)); | |
246 ASSERT_TRUE(sock_->IsConnected()); | |
247 } | |
248 | |
249 void SpdyProxyClientSocketTest::AssertAsyncReadEquals(const char* data, | |
250 int len) { | |
251 // Issue the read, which will be completed asynchronously | |
252 scoped_refptr<IOBuffer> buf(new IOBuffer(len)); | |
253 ASSERT_EQ(ERR_IO_PENDING, | |
254 sock_->Read(buf.get(), len, read_callback_.callback())); | |
255 EXPECT_TRUE(sock_->IsConnected()); | |
256 | |
257 ResumeAndRun(); | |
258 | |
259 EXPECT_EQ(len, read_callback_.WaitForResult()); | |
260 EXPECT_TRUE(sock_->IsConnected()); | |
261 ASSERT_EQ(SpdyString(data, len), SpdyString(buf->data(), len)); | |
262 } | |
263 | |
264 void SpdyProxyClientSocketTest::AssertReadStarts(const char* data, int len) { | |
265 // Issue the read, which will be completed asynchronously. | |
266 read_buf_ = new IOBuffer(len); | |
267 ASSERT_EQ(ERR_IO_PENDING, | |
268 sock_->Read(read_buf_.get(), len, read_callback_.callback())); | |
269 EXPECT_TRUE(sock_->IsConnected()); | |
270 } | |
271 | |
272 void SpdyProxyClientSocketTest::AssertReadReturns(const char* data, int len) { | |
273 EXPECT_TRUE(sock_->IsConnected()); | |
274 | |
275 // Now the read will return | |
276 EXPECT_EQ(len, read_callback_.WaitForResult()); | |
277 ASSERT_EQ(SpdyString(data, len), SpdyString(read_buf_->data(), len)); | |
278 } | |
279 | |
280 void SpdyProxyClientSocketTest::AssertAsyncWriteSucceeds(const char* data, | |
281 int len) { | |
282 AssertWriteReturns(data, len, ERR_IO_PENDING); | |
283 AssertWriteLength(len); | |
284 } | |
285 | |
286 void SpdyProxyClientSocketTest::AssertWriteReturns(const char* data, | |
287 int len, | |
288 int rv) { | |
289 scoped_refptr<IOBufferWithSize> buf(CreateBuffer(data, len)); | |
290 EXPECT_EQ(rv, | |
291 sock_->Write(buf.get(), buf->size(), write_callback_.callback())); | |
292 } | |
293 | |
294 void SpdyProxyClientSocketTest::AssertWriteLength(int len) { | |
295 EXPECT_EQ(len, write_callback_.WaitForResult()); | |
296 } | |
297 | |
298 void SpdyProxyClientSocketTest::PopulateConnectRequestIR( | |
299 SpdyHeaderBlock* block) { | |
300 (*block)[spdy_util_.GetMethodKey()] = "CONNECT"; | |
301 (*block)[spdy_util_.GetHostKey()] = kOriginHostPort; | |
302 (*block)["user-agent"] = kUserAgent; | |
303 } | |
304 | |
305 void SpdyProxyClientSocketTest::PopulateConnectReplyIR(SpdyHeaderBlock* block, | |
306 const char* status) { | |
307 (*block)[spdy_util_.GetStatusKey()] = status; | |
308 } | |
309 | |
310 // Constructs a standard SPDY HEADERS frame for a CONNECT request. | |
311 SpdySerializedFrame SpdyProxyClientSocketTest::ConstructConnectRequestFrame() { | |
312 SpdyHeaderBlock block; | |
313 PopulateConnectRequestIR(&block); | |
314 return spdy_util_.ConstructSpdyHeaders(kStreamId, std::move(block), LOWEST, | |
315 false); | |
316 } | |
317 | |
318 // Constructs a SPDY HEADERS frame for a CONNECT request which includes | |
319 // Proxy-Authorization headers. | |
320 SpdySerializedFrame | |
321 SpdyProxyClientSocketTest::ConstructConnectAuthRequestFrame() { | |
322 SpdyHeaderBlock block; | |
323 PopulateConnectRequestIR(&block); | |
324 block["proxy-authorization"] = "Basic Zm9vOmJhcg=="; | |
325 return spdy_util_.ConstructSpdyHeaders(kStreamId, std::move(block), LOWEST, | |
326 false); | |
327 } | |
328 | |
329 // Constructs a standard SPDY HEADERS frame to match the SPDY CONNECT. | |
330 SpdySerializedFrame SpdyProxyClientSocketTest::ConstructConnectReplyFrame() { | |
331 SpdyHeaderBlock block; | |
332 PopulateConnectReplyIR(&block, "200"); | |
333 return spdy_util_.ConstructSpdyReply(kStreamId, std::move(block)); | |
334 } | |
335 | |
336 // Constructs a standard SPDY HEADERS frame to match the SPDY CONNECT, | |
337 // including Proxy-Authenticate headers. | |
338 SpdySerializedFrame | |
339 SpdyProxyClientSocketTest::ConstructConnectAuthReplyFrame() { | |
340 SpdyHeaderBlock block; | |
341 PopulateConnectReplyIR(&block, "407"); | |
342 block["proxy-authenticate"] = "Basic realm=\"MyRealm1\""; | |
343 return spdy_util_.ConstructSpdyReply(kStreamId, std::move(block)); | |
344 } | |
345 | |
346 // Constructs a SPDY HEADERS frame with an HTTP 302 redirect. | |
347 SpdySerializedFrame | |
348 SpdyProxyClientSocketTest::ConstructConnectRedirectReplyFrame() { | |
349 SpdyHeaderBlock block; | |
350 PopulateConnectReplyIR(&block, "302"); | |
351 block["location"] = kRedirectUrl; | |
352 block["set-cookie"] = "foo=bar"; | |
353 return spdy_util_.ConstructSpdyReply(kStreamId, std::move(block)); | |
354 } | |
355 | |
356 // Constructs a SPDY HEADERS frame with an HTTP 500 error. | |
357 SpdySerializedFrame | |
358 SpdyProxyClientSocketTest::ConstructConnectErrorReplyFrame() { | |
359 SpdyHeaderBlock block; | |
360 PopulateConnectReplyIR(&block, "500"); | |
361 return spdy_util_.ConstructSpdyReply(kStreamId, std::move(block)); | |
362 } | |
363 | |
364 SpdySerializedFrame SpdyProxyClientSocketTest::ConstructBodyFrame( | |
365 const char* data, | |
366 int length) { | |
367 return spdy_util_.ConstructSpdyDataFrame(kStreamId, data, length, | |
368 /*fin=*/false); | |
369 } | |
370 | |
371 // ----------- Connect | |
372 | |
373 TEST_F(SpdyProxyClientSocketTest, ConnectSendsCorrectRequest) { | |
374 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
375 MockWrite writes[] = { | |
376 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
377 }; | |
378 | |
379 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
380 MockRead reads[] = { | |
381 CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2), | |
382 }; | |
383 | |
384 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
385 | |
386 ASSERT_FALSE(sock_->IsConnected()); | |
387 | |
388 AssertConnectSucceeds(); | |
389 | |
390 AssertConnectionEstablished(); | |
391 } | |
392 | |
393 TEST_F(SpdyProxyClientSocketTest, ConnectWithAuthRequested) { | |
394 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
395 MockWrite writes[] = { | |
396 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
397 }; | |
398 | |
399 SpdySerializedFrame resp(ConstructConnectAuthReplyFrame()); | |
400 MockRead reads[] = { | |
401 CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2), | |
402 }; | |
403 | |
404 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
405 | |
406 AssertConnectFails(ERR_PROXY_AUTH_REQUESTED); | |
407 | |
408 const HttpResponseInfo* response = sock_->GetConnectResponseInfo(); | |
409 ASSERT_TRUE(response != NULL); | |
410 ASSERT_EQ(407, response->headers->response_code()); | |
411 } | |
412 | |
413 TEST_F(SpdyProxyClientSocketTest, ConnectWithAuthCredentials) { | |
414 SpdySerializedFrame conn(ConstructConnectAuthRequestFrame()); | |
415 MockWrite writes[] = { | |
416 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
417 }; | |
418 | |
419 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
420 MockRead reads[] = { | |
421 CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2), | |
422 }; | |
423 | |
424 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
425 AddAuthToCache(); | |
426 | |
427 AssertConnectSucceeds(); | |
428 | |
429 AssertConnectionEstablished(); | |
430 } | |
431 | |
432 TEST_F(SpdyProxyClientSocketTest, ConnectRedirects) { | |
433 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
434 SpdySerializedFrame rst( | |
435 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_CANCEL)); | |
436 MockWrite writes[] = { | |
437 CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3), | |
438 }; | |
439 | |
440 SpdySerializedFrame resp(ConstructConnectRedirectReplyFrame()); | |
441 MockRead reads[] = { | |
442 CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2), | |
443 }; | |
444 | |
445 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
446 | |
447 AssertConnectFails(ERR_HTTPS_PROXY_TUNNEL_RESPONSE); | |
448 | |
449 const HttpResponseInfo* response = sock_->GetConnectResponseInfo(); | |
450 ASSERT_TRUE(response != NULL); | |
451 | |
452 const HttpResponseHeaders* headers = response->headers.get(); | |
453 ASSERT_EQ(302, headers->response_code()); | |
454 ASSERT_FALSE(headers->HasHeader("set-cookie")); | |
455 ASSERT_TRUE(headers->HasHeaderValue("content-length", "0")); | |
456 | |
457 SpdyString location; | |
458 ASSERT_TRUE(headers->IsRedirect(&location)); | |
459 ASSERT_EQ(location, kRedirectUrl); | |
460 | |
461 // Let the RST_STREAM write while |rst| is in-scope. | |
462 base::RunLoop().RunUntilIdle(); | |
463 } | |
464 | |
465 TEST_F(SpdyProxyClientSocketTest, ConnectFails) { | |
466 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
467 MockWrite writes[] = { | |
468 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
469 }; | |
470 | |
471 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
472 MockRead reads[] = { | |
473 MockRead(ASYNC, 0, 1), // EOF | |
474 }; | |
475 | |
476 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
477 | |
478 ASSERT_FALSE(sock_->IsConnected()); | |
479 | |
480 AssertConnectFails(ERR_CONNECTION_CLOSED); | |
481 | |
482 ASSERT_FALSE(sock_->IsConnected()); | |
483 } | |
484 | |
485 // ----------- WasEverUsed | |
486 | |
487 TEST_F(SpdyProxyClientSocketTest, WasEverUsedReturnsCorrectValues) { | |
488 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
489 SpdySerializedFrame rst( | |
490 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_CANCEL)); | |
491 MockWrite writes[] = { | |
492 CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3), | |
493 }; | |
494 | |
495 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
496 MockRead reads[] = { | |
497 CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2), | |
498 }; | |
499 | |
500 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
501 | |
502 EXPECT_FALSE(sock_->WasEverUsed()); | |
503 AssertConnectSucceeds(); | |
504 EXPECT_TRUE(sock_->WasEverUsed()); | |
505 sock_->Disconnect(); | |
506 EXPECT_TRUE(sock_->WasEverUsed()); | |
507 | |
508 // Let the RST_STREAM write while |rst| is in-scope. | |
509 base::RunLoop().RunUntilIdle(); | |
510 } | |
511 | |
512 // ----------- GetPeerAddress | |
513 | |
514 TEST_F(SpdyProxyClientSocketTest, GetPeerAddressReturnsCorrectValues) { | |
515 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
516 MockWrite writes[] = { | |
517 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
518 }; | |
519 | |
520 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
521 MockRead reads[] = { | |
522 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
523 MockRead(ASYNC, 0, 3), // EOF | |
524 }; | |
525 | |
526 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
527 | |
528 IPEndPoint addr; | |
529 EXPECT_THAT(sock_->GetPeerAddress(&addr), IsError(ERR_SOCKET_NOT_CONNECTED)); | |
530 | |
531 AssertConnectSucceeds(); | |
532 EXPECT_TRUE(sock_->IsConnected()); | |
533 EXPECT_THAT(sock_->GetPeerAddress(&addr), IsOk()); | |
534 | |
535 ResumeAndRun(); | |
536 | |
537 EXPECT_FALSE(sock_->IsConnected()); | |
538 EXPECT_THAT(sock_->GetPeerAddress(&addr), IsError(ERR_SOCKET_NOT_CONNECTED)); | |
539 | |
540 sock_->Disconnect(); | |
541 | |
542 EXPECT_THAT(sock_->GetPeerAddress(&addr), IsError(ERR_SOCKET_NOT_CONNECTED)); | |
543 } | |
544 | |
545 // ----------- Write | |
546 | |
547 TEST_F(SpdyProxyClientSocketTest, WriteSendsDataInDataFrame) { | |
548 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
549 SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
550 SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
551 MockWrite writes[] = { | |
552 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
553 CreateMockWrite(msg1, 3, SYNCHRONOUS), | |
554 CreateMockWrite(msg2, 4, SYNCHRONOUS), | |
555 }; | |
556 | |
557 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
558 MockRead reads[] = { | |
559 CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2), | |
560 }; | |
561 | |
562 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
563 | |
564 AssertConnectSucceeds(); | |
565 | |
566 AssertAsyncWriteSucceeds(kMsg1, kLen1); | |
567 AssertAsyncWriteSucceeds(kMsg2, kLen2); | |
568 } | |
569 | |
570 TEST_F(SpdyProxyClientSocketTest, WriteSplitsLargeDataIntoMultipleFrames) { | |
571 SpdyString chunk_data(kMaxSpdyFrameChunkSize, 'x'); | |
572 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
573 SpdySerializedFrame chunk( | |
574 ConstructBodyFrame(chunk_data.data(), chunk_data.length())); | |
575 MockWrite writes[] = {CreateMockWrite(conn, 0, SYNCHRONOUS), | |
576 CreateMockWrite(chunk, 3, SYNCHRONOUS), | |
577 CreateMockWrite(chunk, 4, SYNCHRONOUS), | |
578 CreateMockWrite(chunk, 5, SYNCHRONOUS)}; | |
579 | |
580 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
581 MockRead reads[] = { | |
582 CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2), | |
583 }; | |
584 | |
585 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
586 | |
587 AssertConnectSucceeds(); | |
588 | |
589 SpdyString big_data(kMaxSpdyFrameChunkSize * 3, 'x'); | |
590 scoped_refptr<IOBufferWithSize> buf(CreateBuffer(big_data.data(), | |
591 big_data.length())); | |
592 | |
593 EXPECT_EQ(ERR_IO_PENDING, | |
594 sock_->Write(buf.get(), buf->size(), write_callback_.callback())); | |
595 EXPECT_EQ(buf->size(), write_callback_.WaitForResult()); | |
596 } | |
597 | |
598 // ----------- Read | |
599 | |
600 TEST_F(SpdyProxyClientSocketTest, ReadReadsDataInDataFrame) { | |
601 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
602 MockWrite writes[] = { | |
603 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
604 }; | |
605 | |
606 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
607 SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
608 MockRead reads[] = { | |
609 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
610 CreateMockRead(msg1, 3, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4), | |
611 }; | |
612 | |
613 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
614 | |
615 AssertConnectSucceeds(); | |
616 | |
617 // SpdySession consumes the next read and sends it to sock_ to be buffered. | |
618 ResumeAndRun(); | |
619 AssertSyncReadEquals(kMsg1, kLen1); | |
620 } | |
621 | |
622 TEST_F(SpdyProxyClientSocketTest, ReadDataFromBufferedFrames) { | |
623 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
624 MockWrite writes[] = { | |
625 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
626 }; | |
627 | |
628 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
629 SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
630 SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
631 MockRead reads[] = { | |
632 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
633 CreateMockRead(msg1, 3, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 4), | |
634 CreateMockRead(msg2, 5, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), | |
635 }; | |
636 | |
637 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
638 | |
639 AssertConnectSucceeds(); | |
640 | |
641 // SpdySession consumes the next read and sends it to sock_ to be buffered. | |
642 ResumeAndRun(); | |
643 AssertSyncReadEquals(kMsg1, kLen1); | |
644 // SpdySession consumes the next read and sends it to sock_ to be buffered. | |
645 ResumeAndRun(); | |
646 AssertSyncReadEquals(kMsg2, kLen2); | |
647 } | |
648 | |
649 TEST_F(SpdyProxyClientSocketTest, ReadDataMultipleBufferedFrames) { | |
650 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
651 MockWrite writes[] = { | |
652 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
653 }; | |
654 | |
655 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
656 SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
657 SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
658 MockRead reads[] = { | |
659 CreateMockRead(resp, 1, ASYNC), | |
660 MockRead(ASYNC, ERR_IO_PENDING, 2), | |
661 CreateMockRead(msg1, 3, ASYNC), | |
662 CreateMockRead(msg2, 4, ASYNC), | |
663 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), | |
664 }; | |
665 | |
666 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
667 | |
668 AssertConnectSucceeds(); | |
669 | |
670 // SpdySession consumes the next two reads and sends then to sock_ to be | |
671 // buffered. | |
672 ResumeAndRun(); | |
673 AssertSyncReadEquals(kMsg1, kLen1); | |
674 AssertSyncReadEquals(kMsg2, kLen2); | |
675 } | |
676 | |
677 TEST_F(SpdyProxyClientSocketTest, LargeReadWillMergeDataFromDifferentFrames) { | |
678 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
679 MockWrite writes[] = { | |
680 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
681 }; | |
682 | |
683 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
684 SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
685 SpdySerializedFrame msg3(ConstructBodyFrame(kMsg3, kLen3)); | |
686 MockRead reads[] = { | |
687 CreateMockRead(resp, 1, ASYNC), | |
688 MockRead(ASYNC, ERR_IO_PENDING, 2), | |
689 CreateMockRead(msg3, 3, ASYNC), | |
690 CreateMockRead(msg3, 4, ASYNC), | |
691 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), | |
692 }; | |
693 | |
694 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
695 | |
696 AssertConnectSucceeds(); | |
697 | |
698 // SpdySession consumes the next two reads and sends then to sock_ to be | |
699 // buffered. | |
700 ResumeAndRun(); | |
701 // The payload from two data frames, each with kMsg3 will be combined | |
702 // together into a single read(). | |
703 AssertSyncReadEquals(kMsg33, kLen33); | |
704 } | |
705 | |
706 TEST_F(SpdyProxyClientSocketTest, MultipleShortReadsThenMoreRead) { | |
707 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
708 MockWrite writes[] = { | |
709 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
710 }; | |
711 | |
712 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
713 SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
714 SpdySerializedFrame msg3(ConstructBodyFrame(kMsg3, kLen3)); | |
715 SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
716 MockRead reads[] = { | |
717 CreateMockRead(resp, 1, ASYNC), | |
718 MockRead(ASYNC, ERR_IO_PENDING, 2), | |
719 CreateMockRead(msg1, 3, ASYNC), | |
720 CreateMockRead(msg3, 4, ASYNC), | |
721 CreateMockRead(msg3, 5, ASYNC), | |
722 CreateMockRead(msg2, 6, ASYNC), | |
723 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 7), | |
724 }; | |
725 | |
726 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
727 | |
728 AssertConnectSucceeds(); | |
729 | |
730 // SpdySession consumes the next four reads and sends then to sock_ to be | |
731 // buffered. | |
732 ResumeAndRun(); | |
733 AssertSyncReadEquals(kMsg1, kLen1); | |
734 // The payload from two data frames, each with kMsg3 will be combined | |
735 // together into a single read(). | |
736 AssertSyncReadEquals(kMsg33, kLen33); | |
737 AssertSyncReadEquals(kMsg2, kLen2); | |
738 } | |
739 | |
740 TEST_F(SpdyProxyClientSocketTest, ReadWillSplitDataFromLargeFrame) { | |
741 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
742 MockWrite writes[] = { | |
743 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
744 }; | |
745 | |
746 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
747 SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
748 SpdySerializedFrame msg33(ConstructBodyFrame(kMsg33, kLen33)); | |
749 SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
750 MockRead reads[] = { | |
751 CreateMockRead(resp, 1, ASYNC), | |
752 MockRead(ASYNC, ERR_IO_PENDING, 2), | |
753 CreateMockRead(msg1, 3, ASYNC), | |
754 CreateMockRead(msg33, 4, ASYNC), | |
755 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), | |
756 }; | |
757 | |
758 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
759 | |
760 AssertConnectSucceeds(); | |
761 | |
762 // SpdySession consumes the next two reads and sends then to sock_ to be | |
763 // buffered. | |
764 ResumeAndRun(); | |
765 AssertSyncReadEquals(kMsg1, kLen1); | |
766 // The payload from the single large data frame will be read across | |
767 // two different reads. | |
768 AssertSyncReadEquals(kMsg3, kLen3); | |
769 AssertSyncReadEquals(kMsg3, kLen3); | |
770 } | |
771 | |
772 TEST_F(SpdyProxyClientSocketTest, MultipleReadsFromSameLargeFrame) { | |
773 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
774 MockWrite writes[] = { | |
775 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
776 }; | |
777 | |
778 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
779 SpdySerializedFrame msg333(ConstructBodyFrame(kMsg333, kLen333)); | |
780 MockRead reads[] = { | |
781 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
782 CreateMockRead(msg333, 3, ASYNC), | |
783 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4), | |
784 }; | |
785 | |
786 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
787 | |
788 AssertConnectSucceeds(); | |
789 | |
790 // SpdySession consumes the next read and sends it to sock_ to be buffered. | |
791 ResumeAndRun(); | |
792 // The payload from the single large data frame will be read across | |
793 // two different reads. | |
794 AssertSyncReadEquals(kMsg33, kLen33); | |
795 | |
796 // Now attempt to do a read of more data than remains buffered | |
797 scoped_refptr<IOBuffer> buf(new IOBuffer(kLen33)); | |
798 ASSERT_EQ(kLen3, sock_->Read(buf.get(), kLen33, read_callback_.callback())); | |
799 ASSERT_EQ(SpdyString(kMsg3, kLen3), SpdyString(buf->data(), kLen3)); | |
800 ASSERT_TRUE(sock_->IsConnected()); | |
801 } | |
802 | |
803 TEST_F(SpdyProxyClientSocketTest, ReadAuthResponseBody) { | |
804 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
805 MockWrite writes[] = { | |
806 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
807 }; | |
808 | |
809 SpdySerializedFrame resp(ConstructConnectAuthReplyFrame()); | |
810 SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
811 SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
812 MockRead reads[] = { | |
813 CreateMockRead(resp, 1, ASYNC), | |
814 MockRead(ASYNC, ERR_IO_PENDING, 2), | |
815 CreateMockRead(msg1, 3, ASYNC), | |
816 CreateMockRead(msg2, 4, ASYNC), | |
817 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), | |
818 }; | |
819 | |
820 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
821 | |
822 AssertConnectFails(ERR_PROXY_AUTH_REQUESTED); | |
823 | |
824 // SpdySession consumes the next two reads and sends then to sock_ to be | |
825 // buffered. | |
826 ResumeAndRun(); | |
827 AssertSyncReadEquals(kMsg1, kLen1); | |
828 AssertSyncReadEquals(kMsg2, kLen2); | |
829 } | |
830 | |
831 TEST_F(SpdyProxyClientSocketTest, ReadErrorResponseBody) { | |
832 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
833 MockWrite writes[] = { | |
834 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
835 }; | |
836 | |
837 SpdySerializedFrame resp(ConstructConnectErrorReplyFrame()); | |
838 SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
839 SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
840 MockRead reads[] = { | |
841 CreateMockRead(resp, 1, ASYNC), CreateMockRead(msg1, 2, SYNCHRONOUS), | |
842 CreateMockRead(msg2, 3, SYNCHRONOUS), MockRead(SYNCHRONOUS, 0, 4), // EOF | |
843 }; | |
844 | |
845 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
846 | |
847 AssertConnectFails(ERR_TUNNEL_CONNECTION_FAILED); | |
848 } | |
849 | |
850 // ----------- Reads and Writes | |
851 | |
852 TEST_F(SpdyProxyClientSocketTest, AsyncReadAroundWrite) { | |
853 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
854 SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
855 MockWrite writes[] = { | |
856 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
857 CreateMockWrite(msg2, 4, SYNCHRONOUS), | |
858 }; | |
859 | |
860 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
861 SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
862 SpdySerializedFrame msg3(ConstructBodyFrame(kMsg3, kLen3)); | |
863 MockRead reads[] = { | |
864 CreateMockRead(resp, 1, ASYNC), | |
865 MockRead(ASYNC, ERR_IO_PENDING, 2), | |
866 CreateMockRead(msg1, 3, ASYNC), // sync read | |
867 MockRead(ASYNC, ERR_IO_PENDING, 5), | |
868 CreateMockRead(msg3, 6, ASYNC), // async read | |
869 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 7), | |
870 }; | |
871 | |
872 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
873 | |
874 AssertConnectSucceeds(); | |
875 | |
876 ResumeAndRun(); | |
877 AssertSyncReadEquals(kMsg1, kLen1); | |
878 | |
879 AssertReadStarts(kMsg3, kLen3); | |
880 // Read should block until after the write succeeds. | |
881 | |
882 AssertAsyncWriteSucceeds(kMsg2, kLen2); // Advances past paused read. | |
883 | |
884 ASSERT_FALSE(read_callback_.have_result()); | |
885 ResumeAndRun(); | |
886 // Now the read will return. | |
887 AssertReadReturns(kMsg3, kLen3); | |
888 } | |
889 | |
890 TEST_F(SpdyProxyClientSocketTest, AsyncWriteAroundReads) { | |
891 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
892 SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2)); | |
893 MockWrite writes[] = { | |
894 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
895 MockWrite(ASYNC, ERR_IO_PENDING, 7), CreateMockWrite(msg2, 8, ASYNC), | |
896 }; | |
897 | |
898 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
899 SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
900 SpdySerializedFrame msg3(ConstructBodyFrame(kMsg3, kLen3)); | |
901 MockRead reads[] = { | |
902 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
903 CreateMockRead(msg1, 3, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 4), | |
904 CreateMockRead(msg3, 5, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), | |
905 }; | |
906 | |
907 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
908 | |
909 AssertConnectSucceeds(); | |
910 | |
911 ResumeAndRun(); | |
912 AssertSyncReadEquals(kMsg1, kLen1); | |
913 // Write should block until the read completes | |
914 AssertWriteReturns(kMsg2, kLen2, ERR_IO_PENDING); | |
915 | |
916 AssertAsyncReadEquals(kMsg3, kLen3); | |
917 | |
918 ASSERT_FALSE(write_callback_.have_result()); | |
919 | |
920 // Now the write will complete | |
921 ResumeAndRun(); | |
922 AssertWriteLength(kLen2); | |
923 } | |
924 | |
925 // ----------- Reading/Writing on Closed socket | |
926 | |
927 // Reading from an already closed socket should return 0 | |
928 TEST_F(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsZero) { | |
929 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
930 MockWrite writes[] = { | |
931 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
932 }; | |
933 | |
934 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
935 MockRead reads[] = { | |
936 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
937 MockRead(ASYNC, 0, 3), // EOF | |
938 }; | |
939 | |
940 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
941 | |
942 AssertConnectSucceeds(); | |
943 | |
944 ResumeAndRun(); | |
945 | |
946 ASSERT_FALSE(sock_->IsConnected()); | |
947 ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback())); | |
948 ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback())); | |
949 ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback())); | |
950 ASSERT_FALSE(sock_->IsConnectedAndIdle()); | |
951 } | |
952 | |
953 // Read pending when socket is closed should return 0 | |
954 TEST_F(SpdyProxyClientSocketTest, PendingReadOnCloseReturnsZero) { | |
955 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
956 MockWrite writes[] = { | |
957 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
958 }; | |
959 | |
960 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
961 MockRead reads[] = { | |
962 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
963 MockRead(ASYNC, 0, 3), // EOF | |
964 }; | |
965 | |
966 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
967 | |
968 AssertConnectSucceeds(); | |
969 | |
970 AssertReadStarts(kMsg1, kLen1); | |
971 | |
972 ResumeAndRun(); | |
973 | |
974 ASSERT_EQ(0, read_callback_.WaitForResult()); | |
975 } | |
976 | |
977 // Reading from a disconnected socket is an error | |
978 TEST_F(SpdyProxyClientSocketTest, ReadOnDisconnectSocketReturnsNotConnected) { | |
979 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
980 SpdySerializedFrame rst( | |
981 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_CANCEL)); | |
982 MockWrite writes[] = { | |
983 CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3), | |
984 }; | |
985 | |
986 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
987 MockRead reads[] = { | |
988 CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2), | |
989 }; | |
990 | |
991 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
992 | |
993 AssertConnectSucceeds(); | |
994 | |
995 sock_->Disconnect(); | |
996 | |
997 ASSERT_EQ(ERR_SOCKET_NOT_CONNECTED, | |
998 sock_->Read(NULL, 1, CompletionCallback())); | |
999 | |
1000 // Let the RST_STREAM write while |rst| is in-scope. | |
1001 base::RunLoop().RunUntilIdle(); | |
1002 } | |
1003 | |
1004 // Reading buffered data from an already closed socket should return | |
1005 // buffered data, then 0. | |
1006 TEST_F(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsBufferedData) { | |
1007 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
1008 MockWrite writes[] = { | |
1009 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
1010 }; | |
1011 | |
1012 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
1013 SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
1014 MockRead reads[] = { | |
1015 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
1016 CreateMockRead(msg1, 3, ASYNC), MockRead(ASYNC, 0, 4), // EOF | |
1017 }; | |
1018 | |
1019 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
1020 | |
1021 AssertConnectSucceeds(); | |
1022 | |
1023 ResumeAndRun(); | |
1024 | |
1025 ASSERT_FALSE(sock_->IsConnected()); | |
1026 scoped_refptr<IOBuffer> buf(new IOBuffer(kLen1)); | |
1027 ASSERT_EQ(kLen1, sock_->Read(buf.get(), kLen1, CompletionCallback())); | |
1028 ASSERT_EQ(SpdyString(kMsg1, kLen1), SpdyString(buf->data(), kLen1)); | |
1029 | |
1030 ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback())); | |
1031 ASSERT_EQ(0, sock_->Read(NULL, 1, CompletionCallback())); | |
1032 sock_->Disconnect(); | |
1033 ASSERT_EQ(ERR_SOCKET_NOT_CONNECTED, | |
1034 sock_->Read(NULL, 1, CompletionCallback())); | |
1035 } | |
1036 | |
1037 // Calling Write() on a closed socket is an error | |
1038 TEST_F(SpdyProxyClientSocketTest, WriteOnClosedStream) { | |
1039 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
1040 MockWrite writes[] = { | |
1041 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
1042 }; | |
1043 | |
1044 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
1045 SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
1046 MockRead reads[] = { | |
1047 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
1048 MockRead(ASYNC, 0, 3), // EOF | |
1049 }; | |
1050 | |
1051 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
1052 | |
1053 AssertConnectSucceeds(); | |
1054 | |
1055 // Read EOF which will close the stream. | |
1056 ResumeAndRun(); | |
1057 scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1)); | |
1058 EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, | |
1059 sock_->Write(buf.get(), buf->size(), CompletionCallback())); | |
1060 } | |
1061 | |
1062 // Calling Write() on a disconnected socket is an error. | |
1063 TEST_F(SpdyProxyClientSocketTest, WriteOnDisconnectedSocket) { | |
1064 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
1065 SpdySerializedFrame rst( | |
1066 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_CANCEL)); | |
1067 MockWrite writes[] = { | |
1068 CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3), | |
1069 }; | |
1070 | |
1071 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
1072 SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
1073 MockRead reads[] = { | |
1074 CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2), | |
1075 }; | |
1076 | |
1077 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
1078 | |
1079 AssertConnectSucceeds(); | |
1080 | |
1081 sock_->Disconnect(); | |
1082 | |
1083 scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1)); | |
1084 EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, | |
1085 sock_->Write(buf.get(), buf->size(), CompletionCallback())); | |
1086 | |
1087 // Let the RST_STREAM write while |rst| is in-scope. | |
1088 base::RunLoop().RunUntilIdle(); | |
1089 } | |
1090 | |
1091 // If the socket is closed with a pending Write(), the callback | |
1092 // should be called with ERR_CONNECTION_CLOSED. | |
1093 TEST_F(SpdyProxyClientSocketTest, WritePendingOnClose) { | |
1094 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
1095 MockWrite writes[] = { | |
1096 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
1097 MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 3), | |
1098 }; | |
1099 | |
1100 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
1101 MockRead reads[] = { | |
1102 CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2), | |
1103 }; | |
1104 | |
1105 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
1106 | |
1107 AssertConnectSucceeds(); | |
1108 | |
1109 EXPECT_TRUE(sock_->IsConnected()); | |
1110 | |
1111 scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1)); | |
1112 EXPECT_EQ(ERR_IO_PENDING, | |
1113 sock_->Write(buf.get(), buf->size(), write_callback_.callback())); | |
1114 // Make sure the write actually starts. | |
1115 base::RunLoop().RunUntilIdle(); | |
1116 | |
1117 CloseSpdySession(ERR_ABORTED, SpdyString()); | |
1118 | |
1119 EXPECT_THAT(write_callback_.WaitForResult(), IsError(ERR_CONNECTION_CLOSED)); | |
1120 } | |
1121 | |
1122 // If the socket is Disconnected with a pending Write(), the callback | |
1123 // should not be called. | |
1124 TEST_F(SpdyProxyClientSocketTest, DisconnectWithWritePending) { | |
1125 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
1126 SpdySerializedFrame rst( | |
1127 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_CANCEL)); | |
1128 MockWrite writes[] = { | |
1129 CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3), | |
1130 }; | |
1131 | |
1132 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
1133 MockRead reads[] = { | |
1134 CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2), | |
1135 }; | |
1136 | |
1137 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
1138 | |
1139 AssertConnectSucceeds(); | |
1140 | |
1141 EXPECT_TRUE(sock_->IsConnected()); | |
1142 | |
1143 scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1)); | |
1144 EXPECT_EQ(ERR_IO_PENDING, | |
1145 sock_->Write(buf.get(), buf->size(), write_callback_.callback())); | |
1146 | |
1147 sock_->Disconnect(); | |
1148 | |
1149 EXPECT_FALSE(sock_->IsConnected()); | |
1150 EXPECT_FALSE(write_callback_.have_result()); | |
1151 | |
1152 // Let the RST_STREAM write while |rst| is in-scope. | |
1153 base::RunLoop().RunUntilIdle(); | |
1154 } | |
1155 | |
1156 // If the socket is Disconnected with a pending Read(), the callback | |
1157 // should not be called. | |
1158 TEST_F(SpdyProxyClientSocketTest, DisconnectWithReadPending) { | |
1159 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
1160 SpdySerializedFrame rst( | |
1161 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_CANCEL)); | |
1162 MockWrite writes[] = { | |
1163 CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3), | |
1164 }; | |
1165 | |
1166 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
1167 MockRead reads[] = { | |
1168 CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2), | |
1169 }; | |
1170 | |
1171 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
1172 | |
1173 AssertConnectSucceeds(); | |
1174 | |
1175 EXPECT_TRUE(sock_->IsConnected()); | |
1176 | |
1177 scoped_refptr<IOBuffer> buf(new IOBuffer(kLen1)); | |
1178 ASSERT_EQ(ERR_IO_PENDING, | |
1179 sock_->Read(buf.get(), kLen1, read_callback_.callback())); | |
1180 | |
1181 sock_->Disconnect(); | |
1182 | |
1183 EXPECT_FALSE(sock_->IsConnected()); | |
1184 EXPECT_FALSE(read_callback_.have_result()); | |
1185 | |
1186 // Let the RST_STREAM write while |rst| is in-scope. | |
1187 base::RunLoop().RunUntilIdle(); | |
1188 } | |
1189 | |
1190 // If the socket is Reset when both a read and write are pending, | |
1191 // both should be called back. | |
1192 TEST_F(SpdyProxyClientSocketTest, RstWithReadAndWritePending) { | |
1193 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
1194 MockWrite writes[] = { | |
1195 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
1196 }; | |
1197 | |
1198 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
1199 SpdySerializedFrame rst( | |
1200 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_CANCEL)); | |
1201 MockRead reads[] = { | |
1202 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
1203 CreateMockRead(rst, 3, ASYNC), MockRead(ASYNC, 0, 4) // EOF | |
1204 }; | |
1205 | |
1206 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
1207 | |
1208 AssertConnectSucceeds(); | |
1209 | |
1210 EXPECT_TRUE(sock_->IsConnected()); | |
1211 | |
1212 scoped_refptr<IOBuffer> read_buf(new IOBuffer(kLen1)); | |
1213 ASSERT_EQ(ERR_IO_PENDING, | |
1214 sock_->Read(read_buf.get(), kLen1, read_callback_.callback())); | |
1215 | |
1216 scoped_refptr<IOBufferWithSize> write_buf(CreateBuffer(kMsg1, kLen1)); | |
1217 EXPECT_EQ( | |
1218 ERR_IO_PENDING, | |
1219 sock_->Write( | |
1220 write_buf.get(), write_buf->size(), write_callback_.callback())); | |
1221 | |
1222 ResumeAndRun(); | |
1223 | |
1224 EXPECT_TRUE(sock_.get()); | |
1225 EXPECT_TRUE(read_callback_.have_result()); | |
1226 EXPECT_TRUE(write_callback_.have_result()); | |
1227 | |
1228 // Let the RST_STREAM write while |rst| is in-scope. | |
1229 base::RunLoop().RunUntilIdle(); | |
1230 } | |
1231 | |
1232 // Makes sure the proxy client socket's source gets the expected NetLog events | |
1233 // and only the expected NetLog events (No SpdySession events). | |
1234 TEST_F(SpdyProxyClientSocketTest, NetLog) { | |
1235 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
1236 SpdySerializedFrame rst( | |
1237 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_CANCEL)); | |
1238 MockWrite writes[] = { | |
1239 CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 5), | |
1240 }; | |
1241 | |
1242 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
1243 SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1)); | |
1244 MockRead reads[] = { | |
1245 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
1246 CreateMockRead(msg1, 3, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4), | |
1247 }; | |
1248 | |
1249 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
1250 | |
1251 AssertConnectSucceeds(); | |
1252 | |
1253 // SpdySession consumes the next read and sends it to sock_ to be buffered. | |
1254 ResumeAndRun(); | |
1255 AssertSyncReadEquals(kMsg1, kLen1); | |
1256 | |
1257 NetLogSource sock_source = sock_->NetLog().source(); | |
1258 sock_.reset(); | |
1259 | |
1260 TestNetLogEntry::List entry_list; | |
1261 net_log_.GetEntriesForSource(sock_source, &entry_list); | |
1262 | |
1263 ASSERT_EQ(entry_list.size(), 10u); | |
1264 EXPECT_TRUE( | |
1265 LogContainsBeginEvent(entry_list, 0, NetLogEventType::SOCKET_ALIVE)); | |
1266 EXPECT_TRUE(LogContainsEvent(entry_list, 1, | |
1267 NetLogEventType::HTTP2_PROXY_CLIENT_SESSION, | |
1268 NetLogEventPhase::NONE)); | |
1269 EXPECT_TRUE(LogContainsBeginEvent( | |
1270 entry_list, 2, NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST)); | |
1271 EXPECT_TRUE(LogContainsEvent( | |
1272 entry_list, 3, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
1273 NetLogEventPhase::NONE)); | |
1274 EXPECT_TRUE(LogContainsEndEvent( | |
1275 entry_list, 4, NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST)); | |
1276 EXPECT_TRUE(LogContainsBeginEvent( | |
1277 entry_list, 5, NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS)); | |
1278 EXPECT_TRUE(LogContainsEvent( | |
1279 entry_list, 6, | |
1280 NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
1281 NetLogEventPhase::NONE)); | |
1282 EXPECT_TRUE(LogContainsEndEvent( | |
1283 entry_list, 7, NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS)); | |
1284 EXPECT_TRUE(LogContainsEvent(entry_list, 8, | |
1285 NetLogEventType::SOCKET_BYTES_RECEIVED, | |
1286 NetLogEventPhase::NONE)); | |
1287 EXPECT_TRUE( | |
1288 LogContainsEndEvent(entry_list, 9, NetLogEventType::SOCKET_ALIVE)); | |
1289 | |
1290 // Let the RST_STREAM write while |rst| is in-scope. | |
1291 base::RunLoop().RunUntilIdle(); | |
1292 } | |
1293 | |
1294 // CompletionCallback that causes the SpdyProxyClientSocket to be | |
1295 // deleted when Run is invoked. | |
1296 class DeleteSockCallback : public TestCompletionCallbackBase { | |
1297 public: | |
1298 explicit DeleteSockCallback(std::unique_ptr<SpdyProxyClientSocket>* sock) | |
1299 : sock_(sock), | |
1300 callback_(base::Bind(&DeleteSockCallback::OnComplete, | |
1301 base::Unretained(this))) {} | |
1302 | |
1303 ~DeleteSockCallback() override {} | |
1304 | |
1305 const CompletionCallback& callback() const { return callback_; } | |
1306 | |
1307 private: | |
1308 void OnComplete(int result) { | |
1309 sock_->reset(NULL); | |
1310 SetResult(result); | |
1311 } | |
1312 | |
1313 std::unique_ptr<SpdyProxyClientSocket>* sock_; | |
1314 CompletionCallback callback_; | |
1315 | |
1316 DISALLOW_COPY_AND_ASSIGN(DeleteSockCallback); | |
1317 }; | |
1318 | |
1319 // If the socket is Reset when both a read and write are pending, and the | |
1320 // read callback causes the socket to be deleted, the write callback should | |
1321 // not be called. | |
1322 TEST_F(SpdyProxyClientSocketTest, RstWithReadAndWritePendingDelete) { | |
1323 SpdySerializedFrame conn(ConstructConnectRequestFrame()); | |
1324 MockWrite writes[] = { | |
1325 CreateMockWrite(conn, 0, SYNCHRONOUS), | |
1326 }; | |
1327 | |
1328 SpdySerializedFrame resp(ConstructConnectReplyFrame()); | |
1329 SpdySerializedFrame rst( | |
1330 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_CANCEL)); | |
1331 MockRead reads[] = { | |
1332 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2), | |
1333 CreateMockRead(rst, 3, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4), | |
1334 }; | |
1335 | |
1336 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
1337 | |
1338 AssertConnectSucceeds(); | |
1339 | |
1340 EXPECT_TRUE(sock_->IsConnected()); | |
1341 | |
1342 DeleteSockCallback read_callback(&sock_); | |
1343 | |
1344 scoped_refptr<IOBuffer> read_buf(new IOBuffer(kLen1)); | |
1345 ASSERT_EQ(ERR_IO_PENDING, | |
1346 sock_->Read(read_buf.get(), kLen1, read_callback.callback())); | |
1347 | |
1348 scoped_refptr<IOBufferWithSize> write_buf(CreateBuffer(kMsg1, kLen1)); | |
1349 EXPECT_EQ( | |
1350 ERR_IO_PENDING, | |
1351 sock_->Write( | |
1352 write_buf.get(), write_buf->size(), write_callback_.callback())); | |
1353 | |
1354 ResumeAndRun(); | |
1355 | |
1356 EXPECT_FALSE(sock_.get()); | |
1357 EXPECT_TRUE(read_callback.have_result()); | |
1358 EXPECT_FALSE(write_callback_.have_result()); | |
1359 | |
1360 // Let the RST_STREAM write while |rst| is in-scope. | |
1361 base::RunLoop().RunUntilIdle(); | |
1362 } | |
1363 | |
1364 } // namespace net | |
OLD | NEW |