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