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/http/http_network_transaction.h" | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/bind_helpers.h" | |
12 #include "net/base/auth.h" | |
13 #include "net/base/net_log_unittest.h" | |
14 #include "net/http/http_network_session_peer.h" | |
15 #include "net/http/http_transaction_unittest.h" | |
16 #include "net/socket/client_socket_pool_base.h" | |
17 #include "net/spdy/spdy_http_stream.h" | |
18 #include "net/spdy/spdy_http_utils.h" | |
19 #include "net/spdy/spdy_session.h" | |
20 #include "net/spdy/spdy_session_pool.h" | |
21 #include "net/spdy/spdy_test_util.h" | |
22 #include "net/url_request/url_request_test_util.h" | |
23 #include "testing/platform_test.h" | |
24 | |
25 //----------------------------------------------------------------------------- | |
26 | |
27 namespace net { | |
28 | |
29 enum SpdyNetworkTransactionTestTypes { | |
30 SPDYNPN, | |
31 SPDYNOSSL, | |
32 SPDYSSL, | |
33 }; | |
34 class SpdyNetworkTransactionTest | |
35 : public ::testing::TestWithParam<SpdyNetworkTransactionTestTypes> { | |
36 protected: | |
37 | |
38 virtual void SetUp() { | |
39 // By default, all tests turn off compression. | |
40 EnableCompression(false); | |
41 google_get_request_initialized_ = false; | |
42 google_post_request_initialized_ = false; | |
43 google_chunked_post_request_initialized_ = false; | |
44 } | |
45 | |
46 virtual void TearDown() { | |
47 // Empty the current queue. | |
48 MessageLoop::current()->RunAllPending(); | |
49 } | |
50 | |
51 struct TransactionHelperResult { | |
52 int rv; | |
53 std::string status_line; | |
54 std::string response_data; | |
55 HttpResponseInfo response_info; | |
56 }; | |
57 | |
58 void EnableCompression(bool enabled) { | |
59 spdy::SpdyFramer::set_enable_compression_default(enabled); | |
60 } | |
61 | |
62 // A helper class that handles all the initial npn/ssl setup. | |
63 class NormalSpdyTransactionHelper { | |
64 public: | |
65 NormalSpdyTransactionHelper(const HttpRequestInfo& request, | |
66 const BoundNetLog& log, | |
67 SpdyNetworkTransactionTestTypes test_type) | |
68 : request_(request), | |
69 session_deps_(new SpdySessionDependencies()), | |
70 session_(SpdySessionDependencies::SpdyCreateSession( | |
71 session_deps_.get())), | |
72 log_(log), | |
73 test_type_(test_type), | |
74 deterministic_(false), | |
75 spdy_enabled_(true) { | |
76 switch (test_type_) { | |
77 case SPDYNOSSL: | |
78 case SPDYSSL: | |
79 port_ = 80; | |
80 break; | |
81 case SPDYNPN: | |
82 port_ = 443; | |
83 break; | |
84 default: | |
85 NOTREACHED(); | |
86 } | |
87 } | |
88 | |
89 ~NormalSpdyTransactionHelper() { | |
90 // Any test which doesn't close the socket by sending it an EOF will | |
91 // have a valid session left open, which leaks the entire session pool. | |
92 // This is just fine - in fact, some of our tests intentionally do this | |
93 // so that we can check consistency of the SpdySessionPool as the test | |
94 // finishes. If we had put an EOF on the socket, the SpdySession would | |
95 // have closed and we wouldn't be able to check the consistency. | |
96 | |
97 // Forcefully close existing sessions here. | |
98 session()->spdy_session_pool()->CloseAllSessions(); | |
99 } | |
100 | |
101 void SetDeterministic() { | |
102 session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic( | |
103 session_deps_.get()); | |
104 deterministic_ = true; | |
105 } | |
106 | |
107 void SetSpdyDisabled() { | |
108 spdy_enabled_ = false; | |
109 } | |
110 | |
111 void RunPreTestSetup() { | |
112 if (!session_deps_.get()) | |
113 session_deps_.reset(new SpdySessionDependencies()); | |
114 if (!session_.get()) | |
115 session_ = SpdySessionDependencies::SpdyCreateSession( | |
116 session_deps_.get()); | |
117 HttpStreamFactory::set_use_alternate_protocols(false); | |
118 HttpStreamFactory::set_force_spdy_over_ssl(false); | |
119 HttpStreamFactory::set_force_spdy_always(false); | |
120 | |
121 std::vector<std::string> next_protos; | |
122 next_protos.push_back("http/1.1"); | |
123 next_protos.push_back("spdy/2"); | |
124 next_protos.push_back("spdy/2.1"); | |
125 | |
126 switch (test_type_) { | |
127 case SPDYNPN: | |
128 session_->http_server_properties()->SetAlternateProtocol( | |
129 HostPortPair("www.google.com", 80), 443, | |
130 NPN_SPDY_21); | |
131 HttpStreamFactory::set_use_alternate_protocols(true); | |
132 HttpStreamFactory::SetNextProtos(next_protos); | |
133 break; | |
134 case SPDYNOSSL: | |
135 HttpStreamFactory::set_force_spdy_over_ssl(false); | |
136 HttpStreamFactory::set_force_spdy_always(true); | |
137 break; | |
138 case SPDYSSL: | |
139 HttpStreamFactory::set_force_spdy_over_ssl(true); | |
140 HttpStreamFactory::set_force_spdy_always(true); | |
141 break; | |
142 default: | |
143 NOTREACHED(); | |
144 } | |
145 | |
146 // We're now ready to use SSL-npn SPDY. | |
147 trans_.reset(new HttpNetworkTransaction(session_)); | |
148 } | |
149 | |
150 // Start the transaction, read some data, finish. | |
151 void RunDefaultTest() { | |
152 output_.rv = trans_->Start(&request_, callback.callback(), log_); | |
153 | |
154 // We expect an IO Pending or some sort of error. | |
155 EXPECT_LT(output_.rv, 0); | |
156 if (output_.rv != ERR_IO_PENDING) | |
157 return; | |
158 | |
159 output_.rv = callback.WaitForResult(); | |
160 if (output_.rv != OK) { | |
161 session_->spdy_session_pool()->CloseCurrentSessions(); | |
162 return; | |
163 } | |
164 | |
165 // Verify responses. | |
166 const HttpResponseInfo* response = trans_->GetResponseInfo(); | |
167 ASSERT_TRUE(response != NULL); | |
168 ASSERT_TRUE(response->headers != NULL); | |
169 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
170 EXPECT_EQ(spdy_enabled_, response->was_fetched_via_spdy); | |
171 if (test_type_ == SPDYNPN && spdy_enabled_) { | |
172 EXPECT_TRUE(response->was_npn_negotiated); | |
173 } else { | |
174 EXPECT_TRUE(!response->was_npn_negotiated); | |
175 } | |
176 // If SPDY is not enabled, a HTTP request should not be diverted | |
177 // over a SSL session. | |
178 if (!spdy_enabled_) { | |
179 EXPECT_EQ(request_.url.SchemeIs("https"), | |
180 response->was_npn_negotiated); | |
181 } | |
182 EXPECT_EQ("192.0.2.33", response->socket_address.host()); | |
183 EXPECT_EQ(0, response->socket_address.port()); | |
184 output_.status_line = response->headers->GetStatusLine(); | |
185 output_.response_info = *response; // Make a copy so we can verify. | |
186 output_.rv = ReadTransaction(trans_.get(), &output_.response_data); | |
187 } | |
188 | |
189 // Most tests will want to call this function. In particular, the MockReads | |
190 // should end with an empty read, and that read needs to be processed to | |
191 // ensure proper deletion of the spdy_session_pool. | |
192 void VerifyDataConsumed() { | |
193 for (DataVector::iterator it = data_vector_.begin(); | |
194 it != data_vector_.end(); ++it) { | |
195 EXPECT_TRUE((*it)->at_read_eof()) << "Read count: " | |
196 << (*it)->read_count() | |
197 << " Read index: " | |
198 << (*it)->read_index(); | |
199 EXPECT_TRUE((*it)->at_write_eof()) << "Write count: " | |
200 << (*it)->write_count() | |
201 << " Write index: " | |
202 << (*it)->write_index(); | |
203 } | |
204 } | |
205 | |
206 // Occasionally a test will expect to error out before certain reads are | |
207 // processed. In that case we want to explicitly ensure that the reads were | |
208 // not processed. | |
209 void VerifyDataNotConsumed() { | |
210 for (DataVector::iterator it = data_vector_.begin(); | |
211 it != data_vector_.end(); ++it) { | |
212 EXPECT_TRUE(!(*it)->at_read_eof()) << "Read count: " | |
213 << (*it)->read_count() | |
214 << " Read index: " | |
215 << (*it)->read_index(); | |
216 EXPECT_TRUE(!(*it)->at_write_eof()) << "Write count: " | |
217 << (*it)->write_count() | |
218 << " Write index: " | |
219 << (*it)->write_index(); | |
220 } | |
221 } | |
222 | |
223 void RunToCompletion(StaticSocketDataProvider* data) { | |
224 RunPreTestSetup(); | |
225 AddData(data); | |
226 RunDefaultTest(); | |
227 VerifyDataConsumed(); | |
228 } | |
229 | |
230 void AddData(StaticSocketDataProvider* data) { | |
231 DCHECK(!deterministic_); | |
232 data_vector_.push_back(data); | |
233 linked_ptr<SSLSocketDataProvider> ssl_( | |
234 new SSLSocketDataProvider(ASYNC, OK)); | |
235 if (test_type_ == SPDYNPN) { | |
236 ssl_->SetNextProto(SSLClientSocket::kProtoSPDY21); | |
237 } | |
238 ssl_vector_.push_back(ssl_); | |
239 if (test_type_ == SPDYNPN || test_type_ == SPDYSSL) | |
240 session_deps_->socket_factory->AddSSLSocketDataProvider(ssl_.get()); | |
241 session_deps_->socket_factory->AddSocketDataProvider(data); | |
242 if (test_type_ == SPDYNPN) { | |
243 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
244 linked_ptr<StaticSocketDataProvider> | |
245 hanging_non_alternate_protocol_socket( | |
246 new StaticSocketDataProvider(NULL, 0, NULL, 0)); | |
247 hanging_non_alternate_protocol_socket->set_connect_data( | |
248 never_finishing_connect); | |
249 session_deps_->socket_factory->AddSocketDataProvider( | |
250 hanging_non_alternate_protocol_socket.get()); | |
251 alternate_vector_.push_back(hanging_non_alternate_protocol_socket); | |
252 } | |
253 } | |
254 | |
255 void AddDeterministicData(DeterministicSocketData* data) { | |
256 DCHECK(deterministic_); | |
257 data_vector_.push_back(data); | |
258 linked_ptr<SSLSocketDataProvider> ssl_( | |
259 new SSLSocketDataProvider(ASYNC, OK)); | |
260 if (test_type_ == SPDYNPN) { | |
261 ssl_->SetNextProto(SSLClientSocket::kProtoSPDY21); | |
262 } | |
263 ssl_vector_.push_back(ssl_); | |
264 if (test_type_ == SPDYNPN || test_type_ == SPDYSSL) { | |
265 session_deps_->deterministic_socket_factory-> | |
266 AddSSLSocketDataProvider(ssl_.get()); | |
267 } | |
268 session_deps_->deterministic_socket_factory->AddSocketDataProvider(data); | |
269 if (test_type_ == SPDYNPN) { | |
270 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
271 scoped_refptr<DeterministicSocketData> | |
272 hanging_non_alternate_protocol_socket( | |
273 new DeterministicSocketData(NULL, 0, NULL, 0)); | |
274 hanging_non_alternate_protocol_socket->set_connect_data( | |
275 never_finishing_connect); | |
276 session_deps_->deterministic_socket_factory->AddSocketDataProvider( | |
277 hanging_non_alternate_protocol_socket); | |
278 alternate_deterministic_vector_.push_back( | |
279 hanging_non_alternate_protocol_socket); | |
280 } | |
281 } | |
282 | |
283 // This can only be called after RunPreTestSetup. It adds a Data Provider, | |
284 // but not a corresponding SSL data provider | |
285 void AddDataNoSSL(StaticSocketDataProvider* data) { | |
286 DCHECK(!deterministic_); | |
287 session_deps_->socket_factory->AddSocketDataProvider(data); | |
288 } | |
289 void AddDataNoSSL(DeterministicSocketData* data) { | |
290 DCHECK(deterministic_); | |
291 session_deps_->deterministic_socket_factory->AddSocketDataProvider(data); | |
292 } | |
293 | |
294 void SetSession(const scoped_refptr<HttpNetworkSession>& session) { | |
295 session_ = session; | |
296 } | |
297 HttpNetworkTransaction* trans() { return trans_.get(); } | |
298 void ResetTrans() { trans_.reset(); } | |
299 TransactionHelperResult& output() { return output_; } | |
300 const HttpRequestInfo& request() const { return request_; } | |
301 const scoped_refptr<HttpNetworkSession>& session() const { | |
302 return session_; | |
303 } | |
304 scoped_ptr<SpdySessionDependencies>& session_deps() { | |
305 return session_deps_; | |
306 } | |
307 int port() const { return port_; } | |
308 SpdyNetworkTransactionTestTypes test_type() const { return test_type_; } | |
309 | |
310 private: | |
311 typedef std::vector<StaticSocketDataProvider*> DataVector; | |
312 typedef std::vector<linked_ptr<SSLSocketDataProvider> > SSLVector; | |
313 typedef std::vector<linked_ptr<StaticSocketDataProvider> > AlternateVector; | |
314 typedef std::vector<scoped_refptr<DeterministicSocketData> > | |
315 AlternateDeterministicVector; | |
316 HttpRequestInfo request_; | |
317 scoped_ptr<SpdySessionDependencies> session_deps_; | |
318 scoped_refptr<HttpNetworkSession> session_; | |
319 TransactionHelperResult output_; | |
320 scoped_ptr<StaticSocketDataProvider> first_transaction_; | |
321 SSLVector ssl_vector_; | |
322 TestCompletionCallback callback; | |
323 scoped_ptr<HttpNetworkTransaction> trans_; | |
324 scoped_ptr<HttpNetworkTransaction> trans_http_; | |
325 DataVector data_vector_; | |
326 AlternateVector alternate_vector_; | |
327 AlternateDeterministicVector alternate_deterministic_vector_; | |
328 const BoundNetLog& log_; | |
329 SpdyNetworkTransactionTestTypes test_type_; | |
330 int port_; | |
331 bool deterministic_; | |
332 bool spdy_enabled_; | |
333 }; | |
334 | |
335 void ConnectStatusHelperWithExpectedStatus(const MockRead& status, | |
336 int expected_status); | |
337 | |
338 void ConnectStatusHelper(const MockRead& status); | |
339 | |
340 const HttpRequestInfo& CreateGetPushRequest() { | |
341 google_get_push_request_.method = "GET"; | |
342 google_get_push_request_.url = GURL("http://www.google.com/foo.dat"); | |
343 google_get_push_request_.load_flags = 0; | |
344 return google_get_push_request_; | |
345 } | |
346 | |
347 const HttpRequestInfo& CreateGetRequest() { | |
348 if (!google_get_request_initialized_) { | |
349 google_get_request_.method = "GET"; | |
350 google_get_request_.url = GURL(kDefaultURL); | |
351 google_get_request_.load_flags = 0; | |
352 google_get_request_initialized_ = true; | |
353 } | |
354 return google_get_request_; | |
355 } | |
356 | |
357 const HttpRequestInfo& CreateGetRequestWithUserAgent() { | |
358 if (!google_get_request_initialized_) { | |
359 google_get_request_.method = "GET"; | |
360 google_get_request_.url = GURL(kDefaultURL); | |
361 google_get_request_.load_flags = 0; | |
362 google_get_request_.extra_headers.SetHeader("User-Agent", "Chrome"); | |
363 google_get_request_initialized_ = true; | |
364 } | |
365 return google_get_request_; | |
366 } | |
367 | |
368 const HttpRequestInfo& CreatePostRequest() { | |
369 if (!google_post_request_initialized_) { | |
370 google_post_request_.method = "POST"; | |
371 google_post_request_.url = GURL(kDefaultURL); | |
372 google_post_request_.upload_data = new UploadData(); | |
373 google_post_request_.upload_data->AppendBytes(kUploadData, | |
374 kUploadDataSize); | |
375 google_post_request_initialized_ = true; | |
376 } | |
377 return google_post_request_; | |
378 } | |
379 | |
380 const HttpRequestInfo& CreateChunkedPostRequest() { | |
381 if (!google_chunked_post_request_initialized_) { | |
382 google_chunked_post_request_.method = "POST"; | |
383 google_chunked_post_request_.url = GURL(kDefaultURL); | |
384 google_chunked_post_request_.upload_data = new UploadData(); | |
385 google_chunked_post_request_.upload_data->set_is_chunked(true); | |
386 google_chunked_post_request_.upload_data->AppendChunk( | |
387 kUploadData, kUploadDataSize, false); | |
388 google_chunked_post_request_.upload_data->AppendChunk( | |
389 kUploadData, kUploadDataSize, true); | |
390 google_chunked_post_request_initialized_ = true; | |
391 } | |
392 return google_chunked_post_request_; | |
393 } | |
394 | |
395 // Read the result of a particular transaction, knowing that we've got | |
396 // multiple transactions in the read pipeline; so as we read, we may have | |
397 // to skip over data destined for other transactions while we consume | |
398 // the data for |trans|. | |
399 int ReadResult(HttpNetworkTransaction* trans, | |
400 StaticSocketDataProvider* data, | |
401 std::string* result) { | |
402 const int kSize = 3000; | |
403 | |
404 int bytes_read = 0; | |
405 scoped_refptr<net::IOBufferWithSize> buf(new net::IOBufferWithSize(kSize)); | |
406 TestCompletionCallback callback; | |
407 while (true) { | |
408 int rv = trans->Read(buf, kSize, callback.callback()); | |
409 if (rv == ERR_IO_PENDING) { | |
410 // Multiple transactions may be in the data set. Keep pulling off | |
411 // reads until we complete our callback. | |
412 while (!callback.have_result()) { | |
413 data->CompleteRead(); | |
414 MessageLoop::current()->RunAllPending(); | |
415 } | |
416 rv = callback.WaitForResult(); | |
417 } else if (rv <= 0) { | |
418 break; | |
419 } | |
420 result->append(buf->data(), rv); | |
421 bytes_read += rv; | |
422 } | |
423 return bytes_read; | |
424 } | |
425 | |
426 void VerifyStreamsClosed(const NormalSpdyTransactionHelper& helper) { | |
427 // This lengthy block is reaching into the pool to dig out the active | |
428 // session. Once we have the session, we verify that the streams are | |
429 // all closed and not leaked at this point. | |
430 const GURL& url = helper.request().url; | |
431 int port = helper.test_type() == SPDYNPN ? 443 : 80; | |
432 HostPortPair host_port_pair(url.host(), port); | |
433 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); | |
434 BoundNetLog log; | |
435 const scoped_refptr<HttpNetworkSession>& session = helper.session(); | |
436 SpdySessionPool* pool(session->spdy_session_pool()); | |
437 EXPECT_TRUE(pool->HasSession(pair)); | |
438 scoped_refptr<SpdySession> spdy_session(pool->Get(pair, log)); | |
439 ASSERT_TRUE(spdy_session.get() != NULL); | |
440 EXPECT_EQ(0u, spdy_session->num_active_streams()); | |
441 EXPECT_EQ(0u, spdy_session->num_unclaimed_pushed_streams()); | |
442 } | |
443 | |
444 void RunServerPushTest(OrderedSocketData* data, | |
445 HttpResponseInfo* response, | |
446 HttpResponseInfo* push_response, | |
447 std::string& expected) { | |
448 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
449 BoundNetLog(), GetParam()); | |
450 helper.RunPreTestSetup(); | |
451 helper.AddData(data); | |
452 | |
453 HttpNetworkTransaction* trans = helper.trans(); | |
454 | |
455 // Start the transaction with basic parameters. | |
456 TestCompletionCallback callback; | |
457 int rv = trans->Start( | |
458 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
459 EXPECT_EQ(ERR_IO_PENDING, rv); | |
460 rv = callback.WaitForResult(); | |
461 | |
462 // Request the pushed path. | |
463 scoped_ptr<HttpNetworkTransaction> trans2( | |
464 new HttpNetworkTransaction(helper.session())); | |
465 rv = trans2->Start( | |
466 &CreateGetPushRequest(), callback.callback(), BoundNetLog()); | |
467 EXPECT_EQ(ERR_IO_PENDING, rv); | |
468 MessageLoop::current()->RunAllPending(); | |
469 | |
470 // The data for the pushed path may be coming in more than 1 packet. Compile | |
471 // the results into a single string. | |
472 | |
473 // Read the server push body. | |
474 std::string result2; | |
475 ReadResult(trans2.get(), data, &result2); | |
476 // Read the response body. | |
477 std::string result; | |
478 ReadResult(trans, data, &result); | |
479 | |
480 // Verify that we consumed all test data. | |
481 EXPECT_TRUE(data->at_read_eof()); | |
482 EXPECT_TRUE(data->at_write_eof()); | |
483 | |
484 // Verify that the received push data is same as the expected push data. | |
485 EXPECT_EQ(result2.compare(expected), 0) << "Received data: " | |
486 << result2 | |
487 << "||||| Expected data: " | |
488 << expected; | |
489 | |
490 // Verify the SYN_REPLY. | |
491 // Copy the response info, because trans goes away. | |
492 *response = *trans->GetResponseInfo(); | |
493 *push_response = *trans2->GetResponseInfo(); | |
494 | |
495 VerifyStreamsClosed(helper); | |
496 } | |
497 | |
498 static void DeleteSessionCallback(NormalSpdyTransactionHelper* helper, | |
499 int result) { | |
500 helper->ResetTrans(); | |
501 } | |
502 | |
503 static void StartTransactionCallback( | |
504 const scoped_refptr<HttpNetworkSession>& session, | |
505 int result) { | |
506 scoped_ptr<HttpNetworkTransaction> trans( | |
507 new HttpNetworkTransaction(session)); | |
508 TestCompletionCallback callback; | |
509 HttpRequestInfo request; | |
510 request.method = "GET"; | |
511 request.url = GURL("http://www.google.com/"); | |
512 request.load_flags = 0; | |
513 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
514 EXPECT_EQ(ERR_IO_PENDING, rv); | |
515 callback.WaitForResult(); | |
516 } | |
517 | |
518 private: | |
519 bool google_get_request_initialized_; | |
520 bool google_post_request_initialized_; | |
521 bool google_chunked_post_request_initialized_; | |
522 HttpRequestInfo google_get_request_; | |
523 HttpRequestInfo google_post_request_; | |
524 HttpRequestInfo google_chunked_post_request_; | |
525 HttpRequestInfo google_get_push_request_; | |
526 }; | |
527 | |
528 //----------------------------------------------------------------------------- | |
529 // All tests are run with three different connection types: SPDY after NPN | |
530 // negotiation, SPDY without SSL, and SPDY with SSL. | |
531 INSTANTIATE_TEST_CASE_P(Spdy, | |
532 SpdyNetworkTransactionTest, | |
533 ::testing::Values(SPDYNOSSL, SPDYSSL, SPDYNPN)); | |
534 | |
535 | |
536 // Verify HttpNetworkTransaction constructor. | |
537 TEST_P(SpdyNetworkTransactionTest, Constructor) { | |
538 SpdySessionDependencies session_deps; | |
539 scoped_refptr<HttpNetworkSession> session( | |
540 SpdySessionDependencies::SpdyCreateSession(&session_deps)); | |
541 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
542 } | |
543 | |
544 TEST_P(SpdyNetworkTransactionTest, Get) { | |
545 // Construct the request. | |
546 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
547 MockWrite writes[] = { CreateMockWrite(*req) }; | |
548 | |
549 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
550 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
551 MockRead reads[] = { | |
552 CreateMockRead(*resp), | |
553 CreateMockRead(*body), | |
554 MockRead(ASYNC, 0, 0) // EOF | |
555 }; | |
556 | |
557 scoped_ptr<DelayedSocketData> data( | |
558 new DelayedSocketData(1, reads, arraysize(reads), | |
559 writes, arraysize(writes))); | |
560 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
561 BoundNetLog(), GetParam()); | |
562 helper.RunToCompletion(data.get()); | |
563 TransactionHelperResult out = helper.output(); | |
564 EXPECT_EQ(OK, out.rv); | |
565 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
566 EXPECT_EQ("hello!", out.response_data); | |
567 } | |
568 | |
569 TEST_P(SpdyNetworkTransactionTest, GetAtEachPriority) { | |
570 for (RequestPriority p = HIGHEST; p < NUM_PRIORITIES; | |
571 p = RequestPriority(p+1)) { | |
572 // Construct the request. | |
573 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, p)); | |
574 MockWrite writes[] = { CreateMockWrite(*req) }; | |
575 | |
576 const int spdy_prio = reinterpret_cast<spdy::SpdySynStreamControlFrame*>( | |
577 req.get())->priority(); | |
578 // this repeats the RequestPriority-->SpdyPriority mapping from | |
579 // SpdyFramer::ConvertRequestPriorityToSpdyPriority to make | |
580 // sure it's being done right. | |
581 switch(p) { | |
582 case HIGHEST: | |
583 EXPECT_EQ(0, spdy_prio); | |
584 break; | |
585 case MEDIUM: | |
586 EXPECT_EQ(1, spdy_prio); | |
587 break; | |
588 case LOW: | |
589 case LOWEST: | |
590 EXPECT_EQ(2, spdy_prio); | |
591 break; | |
592 case IDLE: | |
593 EXPECT_EQ(3, spdy_prio); | |
594 break; | |
595 default: | |
596 FAIL(); | |
597 } | |
598 | |
599 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
600 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
601 MockRead reads[] = { | |
602 CreateMockRead(*resp), | |
603 CreateMockRead(*body), | |
604 MockRead(ASYNC, 0, 0) // EOF | |
605 }; | |
606 | |
607 scoped_ptr<DelayedSocketData> data( | |
608 new DelayedSocketData(1, reads, arraysize(reads), | |
609 writes, arraysize(writes))); | |
610 HttpRequestInfo http_req = CreateGetRequest(); | |
611 http_req.priority = p; | |
612 | |
613 NormalSpdyTransactionHelper helper(http_req, BoundNetLog(), GetParam()); | |
614 helper.RunToCompletion(data.get()); | |
615 TransactionHelperResult out = helper.output(); | |
616 EXPECT_EQ(OK, out.rv); | |
617 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
618 EXPECT_EQ("hello!", out.response_data); | |
619 } | |
620 } | |
621 | |
622 // Start three gets simultaniously; making sure that multiplexed | |
623 // streams work properly. | |
624 | |
625 // This can't use the TransactionHelper method, since it only | |
626 // handles a single transaction, and finishes them as soon | |
627 // as it launches them. | |
628 | |
629 // TODO(gavinp): create a working generalized TransactionHelper that | |
630 // can allow multiple streams in flight. | |
631 | |
632 TEST_P(SpdyNetworkTransactionTest, ThreeGets) { | |
633 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
634 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
635 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, false)); | |
636 scoped_ptr<spdy::SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true)); | |
637 | |
638 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); | |
639 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
640 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(3, false)); | |
641 scoped_ptr<spdy::SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true)); | |
642 | |
643 scoped_ptr<spdy::SpdyFrame> req3(ConstructSpdyGet(NULL, 0, false, 5, LOWEST)); | |
644 scoped_ptr<spdy::SpdyFrame> resp3(ConstructSpdyGetSynReply(NULL, 0, 5)); | |
645 scoped_ptr<spdy::SpdyFrame> body3(ConstructSpdyBodyFrame(5, false)); | |
646 scoped_ptr<spdy::SpdyFrame> fbody3(ConstructSpdyBodyFrame(5, true)); | |
647 | |
648 MockWrite writes[] = { | |
649 CreateMockWrite(*req), | |
650 CreateMockWrite(*req2), | |
651 CreateMockWrite(*req3), | |
652 }; | |
653 MockRead reads[] = { | |
654 CreateMockRead(*resp, 1), | |
655 CreateMockRead(*body), | |
656 CreateMockRead(*resp2, 4), | |
657 CreateMockRead(*body2), | |
658 CreateMockRead(*resp3, 7), | |
659 CreateMockRead(*body3), | |
660 | |
661 CreateMockRead(*fbody), | |
662 CreateMockRead(*fbody2), | |
663 CreateMockRead(*fbody3), | |
664 | |
665 MockRead(ASYNC, 0, 0), // EOF | |
666 }; | |
667 scoped_ptr<OrderedSocketData> data( | |
668 new OrderedSocketData(reads, arraysize(reads), | |
669 writes, arraysize(writes))); | |
670 scoped_ptr<OrderedSocketData> data_placeholder( | |
671 new OrderedSocketData(NULL, 0, NULL, 0)); | |
672 | |
673 BoundNetLog log; | |
674 TransactionHelperResult out; | |
675 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
676 BoundNetLog(), GetParam()); | |
677 helper.RunPreTestSetup(); | |
678 helper.AddData(data.get()); | |
679 // We require placeholder data because three get requests are sent out, so | |
680 // there needs to be three sets of SSL connection data. | |
681 helper.AddData(data_placeholder.get()); | |
682 helper.AddData(data_placeholder.get()); | |
683 scoped_ptr<HttpNetworkTransaction> trans1( | |
684 new HttpNetworkTransaction(helper.session())); | |
685 scoped_ptr<HttpNetworkTransaction> trans2( | |
686 new HttpNetworkTransaction(helper.session())); | |
687 scoped_ptr<HttpNetworkTransaction> trans3( | |
688 new HttpNetworkTransaction(helper.session())); | |
689 | |
690 TestCompletionCallback callback1; | |
691 TestCompletionCallback callback2; | |
692 TestCompletionCallback callback3; | |
693 | |
694 HttpRequestInfo httpreq1 = CreateGetRequest(); | |
695 HttpRequestInfo httpreq2 = CreateGetRequest(); | |
696 HttpRequestInfo httpreq3 = CreateGetRequest(); | |
697 | |
698 out.rv = trans1->Start(&httpreq1, callback1.callback(), log); | |
699 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
700 out.rv = trans2->Start(&httpreq2, callback2.callback(), log); | |
701 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
702 out.rv = trans3->Start(&httpreq3, callback3.callback(), log); | |
703 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
704 | |
705 out.rv = callback1.WaitForResult(); | |
706 ASSERT_EQ(OK, out.rv); | |
707 out.rv = callback3.WaitForResult(); | |
708 ASSERT_EQ(OK, out.rv); | |
709 | |
710 const HttpResponseInfo* response1 = trans1->GetResponseInfo(); | |
711 EXPECT_TRUE(response1->headers != NULL); | |
712 EXPECT_TRUE(response1->was_fetched_via_spdy); | |
713 out.status_line = response1->headers->GetStatusLine(); | |
714 out.response_info = *response1; | |
715 | |
716 trans2->GetResponseInfo(); | |
717 | |
718 out.rv = ReadTransaction(trans1.get(), &out.response_data); | |
719 helper.VerifyDataConsumed(); | |
720 EXPECT_EQ(OK, out.rv); | |
721 | |
722 EXPECT_EQ(OK, out.rv); | |
723 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
724 EXPECT_EQ("hello!hello!", out.response_data); | |
725 } | |
726 | |
727 TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBinding) { | |
728 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
729 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
730 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, false)); | |
731 scoped_ptr<spdy::SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true)); | |
732 | |
733 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); | |
734 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
735 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(3, false)); | |
736 scoped_ptr<spdy::SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true)); | |
737 | |
738 MockWrite writes[] = { | |
739 CreateMockWrite(*req), | |
740 CreateMockWrite(*req2), | |
741 }; | |
742 MockRead reads[] = { | |
743 CreateMockRead(*resp, 1), | |
744 CreateMockRead(*body), | |
745 CreateMockRead(*resp2, 4), | |
746 CreateMockRead(*body2), | |
747 CreateMockRead(*fbody), | |
748 CreateMockRead(*fbody2), | |
749 MockRead(ASYNC, 0, 0), // EOF | |
750 }; | |
751 scoped_ptr<OrderedSocketData> data( | |
752 new OrderedSocketData(reads, arraysize(reads), | |
753 writes, arraysize(writes))); | |
754 | |
755 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
756 | |
757 scoped_ptr<OrderedSocketData> data_placeholder( | |
758 new OrderedSocketData(NULL, 0, NULL, 0)); | |
759 data_placeholder->set_connect_data(never_finishing_connect); | |
760 | |
761 BoundNetLog log; | |
762 TransactionHelperResult out; | |
763 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
764 BoundNetLog(), GetParam()); | |
765 helper.RunPreTestSetup(); | |
766 helper.AddData(data.get()); | |
767 // We require placeholder data because two get requests are sent out, so | |
768 // there needs to be two sets of SSL connection data. | |
769 helper.AddData(data_placeholder.get()); | |
770 scoped_ptr<HttpNetworkTransaction> trans1( | |
771 new HttpNetworkTransaction(helper.session())); | |
772 scoped_ptr<HttpNetworkTransaction> trans2( | |
773 new HttpNetworkTransaction(helper.session())); | |
774 | |
775 TestCompletionCallback callback1; | |
776 TestCompletionCallback callback2; | |
777 | |
778 HttpRequestInfo httpreq1 = CreateGetRequest(); | |
779 HttpRequestInfo httpreq2 = CreateGetRequest(); | |
780 | |
781 out.rv = trans1->Start(&httpreq1, callback1.callback(), log); | |
782 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
783 out.rv = trans2->Start(&httpreq2, callback2.callback(), log); | |
784 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
785 | |
786 out.rv = callback1.WaitForResult(); | |
787 ASSERT_EQ(OK, out.rv); | |
788 out.rv = callback2.WaitForResult(); | |
789 ASSERT_EQ(OK, out.rv); | |
790 | |
791 const HttpResponseInfo* response1 = trans1->GetResponseInfo(); | |
792 EXPECT_TRUE(response1->headers != NULL); | |
793 EXPECT_TRUE(response1->was_fetched_via_spdy); | |
794 out.status_line = response1->headers->GetStatusLine(); | |
795 out.response_info = *response1; | |
796 out.rv = ReadTransaction(trans1.get(), &out.response_data); | |
797 EXPECT_EQ(OK, out.rv); | |
798 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
799 EXPECT_EQ("hello!hello!", out.response_data); | |
800 | |
801 const HttpResponseInfo* response2 = trans2->GetResponseInfo(); | |
802 EXPECT_TRUE(response2->headers != NULL); | |
803 EXPECT_TRUE(response2->was_fetched_via_spdy); | |
804 out.status_line = response2->headers->GetStatusLine(); | |
805 out.response_info = *response2; | |
806 out.rv = ReadTransaction(trans2.get(), &out.response_data); | |
807 EXPECT_EQ(OK, out.rv); | |
808 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
809 EXPECT_EQ("hello!hello!", out.response_data); | |
810 | |
811 helper.VerifyDataConsumed(); | |
812 } | |
813 | |
814 TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) { | |
815 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
816 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
817 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, false)); | |
818 scoped_ptr<spdy::SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true)); | |
819 | |
820 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); | |
821 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
822 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(3, false)); | |
823 scoped_ptr<spdy::SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true)); | |
824 | |
825 MockWrite writes[] = { | |
826 CreateMockWrite(*req), | |
827 CreateMockWrite(*req2), | |
828 }; | |
829 MockRead reads[] = { | |
830 CreateMockRead(*resp, 1), | |
831 CreateMockRead(*body), | |
832 CreateMockRead(*resp2, 4), | |
833 CreateMockRead(*body2), | |
834 CreateMockRead(*fbody), | |
835 CreateMockRead(*fbody2), | |
836 MockRead(ASYNC, 0, 0), // EOF | |
837 }; | |
838 scoped_ptr<OrderedSocketData> preconnect_data( | |
839 new OrderedSocketData(reads, arraysize(reads), | |
840 writes, arraysize(writes))); | |
841 | |
842 MockConnect never_finishing_connect(ASYNC, ERR_IO_PENDING); | |
843 | |
844 scoped_ptr<OrderedSocketData> data_placeholder( | |
845 new OrderedSocketData(NULL, 0, NULL, 0)); | |
846 data_placeholder->set_connect_data(never_finishing_connect); | |
847 | |
848 BoundNetLog log; | |
849 TransactionHelperResult out; | |
850 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
851 BoundNetLog(), GetParam()); | |
852 helper.RunPreTestSetup(); | |
853 helper.AddData(preconnect_data.get()); | |
854 // We require placeholder data because 3 connections are attempted (first is | |
855 // the preconnect, 2nd and 3rd are the never finished connections. | |
856 helper.AddData(data_placeholder.get()); | |
857 helper.AddData(data_placeholder.get()); | |
858 | |
859 scoped_ptr<HttpNetworkTransaction> trans1( | |
860 new HttpNetworkTransaction(helper.session())); | |
861 scoped_ptr<HttpNetworkTransaction> trans2( | |
862 new HttpNetworkTransaction(helper.session())); | |
863 | |
864 TestCompletionCallback callback1; | |
865 TestCompletionCallback callback2; | |
866 | |
867 HttpRequestInfo httpreq = CreateGetRequest(); | |
868 | |
869 // Preconnect the first. | |
870 SSLConfig preconnect_ssl_config; | |
871 helper.session()->ssl_config_service()->GetSSLConfig(&preconnect_ssl_config); | |
872 HttpStreamFactory* http_stream_factory = | |
873 helper.session()->http_stream_factory(); | |
874 if (http_stream_factory->has_next_protos()) { | |
875 preconnect_ssl_config.next_protos = http_stream_factory->next_protos(); | |
876 } | |
877 | |
878 http_stream_factory->PreconnectStreams( | |
879 1, httpreq, preconnect_ssl_config, preconnect_ssl_config); | |
880 | |
881 out.rv = trans1->Start(&httpreq, callback1.callback(), log); | |
882 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
883 out.rv = trans2->Start(&httpreq, callback2.callback(), log); | |
884 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
885 | |
886 out.rv = callback1.WaitForResult(); | |
887 ASSERT_EQ(OK, out.rv); | |
888 out.rv = callback2.WaitForResult(); | |
889 ASSERT_EQ(OK, out.rv); | |
890 | |
891 const HttpResponseInfo* response1 = trans1->GetResponseInfo(); | |
892 EXPECT_TRUE(response1->headers != NULL); | |
893 EXPECT_TRUE(response1->was_fetched_via_spdy); | |
894 out.status_line = response1->headers->GetStatusLine(); | |
895 out.response_info = *response1; | |
896 out.rv = ReadTransaction(trans1.get(), &out.response_data); | |
897 EXPECT_EQ(OK, out.rv); | |
898 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
899 EXPECT_EQ("hello!hello!", out.response_data); | |
900 | |
901 const HttpResponseInfo* response2 = trans2->GetResponseInfo(); | |
902 EXPECT_TRUE(response2->headers != NULL); | |
903 EXPECT_TRUE(response2->was_fetched_via_spdy); | |
904 out.status_line = response2->headers->GetStatusLine(); | |
905 out.response_info = *response2; | |
906 out.rv = ReadTransaction(trans2.get(), &out.response_data); | |
907 EXPECT_EQ(OK, out.rv); | |
908 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
909 EXPECT_EQ("hello!hello!", out.response_data); | |
910 | |
911 helper.VerifyDataConsumed(); | |
912 } | |
913 | |
914 // Similar to ThreeGets above, however this test adds a SETTINGS | |
915 // frame. The SETTINGS frame is read during the IO loop waiting on | |
916 // the first transaction completion, and sets a maximum concurrent | |
917 // stream limit of 1. This means that our IO loop exists after the | |
918 // second transaction completes, so we can assert on read_index(). | |
919 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) { | |
920 // Construct the request. | |
921 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
922 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
923 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, false)); | |
924 scoped_ptr<spdy::SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true)); | |
925 | |
926 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); | |
927 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
928 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(3, false)); | |
929 scoped_ptr<spdy::SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true)); | |
930 | |
931 scoped_ptr<spdy::SpdyFrame> req3(ConstructSpdyGet(NULL, 0, false, 5, LOWEST)); | |
932 scoped_ptr<spdy::SpdyFrame> resp3(ConstructSpdyGetSynReply(NULL, 0, 5)); | |
933 scoped_ptr<spdy::SpdyFrame> body3(ConstructSpdyBodyFrame(5, false)); | |
934 scoped_ptr<spdy::SpdyFrame> fbody3(ConstructSpdyBodyFrame(5, true)); | |
935 | |
936 spdy::SpdySettings settings; | |
937 spdy::SettingsFlagsAndId id(0); | |
938 id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS); | |
939 const size_t max_concurrent_streams = 1; | |
940 | |
941 settings.push_back(spdy::SpdySetting(id, max_concurrent_streams)); | |
942 scoped_ptr<spdy::SpdyFrame> settings_frame(ConstructSpdySettings(settings)); | |
943 | |
944 MockWrite writes[] = { | |
945 CreateMockWrite(*req), | |
946 CreateMockWrite(*req2), | |
947 CreateMockWrite(*req3), | |
948 }; | |
949 | |
950 MockRead reads[] = { | |
951 CreateMockRead(*settings_frame, 1), | |
952 CreateMockRead(*resp), | |
953 CreateMockRead(*body), | |
954 CreateMockRead(*fbody), | |
955 CreateMockRead(*resp2, 7), | |
956 CreateMockRead(*body2), | |
957 CreateMockRead(*fbody2), | |
958 CreateMockRead(*resp3, 12), | |
959 CreateMockRead(*body3), | |
960 CreateMockRead(*fbody3), | |
961 | |
962 MockRead(ASYNC, 0, 0), // EOF | |
963 }; | |
964 | |
965 scoped_ptr<OrderedSocketData> data( | |
966 new OrderedSocketData(reads, arraysize(reads), | |
967 writes, arraysize(writes))); | |
968 scoped_ptr<OrderedSocketData> data_placeholder( | |
969 new OrderedSocketData(NULL, 0, NULL, 0)); | |
970 | |
971 BoundNetLog log; | |
972 TransactionHelperResult out; | |
973 { | |
974 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
975 BoundNetLog(), GetParam()); | |
976 helper.RunPreTestSetup(); | |
977 helper.AddData(data.get()); | |
978 // We require placeholder data because three get requests are sent out, so | |
979 // there needs to be three sets of SSL connection data. | |
980 helper.AddData(data_placeholder.get()); | |
981 helper.AddData(data_placeholder.get()); | |
982 scoped_ptr<HttpNetworkTransaction> trans1( | |
983 new HttpNetworkTransaction(helper.session())); | |
984 scoped_ptr<HttpNetworkTransaction> trans2( | |
985 new HttpNetworkTransaction(helper.session())); | |
986 scoped_ptr<HttpNetworkTransaction> trans3( | |
987 new HttpNetworkTransaction(helper.session())); | |
988 | |
989 TestCompletionCallback callback1; | |
990 TestCompletionCallback callback2; | |
991 TestCompletionCallback callback3; | |
992 | |
993 HttpRequestInfo httpreq1 = CreateGetRequest(); | |
994 HttpRequestInfo httpreq2 = CreateGetRequest(); | |
995 HttpRequestInfo httpreq3 = CreateGetRequest(); | |
996 | |
997 out.rv = trans1->Start(&httpreq1, callback1.callback(), log); | |
998 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
999 // run transaction 1 through quickly to force a read of our SETTINGS | |
1000 // frame | |
1001 out.rv = callback1.WaitForResult(); | |
1002 ASSERT_EQ(OK, out.rv); | |
1003 | |
1004 out.rv = trans2->Start(&httpreq2, callback2.callback(), log); | |
1005 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1006 out.rv = trans3->Start(&httpreq3, callback3.callback(), log); | |
1007 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1008 out.rv = callback2.WaitForResult(); | |
1009 ASSERT_EQ(OK, out.rv); | |
1010 EXPECT_EQ(7U, data->read_index()); // i.e. the third trans was queued | |
1011 | |
1012 out.rv = callback3.WaitForResult(); | |
1013 ASSERT_EQ(OK, out.rv); | |
1014 | |
1015 const HttpResponseInfo* response1 = trans1->GetResponseInfo(); | |
1016 ASSERT_TRUE(response1 != NULL); | |
1017 EXPECT_TRUE(response1->headers != NULL); | |
1018 EXPECT_TRUE(response1->was_fetched_via_spdy); | |
1019 out.status_line = response1->headers->GetStatusLine(); | |
1020 out.response_info = *response1; | |
1021 out.rv = ReadTransaction(trans1.get(), &out.response_data); | |
1022 EXPECT_EQ(OK, out.rv); | |
1023 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1024 EXPECT_EQ("hello!hello!", out.response_data); | |
1025 | |
1026 const HttpResponseInfo* response2 = trans2->GetResponseInfo(); | |
1027 out.status_line = response2->headers->GetStatusLine(); | |
1028 out.response_info = *response2; | |
1029 out.rv = ReadTransaction(trans2.get(), &out.response_data); | |
1030 EXPECT_EQ(OK, out.rv); | |
1031 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1032 EXPECT_EQ("hello!hello!", out.response_data); | |
1033 | |
1034 const HttpResponseInfo* response3 = trans3->GetResponseInfo(); | |
1035 out.status_line = response3->headers->GetStatusLine(); | |
1036 out.response_info = *response3; | |
1037 out.rv = ReadTransaction(trans3.get(), &out.response_data); | |
1038 EXPECT_EQ(OK, out.rv); | |
1039 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1040 EXPECT_EQ("hello!hello!", out.response_data); | |
1041 | |
1042 helper.VerifyDataConsumed(); | |
1043 } | |
1044 EXPECT_EQ(OK, out.rv); | |
1045 } | |
1046 | |
1047 // Similar to ThreeGetsWithMaxConcurrent above, however this test adds | |
1048 // a fourth transaction. The third and fourth transactions have | |
1049 // different data ("hello!" vs "hello!hello!") and because of the | |
1050 // user specified priority, we expect to see them inverted in | |
1051 // the response from the server. | |
1052 TEST_P(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) { | |
1053 // Construct the request. | |
1054 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
1055 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
1056 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, false)); | |
1057 scoped_ptr<spdy::SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true)); | |
1058 | |
1059 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); | |
1060 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
1061 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(3, false)); | |
1062 scoped_ptr<spdy::SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true)); | |
1063 | |
1064 scoped_ptr<spdy::SpdyFrame> req4( | |
1065 ConstructSpdyGet(NULL, 0, false, 5, HIGHEST)); | |
1066 scoped_ptr<spdy::SpdyFrame> resp4(ConstructSpdyGetSynReply(NULL, 0, 5)); | |
1067 scoped_ptr<spdy::SpdyFrame> fbody4(ConstructSpdyBodyFrame(5, true)); | |
1068 | |
1069 scoped_ptr<spdy::SpdyFrame> req3(ConstructSpdyGet(NULL, 0, false, 7, LOWEST)); | |
1070 scoped_ptr<spdy::SpdyFrame> resp3(ConstructSpdyGetSynReply(NULL, 0, 7)); | |
1071 scoped_ptr<spdy::SpdyFrame> body3(ConstructSpdyBodyFrame(7, false)); | |
1072 scoped_ptr<spdy::SpdyFrame> fbody3(ConstructSpdyBodyFrame(7, true)); | |
1073 | |
1074 | |
1075 spdy::SpdySettings settings; | |
1076 spdy::SettingsFlagsAndId id(0); | |
1077 id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS); | |
1078 const size_t max_concurrent_streams = 1; | |
1079 | |
1080 settings.push_back(spdy::SpdySetting(id, max_concurrent_streams)); | |
1081 scoped_ptr<spdy::SpdyFrame> settings_frame(ConstructSpdySettings(settings)); | |
1082 | |
1083 MockWrite writes[] = { CreateMockWrite(*req), | |
1084 CreateMockWrite(*req2), | |
1085 CreateMockWrite(*req4), | |
1086 CreateMockWrite(*req3), | |
1087 }; | |
1088 MockRead reads[] = { | |
1089 CreateMockRead(*settings_frame, 1), | |
1090 CreateMockRead(*resp), | |
1091 CreateMockRead(*body), | |
1092 CreateMockRead(*fbody), | |
1093 CreateMockRead(*resp2, 7), | |
1094 CreateMockRead(*body2), | |
1095 CreateMockRead(*fbody2), | |
1096 CreateMockRead(*resp4, 13), | |
1097 CreateMockRead(*fbody4), | |
1098 CreateMockRead(*resp3, 16), | |
1099 CreateMockRead(*body3), | |
1100 CreateMockRead(*fbody3), | |
1101 | |
1102 MockRead(ASYNC, 0, 0), // EOF | |
1103 }; | |
1104 | |
1105 scoped_ptr<OrderedSocketData> data( | |
1106 new OrderedSocketData(reads, arraysize(reads), | |
1107 writes, arraysize(writes))); | |
1108 scoped_ptr<OrderedSocketData> data_placeholder( | |
1109 new OrderedSocketData(NULL, 0, NULL, 0)); | |
1110 | |
1111 BoundNetLog log; | |
1112 TransactionHelperResult out; | |
1113 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
1114 BoundNetLog(), GetParam()); | |
1115 helper.RunPreTestSetup(); | |
1116 helper.AddData(data.get()); | |
1117 // We require placeholder data because four get requests are sent out, so | |
1118 // there needs to be four sets of SSL connection data. | |
1119 helper.AddData(data_placeholder.get()); | |
1120 helper.AddData(data_placeholder.get()); | |
1121 helper.AddData(data_placeholder.get()); | |
1122 scoped_ptr<HttpNetworkTransaction> trans1( | |
1123 new HttpNetworkTransaction(helper.session())); | |
1124 scoped_ptr<HttpNetworkTransaction> trans2( | |
1125 new HttpNetworkTransaction(helper.session())); | |
1126 scoped_ptr<HttpNetworkTransaction> trans3( | |
1127 new HttpNetworkTransaction(helper.session())); | |
1128 scoped_ptr<HttpNetworkTransaction> trans4( | |
1129 new HttpNetworkTransaction(helper.session())); | |
1130 | |
1131 TestCompletionCallback callback1; | |
1132 TestCompletionCallback callback2; | |
1133 TestCompletionCallback callback3; | |
1134 TestCompletionCallback callback4; | |
1135 | |
1136 HttpRequestInfo httpreq1 = CreateGetRequest(); | |
1137 HttpRequestInfo httpreq2 = CreateGetRequest(); | |
1138 HttpRequestInfo httpreq3 = CreateGetRequest(); | |
1139 HttpRequestInfo httpreq4 = CreateGetRequest(); | |
1140 httpreq4.priority = HIGHEST; | |
1141 | |
1142 out.rv = trans1->Start(&httpreq1, callback1.callback(), log); | |
1143 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
1144 // run transaction 1 through quickly to force a read of our SETTINGS | |
1145 // frame | |
1146 out.rv = callback1.WaitForResult(); | |
1147 ASSERT_EQ(OK, out.rv); | |
1148 | |
1149 out.rv = trans2->Start(&httpreq2, callback2.callback(), log); | |
1150 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
1151 out.rv = trans3->Start(&httpreq3, callback3.callback(), log); | |
1152 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
1153 out.rv = trans4->Start(&httpreq4, callback4.callback(), log); | |
1154 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
1155 | |
1156 out.rv = callback2.WaitForResult(); | |
1157 ASSERT_EQ(OK, out.rv); | |
1158 EXPECT_EQ(data->read_index(), 7U); // i.e. the third & fourth trans queued | |
1159 | |
1160 out.rv = callback3.WaitForResult(); | |
1161 ASSERT_EQ(OK, out.rv); | |
1162 | |
1163 const HttpResponseInfo* response1 = trans1->GetResponseInfo(); | |
1164 EXPECT_TRUE(response1->headers != NULL); | |
1165 EXPECT_TRUE(response1->was_fetched_via_spdy); | |
1166 out.status_line = response1->headers->GetStatusLine(); | |
1167 out.response_info = *response1; | |
1168 out.rv = ReadTransaction(trans1.get(), &out.response_data); | |
1169 EXPECT_EQ(OK, out.rv); | |
1170 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1171 EXPECT_EQ("hello!hello!", out.response_data); | |
1172 | |
1173 const HttpResponseInfo* response2 = trans2->GetResponseInfo(); | |
1174 out.status_line = response2->headers->GetStatusLine(); | |
1175 out.response_info = *response2; | |
1176 out.rv = ReadTransaction(trans2.get(), &out.response_data); | |
1177 EXPECT_EQ(OK, out.rv); | |
1178 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1179 EXPECT_EQ("hello!hello!", out.response_data); | |
1180 | |
1181 // notice: response3 gets two hellos, response4 gets one | |
1182 // hello, so we know dequeuing priority was respected. | |
1183 const HttpResponseInfo* response3 = trans3->GetResponseInfo(); | |
1184 out.status_line = response3->headers->GetStatusLine(); | |
1185 out.response_info = *response3; | |
1186 out.rv = ReadTransaction(trans3.get(), &out.response_data); | |
1187 EXPECT_EQ(OK, out.rv); | |
1188 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1189 EXPECT_EQ("hello!hello!", out.response_data); | |
1190 | |
1191 out.rv = callback4.WaitForResult(); | |
1192 EXPECT_EQ(OK, out.rv); | |
1193 const HttpResponseInfo* response4 = trans4->GetResponseInfo(); | |
1194 out.status_line = response4->headers->GetStatusLine(); | |
1195 out.response_info = *response4; | |
1196 out.rv = ReadTransaction(trans4.get(), &out.response_data); | |
1197 EXPECT_EQ(OK, out.rv); | |
1198 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1199 EXPECT_EQ("hello!", out.response_data); | |
1200 helper.VerifyDataConsumed(); | |
1201 EXPECT_EQ(OK, out.rv); | |
1202 } | |
1203 | |
1204 // Similar to ThreeGetsMaxConcurrrent above, however, this test | |
1205 // deletes a session in the middle of the transaction to insure | |
1206 // that we properly remove pendingcreatestream objects from | |
1207 // the spdy_session | |
1208 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) { | |
1209 // Construct the request. | |
1210 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
1211 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
1212 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, false)); | |
1213 scoped_ptr<spdy::SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true)); | |
1214 | |
1215 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); | |
1216 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
1217 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(3, false)); | |
1218 scoped_ptr<spdy::SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true)); | |
1219 | |
1220 spdy::SpdySettings settings; | |
1221 spdy::SettingsFlagsAndId id(0); | |
1222 id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS); | |
1223 const size_t max_concurrent_streams = 1; | |
1224 | |
1225 settings.push_back(spdy::SpdySetting(id, max_concurrent_streams)); | |
1226 scoped_ptr<spdy::SpdyFrame> settings_frame(ConstructSpdySettings(settings)); | |
1227 | |
1228 MockWrite writes[] = { CreateMockWrite(*req), | |
1229 CreateMockWrite(*req2), | |
1230 }; | |
1231 MockRead reads[] = { | |
1232 CreateMockRead(*settings_frame, 1), | |
1233 CreateMockRead(*resp), | |
1234 CreateMockRead(*body), | |
1235 CreateMockRead(*fbody), | |
1236 CreateMockRead(*resp2, 7), | |
1237 CreateMockRead(*body2), | |
1238 CreateMockRead(*fbody2), | |
1239 MockRead(ASYNC, 0, 0), // EOF | |
1240 }; | |
1241 | |
1242 scoped_ptr<OrderedSocketData> data( | |
1243 new OrderedSocketData(reads, arraysize(reads), | |
1244 writes, arraysize(writes))); | |
1245 scoped_ptr<OrderedSocketData> data_placeholder( | |
1246 new OrderedSocketData(NULL, 0, NULL, 0)); | |
1247 | |
1248 BoundNetLog log; | |
1249 TransactionHelperResult out; | |
1250 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
1251 BoundNetLog(), GetParam()); | |
1252 helper.RunPreTestSetup(); | |
1253 helper.AddData(data.get()); | |
1254 // We require placeholder data because three get requests are sent out, so | |
1255 // there needs to be three sets of SSL connection data. | |
1256 helper.AddData(data_placeholder.get()); | |
1257 helper.AddData(data_placeholder.get()); | |
1258 scoped_ptr<HttpNetworkTransaction> trans1( | |
1259 new HttpNetworkTransaction(helper.session())); | |
1260 scoped_ptr<HttpNetworkTransaction> trans2( | |
1261 new HttpNetworkTransaction(helper.session())); | |
1262 scoped_ptr<HttpNetworkTransaction> trans3( | |
1263 new HttpNetworkTransaction(helper.session())); | |
1264 | |
1265 TestCompletionCallback callback1; | |
1266 TestCompletionCallback callback2; | |
1267 TestCompletionCallback callback3; | |
1268 | |
1269 HttpRequestInfo httpreq1 = CreateGetRequest(); | |
1270 HttpRequestInfo httpreq2 = CreateGetRequest(); | |
1271 HttpRequestInfo httpreq3 = CreateGetRequest(); | |
1272 | |
1273 out.rv = trans1->Start(&httpreq1, callback1.callback(), log); | |
1274 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1275 // run transaction 1 through quickly to force a read of our SETTINGS | |
1276 // frame | |
1277 out.rv = callback1.WaitForResult(); | |
1278 ASSERT_EQ(OK, out.rv); | |
1279 | |
1280 out.rv = trans2->Start(&httpreq2, callback2.callback(), log); | |
1281 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1282 out.rv = trans3->Start(&httpreq3, callback3.callback(), log); | |
1283 delete trans3.release(); | |
1284 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1285 out.rv = callback2.WaitForResult(); | |
1286 ASSERT_EQ(OK, out.rv); | |
1287 | |
1288 EXPECT_EQ(8U, data->read_index()); | |
1289 | |
1290 const HttpResponseInfo* response1 = trans1->GetResponseInfo(); | |
1291 ASSERT_TRUE(response1 != NULL); | |
1292 EXPECT_TRUE(response1->headers != NULL); | |
1293 EXPECT_TRUE(response1->was_fetched_via_spdy); | |
1294 out.status_line = response1->headers->GetStatusLine(); | |
1295 out.response_info = *response1; | |
1296 out.rv = ReadTransaction(trans1.get(), &out.response_data); | |
1297 EXPECT_EQ(OK, out.rv); | |
1298 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1299 EXPECT_EQ("hello!hello!", out.response_data); | |
1300 | |
1301 const HttpResponseInfo* response2 = trans2->GetResponseInfo(); | |
1302 ASSERT_TRUE(response2 != NULL); | |
1303 out.status_line = response2->headers->GetStatusLine(); | |
1304 out.response_info = *response2; | |
1305 out.rv = ReadTransaction(trans2.get(), &out.response_data); | |
1306 EXPECT_EQ(OK, out.rv); | |
1307 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1308 EXPECT_EQ("hello!hello!", out.response_data); | |
1309 helper.VerifyDataConsumed(); | |
1310 EXPECT_EQ(OK, out.rv); | |
1311 } | |
1312 | |
1313 // The KillerCallback will delete the transaction on error as part of the | |
1314 // callback. | |
1315 class KillerCallback : public TestCompletionCallbackBase { | |
1316 public: | |
1317 explicit KillerCallback(HttpNetworkTransaction* transaction) | |
1318 : transaction_(transaction), | |
1319 ALLOW_THIS_IN_INITIALIZER_LIST(callback_( | |
1320 base::Bind(&KillerCallback::OnComplete, base::Unretained(this)))) { | |
1321 } | |
1322 | |
1323 virtual ~KillerCallback() {} | |
1324 | |
1325 const CompletionCallback& callback() const { return callback_; } | |
1326 | |
1327 private: | |
1328 void OnComplete(int result) { | |
1329 if (result < 0) | |
1330 delete transaction_; | |
1331 | |
1332 SetResult(result); | |
1333 } | |
1334 | |
1335 HttpNetworkTransaction* transaction_; | |
1336 CompletionCallback callback_; | |
1337 }; | |
1338 | |
1339 // Similar to ThreeGetsMaxConcurrrentDelete above, however, this test | |
1340 // closes the socket while we have a pending transaction waiting for | |
1341 // a pending stream creation. http://crbug.com/52901 | |
1342 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) { | |
1343 // Construct the request. | |
1344 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
1345 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
1346 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, false)); | |
1347 scoped_ptr<spdy::SpdyFrame> fin_body(ConstructSpdyBodyFrame(1, true)); | |
1348 | |
1349 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); | |
1350 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
1351 | |
1352 spdy::SpdySettings settings; | |
1353 spdy::SettingsFlagsAndId id(0); | |
1354 id.set_id(spdy::SETTINGS_MAX_CONCURRENT_STREAMS); | |
1355 const size_t max_concurrent_streams = 1; | |
1356 | |
1357 settings.push_back(spdy::SpdySetting(id, max_concurrent_streams)); | |
1358 scoped_ptr<spdy::SpdyFrame> settings_frame(ConstructSpdySettings(settings)); | |
1359 | |
1360 MockWrite writes[] = { CreateMockWrite(*req), | |
1361 CreateMockWrite(*req2), | |
1362 }; | |
1363 MockRead reads[] = { | |
1364 CreateMockRead(*settings_frame, 1), | |
1365 CreateMockRead(*resp), | |
1366 CreateMockRead(*body), | |
1367 CreateMockRead(*fin_body), | |
1368 CreateMockRead(*resp2, 7), | |
1369 MockRead(ASYNC, ERR_CONNECTION_RESET, 0), // Abort! | |
1370 }; | |
1371 | |
1372 scoped_ptr<OrderedSocketData> data( | |
1373 new OrderedSocketData(reads, arraysize(reads), | |
1374 writes, arraysize(writes))); | |
1375 scoped_ptr<OrderedSocketData> data_placeholder( | |
1376 new OrderedSocketData(NULL, 0, NULL, 0)); | |
1377 | |
1378 BoundNetLog log; | |
1379 TransactionHelperResult out; | |
1380 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
1381 BoundNetLog(), GetParam()); | |
1382 helper.RunPreTestSetup(); | |
1383 helper.AddData(data.get()); | |
1384 // We require placeholder data because three get requests are sent out, so | |
1385 // there needs to be three sets of SSL connection data. | |
1386 helper.AddData(data_placeholder.get()); | |
1387 helper.AddData(data_placeholder.get()); | |
1388 HttpNetworkTransaction trans1(helper.session()); | |
1389 HttpNetworkTransaction trans2(helper.session()); | |
1390 HttpNetworkTransaction* trans3(new HttpNetworkTransaction(helper.session())); | |
1391 | |
1392 TestCompletionCallback callback1; | |
1393 TestCompletionCallback callback2; | |
1394 KillerCallback callback3(trans3); | |
1395 | |
1396 HttpRequestInfo httpreq1 = CreateGetRequest(); | |
1397 HttpRequestInfo httpreq2 = CreateGetRequest(); | |
1398 HttpRequestInfo httpreq3 = CreateGetRequest(); | |
1399 | |
1400 out.rv = trans1.Start(&httpreq1, callback1.callback(), log); | |
1401 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1402 // run transaction 1 through quickly to force a read of our SETTINGS | |
1403 // frame | |
1404 out.rv = callback1.WaitForResult(); | |
1405 ASSERT_EQ(OK, out.rv); | |
1406 | |
1407 out.rv = trans2.Start(&httpreq2, callback2.callback(), log); | |
1408 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1409 out.rv = trans3->Start(&httpreq3, callback3.callback(), log); | |
1410 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1411 out.rv = callback3.WaitForResult(); | |
1412 ASSERT_EQ(ERR_ABORTED, out.rv); | |
1413 | |
1414 EXPECT_EQ(6U, data->read_index()); | |
1415 | |
1416 const HttpResponseInfo* response1 = trans1.GetResponseInfo(); | |
1417 ASSERT_TRUE(response1 != NULL); | |
1418 EXPECT_TRUE(response1->headers != NULL); | |
1419 EXPECT_TRUE(response1->was_fetched_via_spdy); | |
1420 out.status_line = response1->headers->GetStatusLine(); | |
1421 out.response_info = *response1; | |
1422 out.rv = ReadTransaction(&trans1, &out.response_data); | |
1423 EXPECT_EQ(OK, out.rv); | |
1424 | |
1425 const HttpResponseInfo* response2 = trans2.GetResponseInfo(); | |
1426 ASSERT_TRUE(response2 != NULL); | |
1427 out.status_line = response2->headers->GetStatusLine(); | |
1428 out.response_info = *response2; | |
1429 out.rv = ReadTransaction(&trans2, &out.response_data); | |
1430 EXPECT_EQ(ERR_CONNECTION_RESET, out.rv); | |
1431 | |
1432 helper.VerifyDataConsumed(); | |
1433 } | |
1434 | |
1435 // Test that a simple PUT request works. | |
1436 TEST_P(SpdyNetworkTransactionTest, Put) { | |
1437 // Setup the request | |
1438 HttpRequestInfo request; | |
1439 request.method = "PUT"; | |
1440 request.url = GURL("http://www.google.com/"); | |
1441 | |
1442 const SpdyHeaderInfo kSynStartHeader = { | |
1443 spdy::SYN_STREAM, // Kind = Syn | |
1444 1, // Stream ID | |
1445 0, // Associated stream ID | |
1446 net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority | |
1447 spdy::CONTROL_FLAG_FIN, // Control Flags | |
1448 false, // Compressed | |
1449 spdy::INVALID, // Status | |
1450 NULL, // Data | |
1451 0, // Length | |
1452 spdy::DATA_FLAG_NONE // Data Flags | |
1453 }; | |
1454 const char* const kPutHeaders[] = { | |
1455 "method", "PUT", | |
1456 "url", "/", | |
1457 "host", "www.google.com", | |
1458 "scheme", "http", | |
1459 "version", "HTTP/1.1", | |
1460 "content-length", "0" | |
1461 }; | |
1462 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPacket(kSynStartHeader, NULL, 0, | |
1463 kPutHeaders, arraysize(kPutHeaders) / 2)); | |
1464 MockWrite writes[] = { | |
1465 CreateMockWrite(*req) | |
1466 }; | |
1467 | |
1468 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
1469 const SpdyHeaderInfo kSynReplyHeader = { | |
1470 spdy::SYN_REPLY, // Kind = SynReply | |
1471 1, // Stream ID | |
1472 0, // Associated stream ID | |
1473 net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority | |
1474 spdy::CONTROL_FLAG_NONE, // Control Flags | |
1475 false, // Compressed | |
1476 spdy::INVALID, // Status | |
1477 NULL, // Data | |
1478 0, // Length | |
1479 spdy::DATA_FLAG_NONE // Data Flags | |
1480 }; | |
1481 static const char* const kStandardGetHeaders[] = { | |
1482 "status", "200", | |
1483 "version", "HTTP/1.1" | |
1484 "content-length", "1234" | |
1485 }; | |
1486 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPacket(kSynReplyHeader, | |
1487 NULL, 0, kStandardGetHeaders, arraysize(kStandardGetHeaders) / 2)); | |
1488 MockRead reads[] = { | |
1489 CreateMockRead(*resp), | |
1490 CreateMockRead(*body), | |
1491 MockRead(ASYNC, 0, 0) // EOF | |
1492 }; | |
1493 | |
1494 scoped_ptr<DelayedSocketData> data( | |
1495 new DelayedSocketData(1, reads, arraysize(reads), | |
1496 writes, arraysize(writes))); | |
1497 NormalSpdyTransactionHelper helper(request, | |
1498 BoundNetLog(), GetParam()); | |
1499 helper.RunToCompletion(data.get()); | |
1500 TransactionHelperResult out = helper.output(); | |
1501 | |
1502 EXPECT_EQ(OK, out.rv); | |
1503 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1504 } | |
1505 | |
1506 // Test that a simple HEAD request works. | |
1507 TEST_P(SpdyNetworkTransactionTest, Head) { | |
1508 // Setup the request | |
1509 HttpRequestInfo request; | |
1510 request.method = "HEAD"; | |
1511 request.url = GURL("http://www.google.com/"); | |
1512 | |
1513 const SpdyHeaderInfo kSynStartHeader = { | |
1514 spdy::SYN_STREAM, // Kind = Syn | |
1515 1, // Stream ID | |
1516 0, // Associated stream ID | |
1517 net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority | |
1518 spdy::CONTROL_FLAG_FIN, // Control Flags | |
1519 false, // Compressed | |
1520 spdy::INVALID, // Status | |
1521 NULL, // Data | |
1522 0, // Length | |
1523 spdy::DATA_FLAG_NONE // Data Flags | |
1524 }; | |
1525 const char* const kHeadHeaders[] = { | |
1526 "method", "HEAD", | |
1527 "url", "/", | |
1528 "host", "www.google.com", | |
1529 "scheme", "http", | |
1530 "version", "HTTP/1.1", | |
1531 "content-length", "0" | |
1532 }; | |
1533 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPacket(kSynStartHeader, NULL, 0, | |
1534 kHeadHeaders, arraysize(kHeadHeaders) / 2)); | |
1535 MockWrite writes[] = { | |
1536 CreateMockWrite(*req) | |
1537 }; | |
1538 | |
1539 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
1540 const SpdyHeaderInfo kSynReplyHeader = { | |
1541 spdy::SYN_REPLY, // Kind = SynReply | |
1542 1, // Stream ID | |
1543 0, // Associated stream ID | |
1544 net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority | |
1545 spdy::CONTROL_FLAG_NONE, // Control Flags | |
1546 false, // Compressed | |
1547 spdy::INVALID, // Status | |
1548 NULL, // Data | |
1549 0, // Length | |
1550 spdy::DATA_FLAG_NONE // Data Flags | |
1551 }; | |
1552 static const char* const kStandardGetHeaders[] = { | |
1553 "status", "200", | |
1554 "version", "HTTP/1.1" | |
1555 "content-length", "1234" | |
1556 }; | |
1557 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPacket(kSynReplyHeader, | |
1558 NULL, 0, kStandardGetHeaders, arraysize(kStandardGetHeaders) / 2)); | |
1559 MockRead reads[] = { | |
1560 CreateMockRead(*resp), | |
1561 CreateMockRead(*body), | |
1562 MockRead(ASYNC, 0, 0) // EOF | |
1563 }; | |
1564 | |
1565 scoped_ptr<DelayedSocketData> data( | |
1566 new DelayedSocketData(1, reads, arraysize(reads), | |
1567 writes, arraysize(writes))); | |
1568 NormalSpdyTransactionHelper helper(request, | |
1569 BoundNetLog(), GetParam()); | |
1570 helper.RunToCompletion(data.get()); | |
1571 TransactionHelperResult out = helper.output(); | |
1572 | |
1573 EXPECT_EQ(OK, out.rv); | |
1574 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1575 } | |
1576 | |
1577 // Test that a simple POST works. | |
1578 TEST_P(SpdyNetworkTransactionTest, Post) { | |
1579 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(kUploadDataSize, NULL, 0)); | |
1580 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
1581 MockWrite writes[] = { | |
1582 CreateMockWrite(*req), | |
1583 CreateMockWrite(*body), // POST upload frame | |
1584 }; | |
1585 | |
1586 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0)); | |
1587 MockRead reads[] = { | |
1588 CreateMockRead(*resp), | |
1589 CreateMockRead(*body), | |
1590 MockRead(ASYNC, 0, 0) // EOF | |
1591 }; | |
1592 | |
1593 scoped_ptr<DelayedSocketData> data( | |
1594 new DelayedSocketData(2, reads, arraysize(reads), | |
1595 writes, arraysize(writes))); | |
1596 NormalSpdyTransactionHelper helper(CreatePostRequest(), | |
1597 BoundNetLog(), GetParam()); | |
1598 helper.RunToCompletion(data.get()); | |
1599 TransactionHelperResult out = helper.output(); | |
1600 EXPECT_EQ(OK, out.rv); | |
1601 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1602 EXPECT_EQ("hello!", out.response_data); | |
1603 } | |
1604 | |
1605 // Test that a chunked POST works. | |
1606 TEST_P(SpdyNetworkTransactionTest, ChunkedPost) { | |
1607 UploadDataStream::set_merge_chunks(false); | |
1608 scoped_ptr<spdy::SpdyFrame> req(ConstructChunkedSpdyPost(NULL, 0)); | |
1609 scoped_ptr<spdy::SpdyFrame> chunk1(ConstructSpdyBodyFrame(1, false)); | |
1610 scoped_ptr<spdy::SpdyFrame> chunk2(ConstructSpdyBodyFrame(1, true)); | |
1611 MockWrite writes[] = { | |
1612 CreateMockWrite(*req), | |
1613 CreateMockWrite(*chunk1), | |
1614 CreateMockWrite(*chunk2), | |
1615 }; | |
1616 | |
1617 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0)); | |
1618 MockRead reads[] = { | |
1619 CreateMockRead(*resp), | |
1620 CreateMockRead(*chunk1), | |
1621 CreateMockRead(*chunk2), | |
1622 MockRead(ASYNC, 0, 0) // EOF | |
1623 }; | |
1624 | |
1625 scoped_ptr<DelayedSocketData> data( | |
1626 new DelayedSocketData(2, reads, arraysize(reads), | |
1627 writes, arraysize(writes))); | |
1628 NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(), | |
1629 BoundNetLog(), GetParam()); | |
1630 helper.RunToCompletion(data.get()); | |
1631 TransactionHelperResult out = helper.output(); | |
1632 EXPECT_EQ(OK, out.rv); | |
1633 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1634 EXPECT_EQ("hello!hello!", out.response_data); | |
1635 } | |
1636 | |
1637 // Test that a POST without any post data works. | |
1638 TEST_P(SpdyNetworkTransactionTest, NullPost) { | |
1639 // Setup the request | |
1640 HttpRequestInfo request; | |
1641 request.method = "POST"; | |
1642 request.url = GURL("http://www.google.com/"); | |
1643 // Create an empty UploadData. | |
1644 request.upload_data = NULL; | |
1645 | |
1646 // When request.upload_data is NULL for post, content-length is | |
1647 // expected to be 0. | |
1648 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost(0, NULL, 0)); | |
1649 // Set the FIN bit since there will be no body. | |
1650 req->set_flags(spdy::CONTROL_FLAG_FIN); | |
1651 MockWrite writes[] = { | |
1652 CreateMockWrite(*req), | |
1653 }; | |
1654 | |
1655 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0)); | |
1656 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
1657 MockRead reads[] = { | |
1658 CreateMockRead(*resp), | |
1659 CreateMockRead(*body), | |
1660 MockRead(ASYNC, 0, 0) // EOF | |
1661 }; | |
1662 | |
1663 scoped_ptr<DelayedSocketData> data( | |
1664 new DelayedSocketData(1, reads, arraysize(reads), | |
1665 writes, arraysize(writes))); | |
1666 | |
1667 NormalSpdyTransactionHelper helper(request, | |
1668 BoundNetLog(), GetParam()); | |
1669 helper.RunToCompletion(data.get()); | |
1670 TransactionHelperResult out = helper.output(); | |
1671 EXPECT_EQ(OK, out.rv); | |
1672 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1673 EXPECT_EQ("hello!", out.response_data); | |
1674 } | |
1675 | |
1676 // Test that a simple POST works. | |
1677 TEST_P(SpdyNetworkTransactionTest, EmptyPost) { | |
1678 // Setup the request | |
1679 HttpRequestInfo request; | |
1680 request.method = "POST"; | |
1681 request.url = GURL("http://www.google.com/"); | |
1682 // Create an empty UploadData. | |
1683 request.upload_data = new UploadData(); | |
1684 | |
1685 // Http POST Content-Length is using UploadDataStream::size(). | |
1686 // It is the same as request.upload_data->GetContentLengthSync(). | |
1687 scoped_ptr<UploadDataStream> stream( | |
1688 new UploadDataStream(request.upload_data)); | |
1689 ASSERT_EQ(OK, stream->Init()); | |
1690 ASSERT_EQ(request.upload_data->GetContentLengthSync(), | |
1691 stream->size()); | |
1692 | |
1693 scoped_ptr<spdy::SpdyFrame> | |
1694 req(ConstructSpdyPost( | |
1695 request.upload_data->GetContentLengthSync(), NULL, 0)); | |
1696 // Set the FIN bit since there will be no body. | |
1697 req->set_flags(spdy::CONTROL_FLAG_FIN); | |
1698 MockWrite writes[] = { | |
1699 CreateMockWrite(*req), | |
1700 }; | |
1701 | |
1702 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0)); | |
1703 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
1704 MockRead reads[] = { | |
1705 CreateMockRead(*resp), | |
1706 CreateMockRead(*body), | |
1707 MockRead(ASYNC, 0, 0) // EOF | |
1708 }; | |
1709 | |
1710 scoped_ptr<DelayedSocketData> data( | |
1711 new DelayedSocketData(1, reads, arraysize(reads), | |
1712 writes, arraysize(writes))); | |
1713 | |
1714 NormalSpdyTransactionHelper helper(request, | |
1715 BoundNetLog(), GetParam()); | |
1716 helper.RunToCompletion(data.get()); | |
1717 TransactionHelperResult out = helper.output(); | |
1718 EXPECT_EQ(OK, out.rv); | |
1719 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1720 EXPECT_EQ("hello!", out.response_data); | |
1721 } | |
1722 | |
1723 // While we're doing a post, the server sends back a SYN_REPLY. | |
1724 TEST_P(SpdyNetworkTransactionTest, PostWithEarlySynReply) { | |
1725 static const char upload[] = { "hello!" }; | |
1726 | |
1727 // Setup the request | |
1728 HttpRequestInfo request; | |
1729 request.method = "POST"; | |
1730 request.url = GURL("http://www.google.com/"); | |
1731 request.upload_data = new UploadData(); | |
1732 request.upload_data->AppendBytes(upload, sizeof(upload)); | |
1733 | |
1734 // Http POST Content-Length is using UploadDataStream::size(). | |
1735 // It is the same as request.upload_data->GetContentLengthSync(). | |
1736 scoped_ptr<UploadDataStream> stream( | |
1737 new UploadDataStream(request.upload_data)); | |
1738 ASSERT_EQ(OK, stream->Init()); | |
1739 ASSERT_EQ(request.upload_data->GetContentLengthSync(), | |
1740 stream->size()); | |
1741 scoped_ptr<spdy::SpdyFrame> stream_reply(ConstructSpdyPostSynReply(NULL, 0)); | |
1742 scoped_ptr<spdy::SpdyFrame> stream_body(ConstructSpdyBodyFrame(1, true)); | |
1743 MockRead reads[] = { | |
1744 CreateMockRead(*stream_reply, 2), | |
1745 CreateMockRead(*stream_body, 3), | |
1746 MockRead(SYNCHRONOUS, 0, 0) // EOF | |
1747 }; | |
1748 | |
1749 scoped_ptr<DelayedSocketData> data( | |
1750 new DelayedSocketData(0, reads, arraysize(reads), NULL, 0)); | |
1751 NormalSpdyTransactionHelper helper(request, | |
1752 BoundNetLog(), GetParam()); | |
1753 helper.RunPreTestSetup(); | |
1754 helper.AddData(data.get()); | |
1755 helper.RunDefaultTest(); | |
1756 helper.VerifyDataConsumed(); | |
1757 | |
1758 TransactionHelperResult out = helper.output(); | |
1759 EXPECT_EQ(ERR_SYN_REPLY_NOT_RECEIVED, out.rv); | |
1760 } | |
1761 | |
1762 // The client upon cancellation tries to send a RST_STREAM frame. The mock | |
1763 // socket causes the TCP write to return zero. This test checks that the client | |
1764 // tries to queue up the RST_STREAM frame again. | |
1765 TEST_P(SpdyNetworkTransactionTest, SocketWriteReturnsZero) { | |
1766 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
1767 scoped_ptr<spdy::SpdyFrame> rst( | |
1768 ConstructSpdyRstStream(1, spdy::CANCEL)); | |
1769 MockWrite writes[] = { | |
1770 CreateMockWrite(*req.get(), 0, SYNCHRONOUS), | |
1771 MockWrite(SYNCHRONOUS, 0, 0, 2), | |
1772 CreateMockWrite(*rst.get(), 3, SYNCHRONOUS), | |
1773 }; | |
1774 | |
1775 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
1776 MockRead reads[] = { | |
1777 CreateMockRead(*resp.get(), 1, ASYNC), | |
1778 MockRead(ASYNC, 0, 0, 4) // EOF | |
1779 }; | |
1780 | |
1781 scoped_refptr<DeterministicSocketData> data( | |
1782 new DeterministicSocketData(reads, arraysize(reads), | |
1783 writes, arraysize(writes))); | |
1784 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
1785 BoundNetLog(), GetParam()); | |
1786 helper.SetDeterministic(); | |
1787 helper.RunPreTestSetup(); | |
1788 helper.AddDeterministicData(data.get()); | |
1789 HttpNetworkTransaction* trans = helper.trans(); | |
1790 | |
1791 TestCompletionCallback callback; | |
1792 int rv = trans->Start( | |
1793 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
1794 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1795 | |
1796 data->SetStop(2); | |
1797 data->Run(); | |
1798 helper.ResetTrans(); | |
1799 data->SetStop(20); | |
1800 data->Run(); | |
1801 | |
1802 helper.VerifyDataConsumed(); | |
1803 } | |
1804 | |
1805 // Test that the transaction doesn't crash when we don't have a reply. | |
1806 TEST_P(SpdyNetworkTransactionTest, ResponseWithoutSynReply) { | |
1807 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
1808 MockRead reads[] = { | |
1809 CreateMockRead(*body), | |
1810 MockRead(ASYNC, 0, 0) // EOF | |
1811 }; | |
1812 | |
1813 scoped_ptr<DelayedSocketData> data( | |
1814 new DelayedSocketData(1, reads, arraysize(reads), NULL, 0)); | |
1815 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
1816 BoundNetLog(), GetParam()); | |
1817 helper.RunToCompletion(data.get()); | |
1818 TransactionHelperResult out = helper.output(); | |
1819 EXPECT_EQ(ERR_SYN_REPLY_NOT_RECEIVED, out.rv); | |
1820 } | |
1821 | |
1822 // Test that the transaction doesn't crash when we get two replies on the same | |
1823 // stream ID. See http://crbug.com/45639. | |
1824 TEST_P(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) { | |
1825 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
1826 MockWrite writes[] = { CreateMockWrite(*req) }; | |
1827 | |
1828 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
1829 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
1830 MockRead reads[] = { | |
1831 CreateMockRead(*resp), | |
1832 CreateMockRead(*resp), | |
1833 CreateMockRead(*body), | |
1834 MockRead(ASYNC, 0, 0) // EOF | |
1835 }; | |
1836 | |
1837 scoped_ptr<DelayedSocketData> data( | |
1838 new DelayedSocketData(1, reads, arraysize(reads), | |
1839 writes, arraysize(writes))); | |
1840 | |
1841 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
1842 BoundNetLog(), GetParam()); | |
1843 helper.RunPreTestSetup(); | |
1844 helper.AddData(data.get()); | |
1845 | |
1846 HttpNetworkTransaction* trans = helper.trans(); | |
1847 | |
1848 TestCompletionCallback callback; | |
1849 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
1850 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1851 rv = callback.WaitForResult(); | |
1852 EXPECT_EQ(OK, rv); | |
1853 | |
1854 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
1855 ASSERT_TRUE(response != NULL); | |
1856 EXPECT_TRUE(response->headers != NULL); | |
1857 EXPECT_TRUE(response->was_fetched_via_spdy); | |
1858 std::string response_data; | |
1859 rv = ReadTransaction(trans, &response_data); | |
1860 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv); | |
1861 | |
1862 helper.VerifyDataConsumed(); | |
1863 } | |
1864 | |
1865 // Test that sent data frames and received WINDOW_UPDATE frames change | |
1866 // the send_window_size_ correctly. | |
1867 | |
1868 // WINDOW_UPDATE is different than most other frames in that it can arrive | |
1869 // while the client is still sending the request body. In order to enforce | |
1870 // this scenario, we feed a couple of dummy frames and give a delay of 0 to | |
1871 // socket data provider, so that initial read that is done as soon as the | |
1872 // stream is created, succeeds and schedules another read. This way reads | |
1873 // and writes are interleaved; after doing a full frame write, SpdyStream | |
1874 // will break out of DoLoop and will read and process a WINDOW_UPDATE. | |
1875 // Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away | |
1876 // since request has not been completely written, therefore we feed | |
1877 // enough number of WINDOW_UPDATEs to finish the first read and cause a | |
1878 // write, leading to a complete write of request body; after that we send | |
1879 // a reply with a body, to cause a graceful shutdown. | |
1880 | |
1881 // TODO(agayev): develop a socket data provider where both, reads and | |
1882 // writes are ordered so that writing tests like these are easy and rewrite | |
1883 // all these tests using it. Right now we are working around the | |
1884 // limitations as described above and it's not deterministic, tests may | |
1885 // fail under specific circumstances. | |
1886 TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) { | |
1887 SpdySession::set_use_flow_control(SpdySession::kEnableFlowControl); | |
1888 | |
1889 static int kFrameCount = 2; | |
1890 scoped_ptr<std::string> content( | |
1891 new std::string(kMaxSpdyFrameChunkSize, 'a')); | |
1892 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost( | |
1893 kMaxSpdyFrameChunkSize * kFrameCount, NULL, 0)); | |
1894 scoped_ptr<spdy::SpdyFrame> body( | |
1895 ConstructSpdyBodyFrame(1, content->c_str(), content->size(), false)); | |
1896 scoped_ptr<spdy::SpdyFrame> body_end( | |
1897 ConstructSpdyBodyFrame(1, content->c_str(), content->size(), true)); | |
1898 | |
1899 MockWrite writes[] = { | |
1900 CreateMockWrite(*req), | |
1901 CreateMockWrite(*body), | |
1902 CreateMockWrite(*body_end), | |
1903 }; | |
1904 | |
1905 static const int32 kDeltaWindowSize = 0xff; | |
1906 static const int kDeltaCount = 4; | |
1907 scoped_ptr<spdy::SpdyFrame> window_update( | |
1908 ConstructSpdyWindowUpdate(1, kDeltaWindowSize)); | |
1909 scoped_ptr<spdy::SpdyFrame> window_update_dummy( | |
1910 ConstructSpdyWindowUpdate(2, kDeltaWindowSize)); | |
1911 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0)); | |
1912 MockRead reads[] = { | |
1913 CreateMockRead(*window_update_dummy), | |
1914 CreateMockRead(*window_update_dummy), | |
1915 CreateMockRead(*window_update_dummy), | |
1916 CreateMockRead(*window_update), // Four updates, therefore window | |
1917 CreateMockRead(*window_update), // size should increase by | |
1918 CreateMockRead(*window_update), // kDeltaWindowSize * 4 | |
1919 CreateMockRead(*window_update), | |
1920 CreateMockRead(*resp), | |
1921 CreateMockRead(*body_end), | |
1922 MockRead(ASYNC, 0, 0) // EOF | |
1923 }; | |
1924 | |
1925 scoped_ptr<DelayedSocketData> data( | |
1926 new DelayedSocketData(0, reads, arraysize(reads), | |
1927 writes, arraysize(writes))); | |
1928 | |
1929 // Setup the request | |
1930 HttpRequestInfo request; | |
1931 request.method = "POST"; | |
1932 request.url = GURL(kDefaultURL); | |
1933 request.upload_data = new UploadData(); | |
1934 for (int i = 0; i < kFrameCount; ++i) | |
1935 request.upload_data->AppendBytes(content->c_str(), content->size()); | |
1936 | |
1937 NormalSpdyTransactionHelper helper(request, BoundNetLog(), GetParam()); | |
1938 helper.AddData(data.get()); | |
1939 helper.RunPreTestSetup(); | |
1940 | |
1941 HttpNetworkTransaction* trans = helper.trans(); | |
1942 | |
1943 TestCompletionCallback callback; | |
1944 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
1945 | |
1946 EXPECT_EQ(ERR_IO_PENDING, rv); | |
1947 rv = callback.WaitForResult(); | |
1948 EXPECT_EQ(OK, rv); | |
1949 | |
1950 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); | |
1951 ASSERT_TRUE(stream != NULL); | |
1952 ASSERT_TRUE(stream->stream() != NULL); | |
1953 EXPECT_EQ(static_cast<int>(spdy::kSpdyStreamInitialWindowSize) + | |
1954 kDeltaWindowSize * kDeltaCount - | |
1955 kMaxSpdyFrameChunkSize * kFrameCount, | |
1956 stream->stream()->send_window_size()); | |
1957 helper.VerifyDataConsumed(); | |
1958 | |
1959 SpdySession::set_use_flow_control(SpdySession::kFlowControlBasedOnNPN); | |
1960 } | |
1961 | |
1962 // Test that received data frames and sent WINDOW_UPDATE frames change | |
1963 // the recv_window_size_ correctly. | |
1964 TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) { | |
1965 SpdySession::set_use_flow_control(SpdySession::kEnableFlowControl); | |
1966 | |
1967 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
1968 scoped_ptr<spdy::SpdyFrame> window_update( | |
1969 ConstructSpdyWindowUpdate(1, kUploadDataSize)); | |
1970 | |
1971 MockWrite writes[] = { | |
1972 CreateMockWrite(*req), | |
1973 CreateMockWrite(*window_update), | |
1974 }; | |
1975 | |
1976 scoped_ptr<spdy::SpdyFrame> resp( | |
1977 ConstructSpdyGetSynReply(NULL, 0, 1)); | |
1978 scoped_ptr<spdy::SpdyFrame> body_no_fin( | |
1979 ConstructSpdyBodyFrame(1, false)); | |
1980 scoped_ptr<spdy::SpdyFrame> body_fin( | |
1981 ConstructSpdyBodyFrame(1, NULL, 0, true)); | |
1982 MockRead reads[] = { | |
1983 CreateMockRead(*resp), | |
1984 CreateMockRead(*body_no_fin), | |
1985 MockRead(ASYNC, ERR_IO_PENDING, 0), // Force a pause | |
1986 CreateMockRead(*body_fin), | |
1987 MockRead(ASYNC, ERR_IO_PENDING, 0), // Force a pause | |
1988 MockRead(ASYNC, 0, 0) // EOF | |
1989 }; | |
1990 | |
1991 scoped_ptr<DelayedSocketData> data( | |
1992 new DelayedSocketData(1, reads, arraysize(reads), | |
1993 writes, arraysize(writes))); | |
1994 | |
1995 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
1996 BoundNetLog(), GetParam()); | |
1997 helper.AddData(data.get()); | |
1998 helper.RunPreTestSetup(); | |
1999 HttpNetworkTransaction* trans = helper.trans(); | |
2000 | |
2001 TestCompletionCallback callback; | |
2002 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
2003 | |
2004 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2005 rv = callback.WaitForResult(); | |
2006 EXPECT_EQ(OK, rv); | |
2007 | |
2008 SpdyHttpStream* stream = | |
2009 static_cast<SpdyHttpStream*>(trans->stream_.get()); | |
2010 ASSERT_TRUE(stream != NULL); | |
2011 ASSERT_TRUE(stream->stream() != NULL); | |
2012 | |
2013 EXPECT_EQ( | |
2014 static_cast<int>(spdy::kSpdyStreamInitialWindowSize) - kUploadDataSize, | |
2015 stream->stream()->recv_window_size()); | |
2016 | |
2017 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
2018 ASSERT_TRUE(response != NULL); | |
2019 ASSERT_TRUE(response->headers != NULL); | |
2020 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
2021 EXPECT_TRUE(response->was_fetched_via_spdy); | |
2022 | |
2023 // Force sending of WINDOW_UPDATE by setting initial_recv_window_size to a | |
2024 // small value. | |
2025 stream->stream()->set_initial_recv_window_size(kUploadDataSize / 2); | |
2026 | |
2027 // Issue a read which will cause a WINDOW_UPDATE to be sent and window | |
2028 // size increased to default. | |
2029 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kUploadDataSize)); | |
2030 rv = trans->Read(buf, kUploadDataSize, CompletionCallback()); | |
2031 EXPECT_EQ(kUploadDataSize, rv); | |
2032 std::string content(buf->data(), buf->data()+kUploadDataSize); | |
2033 EXPECT_STREQ(kUploadData, content.c_str()); | |
2034 | |
2035 // Schedule the reading of empty data frame with FIN | |
2036 data->CompleteRead(); | |
2037 | |
2038 // Force write of WINDOW_UPDATE which was scheduled during the above | |
2039 // read. | |
2040 MessageLoop::current()->RunAllPending(); | |
2041 | |
2042 // Read EOF. | |
2043 data->CompleteRead(); | |
2044 | |
2045 helper.VerifyDataConsumed(); | |
2046 | |
2047 SpdySession::set_use_flow_control(SpdySession::kFlowControlBasedOnNPN); | |
2048 } | |
2049 | |
2050 // Test that WINDOW_UPDATE frame causing overflow is handled correctly. We | |
2051 // use the same trick as in the above test to enforce our scenario. | |
2052 TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) { | |
2053 SpdySession::set_use_flow_control(SpdySession::kEnableFlowControl); | |
2054 | |
2055 // number of full frames we hope to write (but will not, used to | |
2056 // set content-length header correctly) | |
2057 static int kFrameCount = 3; | |
2058 | |
2059 scoped_ptr<std::string> content( | |
2060 new std::string(kMaxSpdyFrameChunkSize, 'a')); | |
2061 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost( | |
2062 kMaxSpdyFrameChunkSize * kFrameCount, NULL, 0)); | |
2063 scoped_ptr<spdy::SpdyFrame> body( | |
2064 ConstructSpdyBodyFrame(1, content->c_str(), content->size(), false)); | |
2065 scoped_ptr<spdy::SpdyFrame> rst( | |
2066 ConstructSpdyRstStream(1, spdy::FLOW_CONTROL_ERROR)); | |
2067 | |
2068 // We're not going to write a data frame with FIN, we'll receive a bad | |
2069 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame. | |
2070 MockWrite writes[] = { | |
2071 CreateMockWrite(*req), | |
2072 CreateMockWrite(*body), | |
2073 CreateMockWrite(*rst), | |
2074 }; | |
2075 | |
2076 static const int32 kDeltaWindowSize = 0x7fffffff; // cause an overflow | |
2077 scoped_ptr<spdy::SpdyFrame> window_update( | |
2078 ConstructSpdyWindowUpdate(1, kDeltaWindowSize)); | |
2079 scoped_ptr<spdy::SpdyFrame> window_update2( | |
2080 ConstructSpdyWindowUpdate(2, kDeltaWindowSize)); | |
2081 scoped_ptr<spdy::SpdyFrame> reply(ConstructSpdyPostSynReply(NULL, 0)); | |
2082 | |
2083 MockRead reads[] = { | |
2084 CreateMockRead(*window_update2), | |
2085 CreateMockRead(*window_update2), | |
2086 CreateMockRead(*window_update), | |
2087 CreateMockRead(*window_update), | |
2088 CreateMockRead(*window_update), | |
2089 MockRead(ASYNC, ERR_IO_PENDING, 0), // Wait for the RST to be written. | |
2090 MockRead(ASYNC, 0, 0) // EOF | |
2091 }; | |
2092 | |
2093 scoped_ptr<DelayedSocketData> data( | |
2094 new DelayedSocketData(0, reads, arraysize(reads), | |
2095 writes, arraysize(writes))); | |
2096 | |
2097 // Setup the request | |
2098 HttpRequestInfo request; | |
2099 request.method = "POST"; | |
2100 request.url = GURL("http://www.google.com/"); | |
2101 request.upload_data = new UploadData(); | |
2102 for (int i = 0; i < kFrameCount; ++i) | |
2103 request.upload_data->AppendBytes(content->c_str(), content->size()); | |
2104 | |
2105 NormalSpdyTransactionHelper helper(request, | |
2106 BoundNetLog(), GetParam()); | |
2107 helper.AddData(data.get()); | |
2108 helper.RunPreTestSetup(); | |
2109 | |
2110 HttpNetworkTransaction* trans = helper.trans(); | |
2111 | |
2112 TestCompletionCallback callback; | |
2113 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
2114 | |
2115 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2116 rv = callback.WaitForResult(); | |
2117 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv); | |
2118 | |
2119 data->CompleteRead(); | |
2120 | |
2121 ASSERT_TRUE(helper.session() != NULL); | |
2122 ASSERT_TRUE(helper.session()->spdy_session_pool() != NULL); | |
2123 helper.session()->spdy_session_pool()->CloseAllSessions(); | |
2124 helper.VerifyDataConsumed(); | |
2125 | |
2126 SpdySession::set_use_flow_control(SpdySession::kFlowControlBasedOnNPN); | |
2127 } | |
2128 | |
2129 // Test that after hitting a send window size of 0, the write process | |
2130 // stalls and upon receiving WINDOW_UPDATE frame write resumes. | |
2131 | |
2132 // This test constructs a POST request followed by enough data frames | |
2133 // containing 'a' that would make the window size 0, followed by another | |
2134 // data frame containing default content (which is "hello!") and this frame | |
2135 // also contains a FIN flag. DelayedSocketData is used to enforce all | |
2136 // writes go through before a read could happen. However, the last frame | |
2137 // ("hello!") is not supposed to go through since by the time its turn | |
2138 // arrives, window size is 0. At this point MessageLoop::Run() called via | |
2139 // callback would block. Therefore we call MessageLoop::RunAllPending() | |
2140 // which returns after performing all possible writes. We use DCHECKS to | |
2141 // ensure that last data frame is still there and stream has stalled. | |
2142 // After that, next read is artifically enforced, which causes a | |
2143 // WINDOW_UPDATE to be read and I/O process resumes. | |
2144 TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) { | |
2145 SpdySession::set_use_flow_control(SpdySession::kEnableFlowControl); | |
2146 | |
2147 // Number of frames we need to send to zero out the window size: data | |
2148 // frames plus SYN_STREAM plus the last data frame; also we need another | |
2149 // data frame that we will send once the WINDOW_UPDATE is received, | |
2150 // therefore +3. | |
2151 size_t nwrites = | |
2152 spdy::kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3; | |
2153 | |
2154 // Calculate last frame's size; 0 size data frame is legal. | |
2155 size_t last_frame_size = | |
2156 spdy::kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize; | |
2157 | |
2158 // Construct content for a data frame of maximum size. | |
2159 scoped_ptr<std::string> content( | |
2160 new std::string(kMaxSpdyFrameChunkSize, 'a')); | |
2161 | |
2162 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPost( | |
2163 spdy::kSpdyStreamInitialWindowSize + kUploadDataSize, NULL, 0)); | |
2164 | |
2165 // Full frames. | |
2166 scoped_ptr<spdy::SpdyFrame> body1( | |
2167 ConstructSpdyBodyFrame(1, content->c_str(), content->size(), false)); | |
2168 | |
2169 // Last frame to zero out the window size. | |
2170 scoped_ptr<spdy::SpdyFrame> body2( | |
2171 ConstructSpdyBodyFrame(1, content->c_str(), last_frame_size, false)); | |
2172 | |
2173 // Data frame to be sent once WINDOW_UPDATE frame is received. | |
2174 scoped_ptr<spdy::SpdyFrame> body3(ConstructSpdyBodyFrame(1, true)); | |
2175 | |
2176 // Fill in mock writes. | |
2177 scoped_array<MockWrite> writes(new MockWrite[nwrites]); | |
2178 size_t i = 0; | |
2179 writes[i] = CreateMockWrite(*req); | |
2180 for (i = 1; i < nwrites-2; i++) | |
2181 writes[i] = CreateMockWrite(*body1); | |
2182 writes[i++] = CreateMockWrite(*body2); | |
2183 writes[i] = CreateMockWrite(*body3); | |
2184 | |
2185 // Construct read frame, give enough space to upload the rest of the | |
2186 // data. | |
2187 scoped_ptr<spdy::SpdyFrame> window_update( | |
2188 ConstructSpdyWindowUpdate(1, kUploadDataSize)); | |
2189 scoped_ptr<spdy::SpdyFrame> reply(ConstructSpdyPostSynReply(NULL, 0)); | |
2190 MockRead reads[] = { | |
2191 CreateMockRead(*window_update), | |
2192 CreateMockRead(*window_update), | |
2193 CreateMockRead(*reply), | |
2194 CreateMockRead(*body2), | |
2195 CreateMockRead(*body3), | |
2196 MockRead(ASYNC, 0, 0) // EOF | |
2197 }; | |
2198 | |
2199 // Force all writes to happen before any read, last write will not | |
2200 // actually queue a frame, due to window size being 0. | |
2201 scoped_ptr<DelayedSocketData> data( | |
2202 new DelayedSocketData(nwrites, reads, arraysize(reads), | |
2203 writes.get(), nwrites)); | |
2204 | |
2205 HttpRequestInfo request; | |
2206 request.method = "POST"; | |
2207 request.url = GURL("http://www.google.com/"); | |
2208 request.upload_data = new UploadData(); | |
2209 scoped_ptr<std::string> upload_data( | |
2210 new std::string(spdy::kSpdyStreamInitialWindowSize, 'a')); | |
2211 upload_data->append(kUploadData, kUploadDataSize); | |
2212 request.upload_data->AppendBytes(upload_data->c_str(), upload_data->size()); | |
2213 NormalSpdyTransactionHelper helper(request, | |
2214 BoundNetLog(), GetParam()); | |
2215 helper.AddData(data.get()); | |
2216 helper.RunPreTestSetup(); | |
2217 | |
2218 HttpNetworkTransaction* trans = helper.trans(); | |
2219 | |
2220 TestCompletionCallback callback; | |
2221 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
2222 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2223 | |
2224 MessageLoop::current()->RunAllPending(); // Write as much as we can. | |
2225 | |
2226 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); | |
2227 ASSERT_TRUE(stream != NULL); | |
2228 ASSERT_TRUE(stream->stream() != NULL); | |
2229 EXPECT_EQ(0, stream->stream()->send_window_size()); | |
2230 // All the body data should have been read. | |
2231 // TODO(satorux): This is because of the weirdness in reading the request | |
2232 // body in OnSendBodyComplete(). See crbug.com/113107. | |
2233 EXPECT_TRUE(stream->request_body_stream_->IsEOF()); | |
2234 // But the body is not yet fully sent ("hello!" is not yet sent). | |
2235 EXPECT_FALSE(stream->stream()->body_sent()); | |
2236 | |
2237 data->ForceNextRead(); // Read in WINDOW_UPDATE frame. | |
2238 rv = callback.WaitForResult(); | |
2239 helper.VerifyDataConsumed(); | |
2240 | |
2241 SpdySession::set_use_flow_control(SpdySession::kFlowControlBasedOnNPN); | |
2242 } | |
2243 | |
2244 TEST_P(SpdyNetworkTransactionTest, CancelledTransaction) { | |
2245 // Construct the request. | |
2246 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
2247 MockWrite writes[] = { | |
2248 CreateMockWrite(*req), | |
2249 }; | |
2250 | |
2251 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2252 MockRead reads[] = { | |
2253 CreateMockRead(*resp), | |
2254 // This following read isn't used by the test, except during the | |
2255 // RunAllPending() call at the end since the SpdySession survives the | |
2256 // HttpNetworkTransaction and still tries to continue Read()'ing. Any | |
2257 // MockRead will do here. | |
2258 MockRead(ASYNC, 0, 0) // EOF | |
2259 }; | |
2260 | |
2261 StaticSocketDataProvider data(reads, arraysize(reads), | |
2262 writes, arraysize(writes)); | |
2263 | |
2264 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
2265 BoundNetLog(), GetParam()); | |
2266 helper.RunPreTestSetup(); | |
2267 helper.AddData(&data); | |
2268 HttpNetworkTransaction* trans = helper.trans(); | |
2269 | |
2270 TestCompletionCallback callback; | |
2271 int rv = trans->Start( | |
2272 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
2273 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2274 helper.ResetTrans(); // Cancel the transaction. | |
2275 | |
2276 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the | |
2277 // MockClientSocketFactory) are still alive. | |
2278 MessageLoop::current()->RunAllPending(); | |
2279 helper.VerifyDataNotConsumed(); | |
2280 } | |
2281 | |
2282 // Verify that the client sends a Rst Frame upon cancelling the stream. | |
2283 TEST_P(SpdyNetworkTransactionTest, CancelledTransactionSendRst) { | |
2284 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
2285 scoped_ptr<spdy::SpdyFrame> rst( | |
2286 ConstructSpdyRstStream(1, spdy::CANCEL)); | |
2287 MockWrite writes[] = { | |
2288 CreateMockWrite(*req, 0, SYNCHRONOUS), | |
2289 CreateMockWrite(*rst, 2, SYNCHRONOUS), | |
2290 }; | |
2291 | |
2292 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2293 MockRead reads[] = { | |
2294 CreateMockRead(*resp, 1, ASYNC), | |
2295 MockRead(ASYNC, 0, 0, 3) // EOF | |
2296 }; | |
2297 | |
2298 scoped_refptr<DeterministicSocketData> data( | |
2299 new DeterministicSocketData(reads, arraysize(reads), | |
2300 writes, arraysize(writes))); | |
2301 | |
2302 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
2303 BoundNetLog(), | |
2304 GetParam()); | |
2305 helper.SetDeterministic(); | |
2306 helper.RunPreTestSetup(); | |
2307 helper.AddDeterministicData(data.get()); | |
2308 HttpNetworkTransaction* trans = helper.trans(); | |
2309 | |
2310 TestCompletionCallback callback; | |
2311 | |
2312 int rv = trans->Start( | |
2313 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
2314 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2315 | |
2316 data->SetStop(2); | |
2317 data->Run(); | |
2318 helper.ResetTrans(); | |
2319 data->SetStop(20); | |
2320 data->Run(); | |
2321 | |
2322 helper.VerifyDataConsumed(); | |
2323 } | |
2324 | |
2325 // Verify that the client can correctly deal with the user callback attempting | |
2326 // to start another transaction on a session that is closing down. See | |
2327 // http://crbug.com/47455 | |
2328 TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) { | |
2329 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
2330 MockWrite writes[] = { CreateMockWrite(*req) }; | |
2331 MockWrite writes2[] = { CreateMockWrite(*req) }; | |
2332 | |
2333 // The indicated length of this packet is longer than its actual length. When | |
2334 // the session receives an empty packet after this one, it shuts down the | |
2335 // session, and calls the read callback with the incomplete data. | |
2336 const uint8 kGetBodyFrame2[] = { | |
2337 0x00, 0x00, 0x00, 0x01, | |
2338 0x01, 0x00, 0x00, 0x07, | |
2339 'h', 'e', 'l', 'l', 'o', '!', | |
2340 }; | |
2341 | |
2342 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2343 MockRead reads[] = { | |
2344 CreateMockRead(*resp, 2), | |
2345 MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause | |
2346 MockRead(ASYNC, reinterpret_cast<const char*>(kGetBodyFrame2), | |
2347 arraysize(kGetBodyFrame2), 4), | |
2348 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause | |
2349 MockRead(ASYNC, 0, 0, 6), // EOF | |
2350 }; | |
2351 MockRead reads2[] = { | |
2352 CreateMockRead(*resp, 2), | |
2353 MockRead(ASYNC, 0, 0, 3), // EOF | |
2354 }; | |
2355 | |
2356 scoped_ptr<OrderedSocketData> data( | |
2357 new OrderedSocketData(reads, arraysize(reads), | |
2358 writes, arraysize(writes))); | |
2359 scoped_ptr<DelayedSocketData> data2( | |
2360 new DelayedSocketData(1, reads2, arraysize(reads2), | |
2361 writes2, arraysize(writes2))); | |
2362 | |
2363 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
2364 BoundNetLog(), GetParam()); | |
2365 helper.RunPreTestSetup(); | |
2366 helper.AddData(data.get()); | |
2367 helper.AddData(data2.get()); | |
2368 HttpNetworkTransaction* trans = helper.trans(); | |
2369 | |
2370 // Start the transaction with basic parameters. | |
2371 TestCompletionCallback callback; | |
2372 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
2373 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2374 rv = callback.WaitForResult(); | |
2375 | |
2376 const int kSize = 3000; | |
2377 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); | |
2378 rv = trans->Read( | |
2379 buf, kSize, | |
2380 base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback, | |
2381 helper.session())); | |
2382 // This forces an err_IO_pending, which sets the callback. | |
2383 data->CompleteRead(); | |
2384 // This finishes the read. | |
2385 data->CompleteRead(); | |
2386 helper.VerifyDataConsumed(); | |
2387 } | |
2388 | |
2389 // Verify that the client can correctly deal with the user callback deleting the | |
2390 // transaction. Failures will usually be valgrind errors. See | |
2391 // http://crbug.com/46925 | |
2392 TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) { | |
2393 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
2394 MockWrite writes[] = { CreateMockWrite(*req) }; | |
2395 | |
2396 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2397 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
2398 MockRead reads[] = { | |
2399 CreateMockRead(*resp.get(), 2), | |
2400 MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause | |
2401 CreateMockRead(*body.get(), 4), | |
2402 MockRead(ASYNC, 0, 0, 5), // EOF | |
2403 }; | |
2404 | |
2405 scoped_ptr<OrderedSocketData> data( | |
2406 new OrderedSocketData(reads, arraysize(reads), | |
2407 writes, arraysize(writes))); | |
2408 | |
2409 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
2410 BoundNetLog(), GetParam()); | |
2411 helper.RunPreTestSetup(); | |
2412 helper.AddData(data.get()); | |
2413 HttpNetworkTransaction* trans = helper.trans(); | |
2414 | |
2415 // Start the transaction with basic parameters. | |
2416 TestCompletionCallback callback; | |
2417 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
2418 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2419 rv = callback.WaitForResult(); | |
2420 | |
2421 // Setup a user callback which will delete the session, and clear out the | |
2422 // memory holding the stream object. Note that the callback deletes trans. | |
2423 const int kSize = 3000; | |
2424 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); | |
2425 rv = trans->Read( | |
2426 buf, kSize, | |
2427 base::Bind(&SpdyNetworkTransactionTest::DeleteSessionCallback, | |
2428 base::Unretained(&helper))); | |
2429 ASSERT_EQ(ERR_IO_PENDING, rv); | |
2430 data->CompleteRead(); | |
2431 | |
2432 // Finish running rest of tasks. | |
2433 MessageLoop::current()->RunAllPending(); | |
2434 helper.VerifyDataConsumed(); | |
2435 } | |
2436 | |
2437 // Send a spdy request to www.google.com that gets redirected to www.foo.com. | |
2438 TEST_P(SpdyNetworkTransactionTest, RedirectGetRequest) { | |
2439 // These are headers which the net::URLRequest tacks on. | |
2440 const char* const kExtraHeaders[] = { | |
2441 "accept-encoding", | |
2442 "gzip,deflate", | |
2443 }; | |
2444 const SpdyHeaderInfo kSynStartHeader = MakeSpdyHeader(spdy::SYN_STREAM); | |
2445 const char* const kStandardGetHeaders[] = { | |
2446 "host", | |
2447 "www.google.com", | |
2448 "method", | |
2449 "GET", | |
2450 "scheme", | |
2451 "http", | |
2452 "url", | |
2453 "/", | |
2454 "user-agent", | |
2455 "", | |
2456 "version", | |
2457 "HTTP/1.1" | |
2458 }; | |
2459 const char* const kStandardGetHeaders2[] = { | |
2460 "host", | |
2461 "www.foo.com", | |
2462 "method", | |
2463 "GET", | |
2464 "scheme", | |
2465 "http", | |
2466 "url", | |
2467 "/index.php", | |
2468 "user-agent", | |
2469 "", | |
2470 "version", | |
2471 "HTTP/1.1" | |
2472 }; | |
2473 | |
2474 // Setup writes/reads to www.google.com | |
2475 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyPacket( | |
2476 kSynStartHeader, kExtraHeaders, arraysize(kExtraHeaders) / 2, | |
2477 kStandardGetHeaders, arraysize(kStandardGetHeaders) / 2)); | |
2478 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyPacket( | |
2479 kSynStartHeader, kExtraHeaders, arraysize(kExtraHeaders) / 2, | |
2480 kStandardGetHeaders2, arraysize(kStandardGetHeaders2) / 2)); | |
2481 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReplyRedirect(1)); | |
2482 MockWrite writes[] = { | |
2483 CreateMockWrite(*req, 1), | |
2484 }; | |
2485 MockRead reads[] = { | |
2486 CreateMockRead(*resp, 2), | |
2487 MockRead(ASYNC, 0, 0, 3) // EOF | |
2488 }; | |
2489 | |
2490 // Setup writes/reads to www.foo.com | |
2491 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2492 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(1, true)); | |
2493 MockWrite writes2[] = { | |
2494 CreateMockWrite(*req2, 1), | |
2495 }; | |
2496 MockRead reads2[] = { | |
2497 CreateMockRead(*resp2, 2), | |
2498 CreateMockRead(*body2, 3), | |
2499 MockRead(ASYNC, 0, 0, 4) // EOF | |
2500 }; | |
2501 scoped_ptr<OrderedSocketData> data( | |
2502 new OrderedSocketData(reads, arraysize(reads), | |
2503 writes, arraysize(writes))); | |
2504 scoped_ptr<OrderedSocketData> data2( | |
2505 new OrderedSocketData(reads2, arraysize(reads2), | |
2506 writes2, arraysize(writes2))); | |
2507 | |
2508 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN | |
2509 HttpStreamFactory::set_force_spdy_over_ssl(false); | |
2510 HttpStreamFactory::set_force_spdy_always(true); | |
2511 TestDelegate d; | |
2512 { | |
2513 net::URLRequest r(GURL("http://www.google.com/"), &d); | |
2514 SpdyURLRequestContext* spdy_url_request_context = | |
2515 new SpdyURLRequestContext(); | |
2516 r.set_context(spdy_url_request_context); | |
2517 spdy_url_request_context->socket_factory(). | |
2518 AddSocketDataProvider(data.get()); | |
2519 spdy_url_request_context->socket_factory(). | |
2520 AddSocketDataProvider(data2.get()); | |
2521 | |
2522 d.set_quit_on_redirect(true); | |
2523 r.Start(); | |
2524 MessageLoop::current()->Run(); | |
2525 | |
2526 EXPECT_EQ(1, d.received_redirect_count()); | |
2527 | |
2528 r.FollowDeferredRedirect(); | |
2529 MessageLoop::current()->Run(); | |
2530 EXPECT_EQ(1, d.response_started_count()); | |
2531 EXPECT_FALSE(d.received_data_before_response()); | |
2532 EXPECT_EQ(net::URLRequestStatus::SUCCESS, r.status().status()); | |
2533 std::string contents("hello!"); | |
2534 EXPECT_EQ(contents, d.data_received()); | |
2535 } | |
2536 EXPECT_TRUE(data->at_read_eof()); | |
2537 EXPECT_TRUE(data->at_write_eof()); | |
2538 EXPECT_TRUE(data2->at_read_eof()); | |
2539 EXPECT_TRUE(data2->at_write_eof()); | |
2540 } | |
2541 | |
2542 // Detect response with upper case headers and reset the stream. | |
2543 TEST_P(SpdyNetworkTransactionTest, UpperCaseHeaders) { | |
2544 scoped_ptr<spdy::SpdyFrame> | |
2545 syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
2546 scoped_ptr<spdy::SpdyFrame> | |
2547 rst(ConstructSpdyRstStream(1, spdy::PROTOCOL_ERROR)); | |
2548 MockWrite writes[] = { | |
2549 CreateMockWrite(*syn, 0), | |
2550 CreateMockWrite(*rst, 2), | |
2551 }; | |
2552 | |
2553 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"}; | |
2554 scoped_ptr<spdy::SpdyFrame> | |
2555 reply(ConstructSpdyGetSynReply(kExtraHeaders, 1, 1)); | |
2556 MockRead reads[] = { | |
2557 CreateMockRead(*reply, 1), | |
2558 MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause | |
2559 }; | |
2560 | |
2561 HttpResponseInfo response; | |
2562 HttpResponseInfo response2; | |
2563 scoped_ptr<OrderedSocketData> data(new OrderedSocketData( | |
2564 reads, | |
2565 arraysize(reads), | |
2566 writes, | |
2567 arraysize(writes))); | |
2568 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
2569 BoundNetLog(), GetParam()); | |
2570 helper.RunToCompletion(data.get()); | |
2571 TransactionHelperResult out = helper.output(); | |
2572 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
2573 } | |
2574 | |
2575 // Detect response with upper case headers in a HEADERS frame and reset the | |
2576 // stream. | |
2577 TEST_P(SpdyNetworkTransactionTest, UpperCaseHeadersInHeadersFrame) { | |
2578 scoped_ptr<spdy::SpdyFrame> | |
2579 syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
2580 scoped_ptr<spdy::SpdyFrame> | |
2581 rst(ConstructSpdyRstStream(1, spdy::PROTOCOL_ERROR)); | |
2582 MockWrite writes[] = { | |
2583 CreateMockWrite(*syn, 0), | |
2584 CreateMockWrite(*rst, 2), | |
2585 }; | |
2586 | |
2587 static const char* const kInitialHeaders[] = { | |
2588 "status", "200 OK", | |
2589 "version", "HTTP/1.1" | |
2590 }; | |
2591 static const char* const kLateHeaders[] = { | |
2592 "X-UpperCase", "yes", | |
2593 }; | |
2594 scoped_ptr<spdy::SpdyFrame> | |
2595 stream1_reply(ConstructSpdyControlFrame(kInitialHeaders, | |
2596 arraysize(kInitialHeaders) / 2, | |
2597 false, | |
2598 1, | |
2599 LOWEST, | |
2600 spdy::SYN_REPLY, | |
2601 spdy::CONTROL_FLAG_NONE, | |
2602 NULL, | |
2603 0, | |
2604 0)); | |
2605 scoped_ptr<spdy::SpdyFrame> | |
2606 stream1_headers(ConstructSpdyControlFrame(kLateHeaders, | |
2607 arraysize(kLateHeaders) / 2, | |
2608 false, | |
2609 1, | |
2610 LOWEST, | |
2611 spdy::HEADERS, | |
2612 spdy::CONTROL_FLAG_NONE, | |
2613 NULL, | |
2614 0, | |
2615 0)); | |
2616 scoped_ptr<spdy::SpdyFrame> stream1_body(ConstructSpdyBodyFrame(1, true)); | |
2617 MockRead reads[] = { | |
2618 CreateMockRead(*stream1_reply), | |
2619 CreateMockRead(*stream1_headers), | |
2620 CreateMockRead(*stream1_body), | |
2621 MockRead(ASYNC, 0, 0) // EOF | |
2622 }; | |
2623 | |
2624 scoped_ptr<DelayedSocketData> data( | |
2625 new DelayedSocketData(1, reads, arraysize(reads), | |
2626 writes, arraysize(writes))); | |
2627 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
2628 BoundNetLog(), GetParam()); | |
2629 helper.RunToCompletion(data.get()); | |
2630 TransactionHelperResult out = helper.output(); | |
2631 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
2632 } | |
2633 | |
2634 // Detect push stream with upper case headers and reset the stream. | |
2635 TEST_P(SpdyNetworkTransactionTest, UpperCaseHeadersOnPush) { | |
2636 scoped_ptr<spdy::SpdyFrame> | |
2637 syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
2638 scoped_ptr<spdy::SpdyFrame> | |
2639 rst(ConstructSpdyRstStream(2, spdy::PROTOCOL_ERROR)); | |
2640 MockWrite writes[] = { | |
2641 CreateMockWrite(*syn, 0), | |
2642 CreateMockWrite(*rst, 2), | |
2643 }; | |
2644 | |
2645 scoped_ptr<spdy::SpdyFrame> | |
2646 reply(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2647 const char* const extra_headers[] = {"X-UpperCase", "yes"}; | |
2648 scoped_ptr<spdy::SpdyFrame> | |
2649 push(ConstructSpdyPush(extra_headers, 1, 2, 1)); | |
2650 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
2651 MockRead reads[] = { | |
2652 CreateMockRead(*reply, 1), | |
2653 CreateMockRead(*push, 1), | |
2654 CreateMockRead(*body, 1), | |
2655 MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause | |
2656 }; | |
2657 | |
2658 HttpResponseInfo response; | |
2659 HttpResponseInfo response2; | |
2660 scoped_ptr<OrderedSocketData> data(new OrderedSocketData( | |
2661 reads, | |
2662 arraysize(reads), | |
2663 writes, | |
2664 arraysize(writes))); | |
2665 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
2666 BoundNetLog(), GetParam()); | |
2667 helper.RunToCompletion(data.get()); | |
2668 TransactionHelperResult out = helper.output(); | |
2669 EXPECT_EQ(OK, out.rv); | |
2670 } | |
2671 | |
2672 // Send a spdy request to www.google.com. Get a pushed stream that redirects to | |
2673 // www.foo.com. | |
2674 TEST_P(SpdyNetworkTransactionTest, RedirectServerPush) { | |
2675 // These are headers which the net::URLRequest tacks on. | |
2676 const char* const kExtraHeaders[] = { | |
2677 "accept-encoding", | |
2678 "gzip,deflate", | |
2679 }; | |
2680 const SpdyHeaderInfo kSynStartHeader = MakeSpdyHeader(spdy::SYN_STREAM); | |
2681 const char* const kStandardGetHeaders[] = { | |
2682 "host", | |
2683 "www.google.com", | |
2684 "method", | |
2685 "GET", | |
2686 "scheme", | |
2687 "http", | |
2688 "url", | |
2689 "/", | |
2690 "user-agent", | |
2691 "", | |
2692 "version", | |
2693 "HTTP/1.1" | |
2694 }; | |
2695 | |
2696 // Setup writes/reads to www.google.com | |
2697 scoped_ptr<spdy::SpdyFrame> req( | |
2698 ConstructSpdyPacket(kSynStartHeader, | |
2699 kExtraHeaders, | |
2700 arraysize(kExtraHeaders) / 2, | |
2701 kStandardGetHeaders, | |
2702 arraysize(kStandardGetHeaders) / 2)); | |
2703 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2704 scoped_ptr<spdy::SpdyFrame> rep( | |
2705 ConstructSpdyPush(NULL, | |
2706 0, | |
2707 2, | |
2708 1, | |
2709 "http://www.google.com/foo.dat", | |
2710 "301 Moved Permanently", | |
2711 "http://www.foo.com/index.php")); | |
2712 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
2713 scoped_ptr<spdy::SpdyFrame> rst(ConstructSpdyRstStream(2, spdy::CANCEL)); | |
2714 MockWrite writes[] = { | |
2715 CreateMockWrite(*req, 1), | |
2716 CreateMockWrite(*rst, 6), | |
2717 }; | |
2718 MockRead reads[] = { | |
2719 CreateMockRead(*resp, 2), | |
2720 CreateMockRead(*rep, 3), | |
2721 CreateMockRead(*body, 4), | |
2722 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause | |
2723 MockRead(ASYNC, 0, 0, 7) // EOF | |
2724 }; | |
2725 | |
2726 // Setup writes/reads to www.foo.com | |
2727 const char* const kStandardGetHeaders2[] = { | |
2728 "host", | |
2729 "www.foo.com", | |
2730 "method", | |
2731 "GET", | |
2732 "scheme", | |
2733 "http", | |
2734 "url", | |
2735 "/index.php", | |
2736 "user-agent", | |
2737 "", | |
2738 "version", | |
2739 "HTTP/1.1" | |
2740 }; | |
2741 scoped_ptr<spdy::SpdyFrame> req2( | |
2742 ConstructSpdyPacket(kSynStartHeader, | |
2743 kExtraHeaders, | |
2744 arraysize(kExtraHeaders) / 2, | |
2745 kStandardGetHeaders2, | |
2746 arraysize(kStandardGetHeaders2) / 2)); | |
2747 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2748 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(1, true)); | |
2749 MockWrite writes2[] = { | |
2750 CreateMockWrite(*req2, 1), | |
2751 }; | |
2752 MockRead reads2[] = { | |
2753 CreateMockRead(*resp2, 2), | |
2754 CreateMockRead(*body2, 3), | |
2755 MockRead(ASYNC, 0, 0, 5) // EOF | |
2756 }; | |
2757 scoped_ptr<OrderedSocketData> data( | |
2758 new OrderedSocketData(reads, arraysize(reads), | |
2759 writes, arraysize(writes))); | |
2760 scoped_ptr<OrderedSocketData> data2( | |
2761 new OrderedSocketData(reads2, arraysize(reads2), | |
2762 writes2, arraysize(writes2))); | |
2763 | |
2764 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN | |
2765 HttpStreamFactory::set_force_spdy_over_ssl(false); | |
2766 HttpStreamFactory::set_force_spdy_always(true); | |
2767 TestDelegate d; | |
2768 TestDelegate d2; | |
2769 scoped_refptr<SpdyURLRequestContext> spdy_url_request_context( | |
2770 new SpdyURLRequestContext()); | |
2771 { | |
2772 net::URLRequest r(GURL("http://www.google.com/"), &d); | |
2773 r.set_context(spdy_url_request_context); | |
2774 spdy_url_request_context->socket_factory(). | |
2775 AddSocketDataProvider(data.get()); | |
2776 | |
2777 r.Start(); | |
2778 MessageLoop::current()->Run(); | |
2779 | |
2780 EXPECT_EQ(0, d.received_redirect_count()); | |
2781 std::string contents("hello!"); | |
2782 EXPECT_EQ(contents, d.data_received()); | |
2783 | |
2784 net::URLRequest r2(GURL("http://www.google.com/foo.dat"), &d2); | |
2785 r2.set_context(spdy_url_request_context); | |
2786 spdy_url_request_context->socket_factory(). | |
2787 AddSocketDataProvider(data2.get()); | |
2788 | |
2789 d2.set_quit_on_redirect(true); | |
2790 r2.Start(); | |
2791 MessageLoop::current()->Run(); | |
2792 EXPECT_EQ(1, d2.received_redirect_count()); | |
2793 | |
2794 r2.FollowDeferredRedirect(); | |
2795 MessageLoop::current()->Run(); | |
2796 EXPECT_EQ(1, d2.response_started_count()); | |
2797 EXPECT_FALSE(d2.received_data_before_response()); | |
2798 EXPECT_EQ(net::URLRequestStatus::SUCCESS, r2.status().status()); | |
2799 std::string contents2("hello!"); | |
2800 EXPECT_EQ(contents2, d2.data_received()); | |
2801 } | |
2802 data->CompleteRead(); | |
2803 data2->CompleteRead(); | |
2804 EXPECT_TRUE(data->at_read_eof()); | |
2805 EXPECT_TRUE(data->at_write_eof()); | |
2806 EXPECT_TRUE(data2->at_read_eof()); | |
2807 EXPECT_TRUE(data2->at_write_eof()); | |
2808 } | |
2809 | |
2810 TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) { | |
2811 static const unsigned char kPushBodyFrame[] = { | |
2812 0x00, 0x00, 0x00, 0x02, // header, ID | |
2813 0x01, 0x00, 0x00, 0x06, // FIN, length | |
2814 'p', 'u', 's', 'h', 'e', 'd' // "pushed" | |
2815 }; | |
2816 scoped_ptr<spdy::SpdyFrame> | |
2817 stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
2818 scoped_ptr<spdy::SpdyFrame> | |
2819 stream1_body(ConstructSpdyBodyFrame(1, true)); | |
2820 MockWrite writes[] = { | |
2821 CreateMockWrite(*stream1_syn, 1), | |
2822 }; | |
2823 | |
2824 scoped_ptr<spdy::SpdyFrame> | |
2825 stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2826 scoped_ptr<spdy::SpdyFrame> | |
2827 stream2_syn(ConstructSpdyPush(NULL, | |
2828 0, | |
2829 2, | |
2830 1, | |
2831 "http://www.google.com/foo.dat")); | |
2832 MockRead reads[] = { | |
2833 CreateMockRead(*stream1_reply, 2), | |
2834 CreateMockRead(*stream2_syn, 3), | |
2835 CreateMockRead(*stream1_body, 4, SYNCHRONOUS), | |
2836 MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), | |
2837 arraysize(kPushBodyFrame), 5), | |
2838 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause | |
2839 }; | |
2840 | |
2841 HttpResponseInfo response; | |
2842 HttpResponseInfo response2; | |
2843 std::string expected_push_result("pushed"); | |
2844 scoped_ptr<OrderedSocketData> data(new OrderedSocketData( | |
2845 reads, | |
2846 arraysize(reads), | |
2847 writes, | |
2848 arraysize(writes))); | |
2849 RunServerPushTest(data.get(), | |
2850 &response, | |
2851 &response2, | |
2852 expected_push_result); | |
2853 | |
2854 // Verify the SYN_REPLY. | |
2855 EXPECT_TRUE(response.headers != NULL); | |
2856 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
2857 | |
2858 // Verify the pushed stream. | |
2859 EXPECT_TRUE(response2.headers != NULL); | |
2860 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
2861 } | |
2862 | |
2863 TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) { | |
2864 static const unsigned char kPushBodyFrame[] = { | |
2865 0x00, 0x00, 0x00, 0x02, // header, ID | |
2866 0x01, 0x00, 0x00, 0x06, // FIN, length | |
2867 'p', 'u', 's', 'h', 'e', 'd' // "pushed" | |
2868 }; | |
2869 scoped_ptr<spdy::SpdyFrame> | |
2870 stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
2871 MockWrite writes[] = { | |
2872 CreateMockWrite(*stream1_syn, 1), | |
2873 }; | |
2874 | |
2875 scoped_ptr<spdy::SpdyFrame> | |
2876 stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2877 scoped_ptr<spdy::SpdyFrame> | |
2878 stream2_syn(ConstructSpdyPush(NULL, | |
2879 0, | |
2880 2, | |
2881 1, | |
2882 "http://www.google.com/foo.dat")); | |
2883 scoped_ptr<spdy::SpdyFrame> | |
2884 stream1_body(ConstructSpdyBodyFrame(1, true)); | |
2885 MockRead reads[] = { | |
2886 CreateMockRead(*stream1_reply, 2), | |
2887 CreateMockRead(*stream2_syn, 3), | |
2888 MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), | |
2889 arraysize(kPushBodyFrame), 5), | |
2890 CreateMockRead(*stream1_body, 4, SYNCHRONOUS), | |
2891 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause | |
2892 }; | |
2893 | |
2894 HttpResponseInfo response; | |
2895 HttpResponseInfo response2; | |
2896 std::string expected_push_result("pushed"); | |
2897 scoped_ptr<OrderedSocketData> data(new OrderedSocketData( | |
2898 reads, | |
2899 arraysize(reads), | |
2900 writes, | |
2901 arraysize(writes))); | |
2902 RunServerPushTest(data.get(), | |
2903 &response, | |
2904 &response2, | |
2905 expected_push_result); | |
2906 | |
2907 // Verify the SYN_REPLY. | |
2908 EXPECT_TRUE(response.headers != NULL); | |
2909 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
2910 | |
2911 // Verify the pushed stream. | |
2912 EXPECT_TRUE(response2.headers != NULL); | |
2913 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
2914 } | |
2915 | |
2916 TEST_P(SpdyNetworkTransactionTest, ServerPushServerAborted) { | |
2917 scoped_ptr<spdy::SpdyFrame> | |
2918 stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
2919 scoped_ptr<spdy::SpdyFrame> | |
2920 stream1_body(ConstructSpdyBodyFrame(1, true)); | |
2921 MockWrite writes[] = { | |
2922 CreateMockWrite(*stream1_syn, 1), | |
2923 }; | |
2924 | |
2925 scoped_ptr<spdy::SpdyFrame> | |
2926 stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2927 scoped_ptr<spdy::SpdyFrame> | |
2928 stream2_syn(ConstructSpdyPush(NULL, | |
2929 0, | |
2930 2, | |
2931 1, | |
2932 "http://www.google.com/foo.dat")); | |
2933 scoped_ptr<spdy::SpdyFrame> | |
2934 stream2_rst(ConstructSpdyRstStream(2, spdy::PROTOCOL_ERROR)); | |
2935 MockRead reads[] = { | |
2936 CreateMockRead(*stream1_reply, 2), | |
2937 CreateMockRead(*stream2_syn, 3), | |
2938 CreateMockRead(*stream2_rst, 4), | |
2939 CreateMockRead(*stream1_body, 5, SYNCHRONOUS), | |
2940 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause | |
2941 }; | |
2942 | |
2943 scoped_ptr<OrderedSocketData> data( | |
2944 new OrderedSocketData(reads, arraysize(reads), | |
2945 writes, arraysize(writes))); | |
2946 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
2947 BoundNetLog(), GetParam()); | |
2948 | |
2949 helper.RunPreTestSetup(); | |
2950 helper.AddData(data.get()); | |
2951 | |
2952 HttpNetworkTransaction* trans = helper.trans(); | |
2953 | |
2954 // Start the transaction with basic parameters. | |
2955 TestCompletionCallback callback; | |
2956 int rv = trans->Start( | |
2957 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
2958 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2959 rv = callback.WaitForResult(); | |
2960 EXPECT_EQ(OK, rv); | |
2961 | |
2962 // Verify that we consumed all test data. | |
2963 EXPECT_TRUE(data->at_read_eof()) << "Read count: " | |
2964 << data->read_count() | |
2965 << " Read index: " | |
2966 << data->read_index(); | |
2967 EXPECT_TRUE(data->at_write_eof()) << "Write count: " | |
2968 << data->write_count() | |
2969 << " Write index: " | |
2970 << data->write_index(); | |
2971 | |
2972 // Verify the SYN_REPLY. | |
2973 HttpResponseInfo response = *trans->GetResponseInfo(); | |
2974 EXPECT_TRUE(response.headers != NULL); | |
2975 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
2976 } | |
2977 | |
2978 TEST_P(SpdyNetworkTransactionTest, ServerPushDuplicate) { | |
2979 // Verify that we don't leak streams and that we properly send a reset | |
2980 // if the server pushes the same stream twice. | |
2981 static const unsigned char kPushBodyFrame[] = { | |
2982 0x00, 0x00, 0x00, 0x02, // header, ID | |
2983 0x01, 0x00, 0x00, 0x06, // FIN, length | |
2984 'p', 'u', 's', 'h', 'e', 'd' // "pushed" | |
2985 }; | |
2986 | |
2987 scoped_ptr<spdy::SpdyFrame> | |
2988 stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
2989 scoped_ptr<spdy::SpdyFrame> | |
2990 stream1_body(ConstructSpdyBodyFrame(1, true)); | |
2991 scoped_ptr<spdy::SpdyFrame> | |
2992 stream3_rst(ConstructSpdyRstStream(4, spdy::PROTOCOL_ERROR)); | |
2993 MockWrite writes[] = { | |
2994 CreateMockWrite(*stream1_syn, 1), | |
2995 CreateMockWrite(*stream3_rst, 5), | |
2996 }; | |
2997 | |
2998 scoped_ptr<spdy::SpdyFrame> | |
2999 stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3000 scoped_ptr<spdy::SpdyFrame> | |
3001 stream2_syn(ConstructSpdyPush(NULL, | |
3002 0, | |
3003 2, | |
3004 1, | |
3005 "http://www.google.com/foo.dat")); | |
3006 scoped_ptr<spdy::SpdyFrame> | |
3007 stream3_syn(ConstructSpdyPush(NULL, | |
3008 0, | |
3009 4, | |
3010 1, | |
3011 "http://www.google.com/foo.dat")); | |
3012 MockRead reads[] = { | |
3013 CreateMockRead(*stream1_reply, 2), | |
3014 CreateMockRead(*stream2_syn, 3), | |
3015 CreateMockRead(*stream3_syn, 4), | |
3016 CreateMockRead(*stream1_body, 6, SYNCHRONOUS), | |
3017 MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), | |
3018 arraysize(kPushBodyFrame), 7), | |
3019 MockRead(ASYNC, ERR_IO_PENDING, 8), // Force a pause | |
3020 }; | |
3021 | |
3022 HttpResponseInfo response; | |
3023 HttpResponseInfo response2; | |
3024 std::string expected_push_result("pushed"); | |
3025 scoped_ptr<OrderedSocketData> data(new OrderedSocketData( | |
3026 reads, | |
3027 arraysize(reads), | |
3028 writes, | |
3029 arraysize(writes))); | |
3030 RunServerPushTest(data.get(), | |
3031 &response, | |
3032 &response2, | |
3033 expected_push_result); | |
3034 | |
3035 // Verify the SYN_REPLY. | |
3036 EXPECT_TRUE(response.headers != NULL); | |
3037 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
3038 | |
3039 // Verify the pushed stream. | |
3040 EXPECT_TRUE(response2.headers != NULL); | |
3041 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
3042 } | |
3043 | |
3044 TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) { | |
3045 static const unsigned char kPushBodyFrame1[] = { | |
3046 0x00, 0x00, 0x00, 0x02, // header, ID | |
3047 0x01, 0x00, 0x00, 0x1F, // FIN, length | |
3048 'p', 'u', 's', 'h', 'e', 'd' // "pushed" | |
3049 }; | |
3050 static const char kPushBodyFrame2[] = " my darling"; | |
3051 static const char kPushBodyFrame3[] = " hello"; | |
3052 static const char kPushBodyFrame4[] = " my baby"; | |
3053 | |
3054 scoped_ptr<spdy::SpdyFrame> | |
3055 stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
3056 scoped_ptr<spdy::SpdyFrame> | |
3057 stream1_body(ConstructSpdyBodyFrame(1, true)); | |
3058 MockWrite writes[] = { | |
3059 CreateMockWrite(*stream1_syn, 1), | |
3060 }; | |
3061 | |
3062 scoped_ptr<spdy::SpdyFrame> | |
3063 stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3064 scoped_ptr<spdy::SpdyFrame> | |
3065 stream2_syn(ConstructSpdyPush(NULL, | |
3066 0, | |
3067 2, | |
3068 1, | |
3069 "http://www.google.com/foo.dat")); | |
3070 MockRead reads[] = { | |
3071 CreateMockRead(*stream1_reply, 2), | |
3072 CreateMockRead(*stream2_syn, 3), | |
3073 MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame1), | |
3074 arraysize(kPushBodyFrame1), 4), | |
3075 MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame2), | |
3076 arraysize(kPushBodyFrame2) - 1, 5), | |
3077 MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame3), | |
3078 arraysize(kPushBodyFrame3) - 1, 6), | |
3079 MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame4), | |
3080 arraysize(kPushBodyFrame4) - 1, 7), | |
3081 CreateMockRead(*stream1_body, 8, SYNCHRONOUS), | |
3082 MockRead(ASYNC, ERR_IO_PENDING, 9), // Force a pause | |
3083 }; | |
3084 | |
3085 HttpResponseInfo response; | |
3086 HttpResponseInfo response2; | |
3087 std::string expected_push_result("pushed my darling hello my baby"); | |
3088 scoped_ptr<OrderedSocketData> data(new OrderedSocketData( | |
3089 reads, | |
3090 arraysize(reads), | |
3091 writes, | |
3092 arraysize(writes))); | |
3093 RunServerPushTest(data.get(), | |
3094 &response, | |
3095 &response2, | |
3096 expected_push_result); | |
3097 | |
3098 // Verify the SYN_REPLY. | |
3099 EXPECT_TRUE(response.headers != NULL); | |
3100 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
3101 | |
3102 // Verify the pushed stream. | |
3103 EXPECT_TRUE(response2.headers != NULL); | |
3104 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
3105 } | |
3106 | |
3107 TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) { | |
3108 SpdySession::set_use_flow_control(SpdySession::kDisableFlowControl); | |
3109 | |
3110 static const unsigned char kPushBodyFrame1[] = { | |
3111 0x00, 0x00, 0x00, 0x02, // header, ID | |
3112 0x01, 0x00, 0x00, 0x1F, // FIN, length | |
3113 'p', 'u', 's', 'h', 'e', 'd' // "pushed" | |
3114 }; | |
3115 static const char kPushBodyFrame2[] = " my darling"; | |
3116 static const char kPushBodyFrame3[] = " hello"; | |
3117 static const char kPushBodyFrame4[] = " my baby"; | |
3118 | |
3119 scoped_ptr<spdy::SpdyFrame> | |
3120 stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
3121 scoped_ptr<spdy::SpdyFrame> | |
3122 stream1_body(ConstructSpdyBodyFrame(1, true)); | |
3123 MockWrite writes[] = { | |
3124 CreateMockWrite(*stream1_syn, 1), | |
3125 }; | |
3126 | |
3127 scoped_ptr<spdy::SpdyFrame> | |
3128 stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3129 scoped_ptr<spdy::SpdyFrame> | |
3130 stream2_syn(ConstructSpdyPush(NULL, | |
3131 0, | |
3132 2, | |
3133 1, | |
3134 "http://www.google.com/foo.dat")); | |
3135 MockRead reads[] = { | |
3136 CreateMockRead(*stream1_reply, 2), | |
3137 CreateMockRead(*stream2_syn, 3), | |
3138 MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame1), | |
3139 arraysize(kPushBodyFrame1), 4), | |
3140 MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame2), | |
3141 arraysize(kPushBodyFrame2) - 1, 5), | |
3142 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause | |
3143 MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame3), | |
3144 arraysize(kPushBodyFrame3) - 1, 7), | |
3145 MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame4), | |
3146 arraysize(kPushBodyFrame4) - 1, 8), | |
3147 CreateMockRead(*stream1_body.get(), 9, SYNCHRONOUS), | |
3148 MockRead(ASYNC, ERR_IO_PENDING, 10) // Force a pause. | |
3149 }; | |
3150 | |
3151 HttpResponseInfo response; | |
3152 HttpResponseInfo response2; | |
3153 std::string expected_push_result("pushed my darling hello my baby"); | |
3154 scoped_ptr<OrderedSocketData> data(new OrderedSocketData( | |
3155 reads, | |
3156 arraysize(reads), | |
3157 writes, | |
3158 arraysize(writes))); | |
3159 RunServerPushTest(data.get(), | |
3160 &response, | |
3161 &response2, | |
3162 expected_push_result); | |
3163 | |
3164 // Verify the SYN_REPLY. | |
3165 EXPECT_TRUE(response.headers != NULL); | |
3166 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
3167 | |
3168 // Verify the pushed stream. | |
3169 EXPECT_TRUE(response2.headers != NULL); | |
3170 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
3171 | |
3172 SpdySession::set_use_flow_control(SpdySession::kFlowControlBasedOnNPN); | |
3173 } | |
3174 | |
3175 TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) { | |
3176 scoped_ptr<spdy::SpdyFrame> | |
3177 stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
3178 scoped_ptr<spdy::SpdyFrame> | |
3179 stream1_body(ConstructSpdyBodyFrame(1, true)); | |
3180 scoped_ptr<spdy::SpdyFrame> | |
3181 stream2_rst(ConstructSpdyRstStream(2, spdy::INVALID_STREAM)); | |
3182 MockWrite writes[] = { | |
3183 CreateMockWrite(*stream1_syn, 1), | |
3184 CreateMockWrite(*stream2_rst, 4), | |
3185 }; | |
3186 | |
3187 scoped_ptr<spdy::SpdyFrame> | |
3188 stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3189 scoped_ptr<spdy::SpdyFrame> | |
3190 stream2_syn(ConstructSpdyPush(NULL, | |
3191 0, | |
3192 2, | |
3193 0, | |
3194 "http://www.google.com/foo.dat")); | |
3195 MockRead reads[] = { | |
3196 CreateMockRead(*stream1_reply, 2), | |
3197 CreateMockRead(*stream2_syn, 3), | |
3198 CreateMockRead(*stream1_body, 4), | |
3199 MockRead(ASYNC, ERR_IO_PENDING, 5) // Force a pause | |
3200 }; | |
3201 | |
3202 scoped_ptr<OrderedSocketData> data( | |
3203 new OrderedSocketData(reads, arraysize(reads), | |
3204 writes, arraysize(writes))); | |
3205 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
3206 BoundNetLog(), GetParam()); | |
3207 | |
3208 helper.RunPreTestSetup(); | |
3209 helper.AddData(data.get()); | |
3210 | |
3211 HttpNetworkTransaction* trans = helper.trans(); | |
3212 | |
3213 // Start the transaction with basic parameters. | |
3214 TestCompletionCallback callback; | |
3215 int rv = trans->Start( | |
3216 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
3217 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3218 rv = callback.WaitForResult(); | |
3219 EXPECT_EQ(OK, rv); | |
3220 | |
3221 // Verify that we consumed all test data. | |
3222 EXPECT_TRUE(data->at_read_eof()) << "Read count: " | |
3223 << data->read_count() | |
3224 << " Read index: " | |
3225 << data->read_index(); | |
3226 EXPECT_TRUE(data->at_write_eof()) << "Write count: " | |
3227 << data->write_count() | |
3228 << " Write index: " | |
3229 << data->write_index(); | |
3230 | |
3231 // Verify the SYN_REPLY. | |
3232 HttpResponseInfo response = *trans->GetResponseInfo(); | |
3233 EXPECT_TRUE(response.headers != NULL); | |
3234 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
3235 } | |
3236 | |
3237 TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) { | |
3238 scoped_ptr<spdy::SpdyFrame> | |
3239 stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
3240 scoped_ptr<spdy::SpdyFrame> | |
3241 stream1_body(ConstructSpdyBodyFrame(1, true)); | |
3242 scoped_ptr<spdy::SpdyFrame> | |
3243 stream2_rst(ConstructSpdyRstStream(2, spdy::INVALID_ASSOCIATED_STREAM)); | |
3244 MockWrite writes[] = { | |
3245 CreateMockWrite(*stream1_syn, 1), | |
3246 CreateMockWrite(*stream2_rst, 4), | |
3247 }; | |
3248 | |
3249 scoped_ptr<spdy::SpdyFrame> | |
3250 stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3251 scoped_ptr<spdy::SpdyFrame> | |
3252 stream2_syn(ConstructSpdyPush(NULL, | |
3253 0, | |
3254 2, | |
3255 9, | |
3256 "http://www.google.com/foo.dat")); | |
3257 MockRead reads[] = { | |
3258 CreateMockRead(*stream1_reply, 2), | |
3259 CreateMockRead(*stream2_syn, 3), | |
3260 CreateMockRead(*stream1_body, 4), | |
3261 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause | |
3262 }; | |
3263 | |
3264 scoped_ptr<OrderedSocketData> data( | |
3265 new OrderedSocketData(reads, arraysize(reads), | |
3266 writes, arraysize(writes))); | |
3267 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
3268 BoundNetLog(), GetParam()); | |
3269 | |
3270 helper.RunPreTestSetup(); | |
3271 helper.AddData(data.get()); | |
3272 | |
3273 HttpNetworkTransaction* trans = helper.trans(); | |
3274 | |
3275 // Start the transaction with basic parameters. | |
3276 TestCompletionCallback callback; | |
3277 int rv = trans->Start( | |
3278 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
3279 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3280 rv = callback.WaitForResult(); | |
3281 EXPECT_EQ(OK, rv); | |
3282 | |
3283 // Verify that we consumed all test data. | |
3284 EXPECT_TRUE(data->at_read_eof()) << "Read count: " | |
3285 << data->read_count() | |
3286 << " Read index: " | |
3287 << data->read_index(); | |
3288 EXPECT_TRUE(data->at_write_eof()) << "Write count: " | |
3289 << data->write_count() | |
3290 << " Write index: " | |
3291 << data->write_index(); | |
3292 | |
3293 // Verify the SYN_REPLY. | |
3294 HttpResponseInfo response = *trans->GetResponseInfo(); | |
3295 EXPECT_TRUE(response.headers != NULL); | |
3296 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
3297 } | |
3298 | |
3299 TEST_P(SpdyNetworkTransactionTest, ServerPushNoURL) { | |
3300 scoped_ptr<spdy::SpdyFrame> | |
3301 stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
3302 scoped_ptr<spdy::SpdyFrame> | |
3303 stream1_body(ConstructSpdyBodyFrame(1, true)); | |
3304 scoped_ptr<spdy::SpdyFrame> | |
3305 stream2_rst(ConstructSpdyRstStream(2, spdy::PROTOCOL_ERROR)); | |
3306 MockWrite writes[] = { | |
3307 CreateMockWrite(*stream1_syn, 1), | |
3308 CreateMockWrite(*stream2_rst, 4), | |
3309 }; | |
3310 | |
3311 scoped_ptr<spdy::SpdyFrame> | |
3312 stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3313 scoped_ptr<spdy::SpdyFrame> | |
3314 stream2_syn(ConstructSpdyPush(NULL, 0, 2, 1)); | |
3315 MockRead reads[] = { | |
3316 CreateMockRead(*stream1_reply, 2), | |
3317 CreateMockRead(*stream2_syn, 3), | |
3318 CreateMockRead(*stream1_body, 4), | |
3319 MockRead(ASYNC, ERR_IO_PENDING, 5) // Force a pause | |
3320 }; | |
3321 | |
3322 scoped_ptr<OrderedSocketData> data( | |
3323 new OrderedSocketData(reads, arraysize(reads), | |
3324 writes, arraysize(writes))); | |
3325 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
3326 BoundNetLog(), GetParam()); | |
3327 | |
3328 helper.RunPreTestSetup(); | |
3329 helper.AddData(data.get()); | |
3330 | |
3331 HttpNetworkTransaction* trans = helper.trans(); | |
3332 | |
3333 // Start the transaction with basic parameters. | |
3334 TestCompletionCallback callback; | |
3335 int rv = trans->Start( | |
3336 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
3337 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3338 rv = callback.WaitForResult(); | |
3339 EXPECT_EQ(OK, rv); | |
3340 // Verify that we consumed all test data. | |
3341 EXPECT_TRUE(data->at_read_eof()) << "Read count: " | |
3342 << data->read_count() | |
3343 << " Read index: " | |
3344 << data->read_index(); | |
3345 EXPECT_TRUE(data->at_write_eof()) << "Write count: " | |
3346 << data->write_count() | |
3347 << " Write index: " | |
3348 << data->write_index(); | |
3349 | |
3350 // Verify the SYN_REPLY. | |
3351 HttpResponseInfo response = *trans->GetResponseInfo(); | |
3352 EXPECT_TRUE(response.headers != NULL); | |
3353 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
3354 } | |
3355 | |
3356 // Verify that various SynReply headers parse correctly through the | |
3357 // HTTP layer. | |
3358 TEST_P(SpdyNetworkTransactionTest, SynReplyHeaders) { | |
3359 struct SynReplyHeadersTests { | |
3360 int num_headers; | |
3361 const char* extra_headers[5]; | |
3362 const char* expected_headers; | |
3363 } test_cases[] = { | |
3364 // This uses a multi-valued cookie header. | |
3365 { 2, | |
3366 { "cookie", "val1", | |
3367 "cookie", "val2", // will get appended separated by NULL | |
3368 NULL | |
3369 }, | |
3370 "cookie: val1\n" | |
3371 "cookie: val2\n" | |
3372 "hello: bye\n" | |
3373 "status: 200\n" | |
3374 "version: HTTP/1.1\n" | |
3375 }, | |
3376 // This is the minimalist set of headers. | |
3377 { 0, | |
3378 { NULL }, | |
3379 "hello: bye\n" | |
3380 "status: 200\n" | |
3381 "version: HTTP/1.1\n" | |
3382 }, | |
3383 // Headers with a comma separated list. | |
3384 { 1, | |
3385 { "cookie", "val1,val2", | |
3386 NULL | |
3387 }, | |
3388 "cookie: val1,val2\n" | |
3389 "hello: bye\n" | |
3390 "status: 200\n" | |
3391 "version: HTTP/1.1\n" | |
3392 } | |
3393 }; | |
3394 | |
3395 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { | |
3396 scoped_ptr<spdy::SpdyFrame> req( | |
3397 ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
3398 MockWrite writes[] = { CreateMockWrite(*req) }; | |
3399 | |
3400 scoped_ptr<spdy::SpdyFrame> resp( | |
3401 ConstructSpdyGetSynReply(test_cases[i].extra_headers, | |
3402 test_cases[i].num_headers, | |
3403 1)); | |
3404 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
3405 MockRead reads[] = { | |
3406 CreateMockRead(*resp), | |
3407 CreateMockRead(*body), | |
3408 MockRead(ASYNC, 0, 0) // EOF | |
3409 }; | |
3410 | |
3411 scoped_ptr<DelayedSocketData> data( | |
3412 new DelayedSocketData(1, reads, arraysize(reads), | |
3413 writes, arraysize(writes))); | |
3414 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
3415 BoundNetLog(), GetParam()); | |
3416 helper.RunToCompletion(data.get()); | |
3417 TransactionHelperResult out = helper.output(); | |
3418 | |
3419 EXPECT_EQ(OK, out.rv); | |
3420 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
3421 EXPECT_EQ("hello!", out.response_data); | |
3422 | |
3423 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers; | |
3424 EXPECT_TRUE(headers.get() != NULL); | |
3425 void* iter = NULL; | |
3426 std::string name, value, lines; | |
3427 while (headers->EnumerateHeaderLines(&iter, &name, &value)) { | |
3428 lines.append(name); | |
3429 lines.append(": "); | |
3430 lines.append(value); | |
3431 lines.append("\n"); | |
3432 } | |
3433 EXPECT_EQ(std::string(test_cases[i].expected_headers), lines); | |
3434 } | |
3435 } | |
3436 | |
3437 // Verify that various SynReply headers parse vary fields correctly | |
3438 // through the HTTP layer, and the response matches the request. | |
3439 TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) { | |
3440 static const SpdyHeaderInfo syn_reply_info = { | |
3441 spdy::SYN_REPLY, // Syn Reply | |
3442 1, // Stream ID | |
3443 0, // Associated Stream ID | |
3444 net::ConvertRequestPriorityToSpdyPriority(LOWEST), | |
3445 // Priority | |
3446 spdy::CONTROL_FLAG_NONE, // Control Flags | |
3447 false, // Compressed | |
3448 spdy::INVALID, // Status | |
3449 NULL, // Data | |
3450 0, // Data Length | |
3451 spdy::DATA_FLAG_NONE // Data Flags | |
3452 }; | |
3453 // Modify the following data to change/add test cases: | |
3454 struct SynReplyTests { | |
3455 const SpdyHeaderInfo* syn_reply; | |
3456 bool vary_matches; | |
3457 int num_headers[2]; | |
3458 const char* extra_headers[2][16]; | |
3459 } test_cases[] = { | |
3460 // Test the case of a multi-valued cookie. When the value is delimited | |
3461 // with NUL characters, it needs to be unfolded into multiple headers. | |
3462 { | |
3463 &syn_reply_info, | |
3464 true, | |
3465 { 1, 4 }, | |
3466 { { "cookie", "val1,val2", | |
3467 NULL | |
3468 }, | |
3469 { "vary", "cookie", | |
3470 "status", "200", | |
3471 "url", "/index.php", | |
3472 "version", "HTTP/1.1", | |
3473 NULL | |
3474 } | |
3475 } | |
3476 }, { // Multiple vary fields. | |
3477 &syn_reply_info, | |
3478 true, | |
3479 { 2, 5 }, | |
3480 { { "friend", "barney", | |
3481 "enemy", "snaggletooth", | |
3482 NULL | |
3483 }, | |
3484 { "vary", "friend", | |
3485 "vary", "enemy", | |
3486 "status", "200", | |
3487 "url", "/index.php", | |
3488 "version", "HTTP/1.1", | |
3489 NULL | |
3490 } | |
3491 } | |
3492 }, { // Test a '*' vary field. | |
3493 &syn_reply_info, | |
3494 false, | |
3495 { 1, 4 }, | |
3496 { { "cookie", "val1,val2", | |
3497 NULL | |
3498 }, | |
3499 { "vary", "*", | |
3500 "status", "200", | |
3501 "url", "/index.php", | |
3502 "version", "HTTP/1.1", | |
3503 NULL | |
3504 } | |
3505 } | |
3506 }, { // Multiple comma-separated vary fields. | |
3507 &syn_reply_info, | |
3508 true, | |
3509 { 2, 4 }, | |
3510 { { "friend", "barney", | |
3511 "enemy", "snaggletooth", | |
3512 NULL | |
3513 }, | |
3514 { "vary", "friend,enemy", | |
3515 "status", "200", | |
3516 "url", "/index.php", | |
3517 "version", "HTTP/1.1", | |
3518 NULL | |
3519 } | |
3520 } | |
3521 } | |
3522 }; | |
3523 | |
3524 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { | |
3525 // Construct the request. | |
3526 scoped_ptr<spdy::SpdyFrame> frame_req( | |
3527 ConstructSpdyGet(test_cases[i].extra_headers[0], | |
3528 test_cases[i].num_headers[0], | |
3529 false, 1, LOWEST)); | |
3530 | |
3531 MockWrite writes[] = { | |
3532 CreateMockWrite(*frame_req), | |
3533 }; | |
3534 | |
3535 // Construct the reply. | |
3536 scoped_ptr<spdy::SpdyFrame> frame_reply( | |
3537 ConstructSpdyPacket(*test_cases[i].syn_reply, | |
3538 test_cases[i].extra_headers[1], | |
3539 test_cases[i].num_headers[1], | |
3540 NULL, | |
3541 0)); | |
3542 | |
3543 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
3544 MockRead reads[] = { | |
3545 CreateMockRead(*frame_reply), | |
3546 CreateMockRead(*body), | |
3547 MockRead(ASYNC, 0, 0) // EOF | |
3548 }; | |
3549 | |
3550 // Attach the headers to the request. | |
3551 int header_count = test_cases[i].num_headers[0]; | |
3552 | |
3553 HttpRequestInfo request = CreateGetRequest(); | |
3554 for (int ct = 0; ct < header_count; ct++) { | |
3555 const char* header_key = test_cases[i].extra_headers[0][ct * 2]; | |
3556 const char* header_value = test_cases[i].extra_headers[0][ct * 2 + 1]; | |
3557 request.extra_headers.SetHeader(header_key, header_value); | |
3558 } | |
3559 | |
3560 scoped_ptr<DelayedSocketData> data( | |
3561 new DelayedSocketData(1, reads, arraysize(reads), | |
3562 writes, arraysize(writes))); | |
3563 NormalSpdyTransactionHelper helper(request, | |
3564 BoundNetLog(), GetParam()); | |
3565 helper.RunToCompletion(data.get()); | |
3566 TransactionHelperResult out = helper.output(); | |
3567 | |
3568 EXPECT_EQ(OK, out.rv) << i; | |
3569 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line) << i; | |
3570 EXPECT_EQ("hello!", out.response_data) << i; | |
3571 | |
3572 // Test the response information. | |
3573 EXPECT_TRUE(out.response_info.response_time > | |
3574 out.response_info.request_time) << i; | |
3575 base::TimeDelta test_delay = out.response_info.response_time - | |
3576 out.response_info.request_time; | |
3577 base::TimeDelta min_expected_delay; | |
3578 min_expected_delay.FromMilliseconds(10); | |
3579 EXPECT_GT(test_delay.InMillisecondsF(), | |
3580 min_expected_delay.InMillisecondsF()) << i; | |
3581 EXPECT_EQ(out.response_info.vary_data.is_valid(), | |
3582 test_cases[i].vary_matches) << i; | |
3583 | |
3584 // Check the headers. | |
3585 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers; | |
3586 ASSERT_TRUE(headers.get() != NULL) << i; | |
3587 void* iter = NULL; | |
3588 std::string name, value, lines; | |
3589 while (headers->EnumerateHeaderLines(&iter, &name, &value)) { | |
3590 lines.append(name); | |
3591 lines.append(": "); | |
3592 lines.append(value); | |
3593 lines.append("\n"); | |
3594 } | |
3595 | |
3596 // Construct the expected header reply string. | |
3597 char reply_buffer[256] = ""; | |
3598 ConstructSpdyReplyString(test_cases[i].extra_headers[1], | |
3599 test_cases[i].num_headers[1], | |
3600 reply_buffer, | |
3601 256); | |
3602 | |
3603 EXPECT_EQ(std::string(reply_buffer), lines) << i; | |
3604 } | |
3605 } | |
3606 | |
3607 // Verify that we don't crash on invalid SynReply responses. | |
3608 TEST_P(SpdyNetworkTransactionTest, InvalidSynReply) { | |
3609 const SpdyHeaderInfo kSynStartHeader = { | |
3610 spdy::SYN_REPLY, // Kind = SynReply | |
3611 1, // Stream ID | |
3612 0, // Associated stream ID | |
3613 net::ConvertRequestPriorityToSpdyPriority(LOWEST), | |
3614 // Priority | |
3615 spdy::CONTROL_FLAG_NONE, // Control Flags | |
3616 false, // Compressed | |
3617 spdy::INVALID, // Status | |
3618 NULL, // Data | |
3619 0, // Length | |
3620 spdy::DATA_FLAG_NONE // Data Flags | |
3621 }; | |
3622 | |
3623 struct InvalidSynReplyTests { | |
3624 int num_headers; | |
3625 const char* headers[10]; | |
3626 } test_cases[] = { | |
3627 // SYN_REPLY missing status header | |
3628 { 4, | |
3629 { "cookie", "val1", | |
3630 "cookie", "val2", | |
3631 "url", "/index.php", | |
3632 "version", "HTTP/1.1", | |
3633 NULL | |
3634 }, | |
3635 }, | |
3636 // SYN_REPLY missing version header | |
3637 { 2, | |
3638 { "status", "200", | |
3639 "url", "/index.php", | |
3640 NULL | |
3641 }, | |
3642 }, | |
3643 // SYN_REPLY with no headers | |
3644 { 0, { NULL }, }, | |
3645 }; | |
3646 | |
3647 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { | |
3648 scoped_ptr<spdy::SpdyFrame> req( | |
3649 ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
3650 MockWrite writes[] = { | |
3651 CreateMockWrite(*req), | |
3652 }; | |
3653 | |
3654 scoped_ptr<spdy::SpdyFrame> resp( | |
3655 ConstructSpdyPacket(kSynStartHeader, | |
3656 NULL, 0, | |
3657 test_cases[i].headers, | |
3658 test_cases[i].num_headers)); | |
3659 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
3660 MockRead reads[] = { | |
3661 CreateMockRead(*resp), | |
3662 CreateMockRead(*body), | |
3663 MockRead(ASYNC, 0, 0) // EOF | |
3664 }; | |
3665 | |
3666 scoped_ptr<DelayedSocketData> data( | |
3667 new DelayedSocketData(1, reads, arraysize(reads), | |
3668 writes, arraysize(writes))); | |
3669 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
3670 BoundNetLog(), GetParam()); | |
3671 helper.RunToCompletion(data.get()); | |
3672 TransactionHelperResult out = helper.output(); | |
3673 EXPECT_EQ(ERR_INCOMPLETE_SPDY_HEADERS, out.rv); | |
3674 } | |
3675 } | |
3676 | |
3677 // Verify that we don't crash on some corrupt frames. | |
3678 TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionError) { | |
3679 // This is the length field that's too short. | |
3680 scoped_ptr<spdy::SpdyFrame> syn_reply_wrong_length( | |
3681 ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3682 syn_reply_wrong_length->set_length(syn_reply_wrong_length->length() - 4); | |
3683 | |
3684 struct SynReplyTests { | |
3685 const spdy::SpdyFrame* syn_reply; | |
3686 } test_cases[] = { | |
3687 { syn_reply_wrong_length.get(), }, | |
3688 }; | |
3689 | |
3690 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { | |
3691 scoped_ptr<spdy::SpdyFrame> req( | |
3692 ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
3693 MockWrite writes[] = { | |
3694 CreateMockWrite(*req), | |
3695 MockWrite(ASYNC, 0, 0) // EOF | |
3696 }; | |
3697 | |
3698 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
3699 MockRead reads[] = { | |
3700 CreateMockRead(*test_cases[i].syn_reply), | |
3701 CreateMockRead(*body), | |
3702 MockRead(ASYNC, 0, 0) // EOF | |
3703 }; | |
3704 | |
3705 scoped_ptr<DelayedSocketData> data( | |
3706 new DelayedSocketData(1, reads, arraysize(reads), | |
3707 writes, arraysize(writes))); | |
3708 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
3709 BoundNetLog(), GetParam()); | |
3710 helper.RunToCompletion(data.get()); | |
3711 TransactionHelperResult out = helper.output(); | |
3712 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
3713 } | |
3714 } | |
3715 | |
3716 // Test that we shutdown correctly on write errors. | |
3717 TEST_P(SpdyNetworkTransactionTest, WriteError) { | |
3718 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
3719 MockWrite writes[] = { | |
3720 // We'll write 10 bytes successfully | |
3721 MockWrite(ASYNC, req->data(), 10), | |
3722 // Followed by ERROR! | |
3723 MockWrite(ASYNC, ERR_FAILED), | |
3724 }; | |
3725 | |
3726 scoped_ptr<DelayedSocketData> data( | |
3727 new DelayedSocketData(2, NULL, 0, | |
3728 writes, arraysize(writes))); | |
3729 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
3730 BoundNetLog(), GetParam()); | |
3731 helper.RunToCompletion(data.get()); | |
3732 TransactionHelperResult out = helper.output(); | |
3733 EXPECT_EQ(ERR_FAILED, out.rv); | |
3734 data->Reset(); | |
3735 } | |
3736 | |
3737 // Test that partial writes work. | |
3738 TEST_P(SpdyNetworkTransactionTest, PartialWrite) { | |
3739 // Chop the SYN_STREAM frame into 5 chunks. | |
3740 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
3741 const int kChunks = 5; | |
3742 scoped_array<MockWrite> writes(ChopWriteFrame(*req.get(), kChunks)); | |
3743 | |
3744 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3745 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
3746 MockRead reads[] = { | |
3747 CreateMockRead(*resp), | |
3748 CreateMockRead(*body), | |
3749 MockRead(ASYNC, 0, 0) // EOF | |
3750 }; | |
3751 | |
3752 scoped_ptr<DelayedSocketData> data( | |
3753 new DelayedSocketData(kChunks, reads, arraysize(reads), | |
3754 writes.get(), kChunks)); | |
3755 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
3756 BoundNetLog(), GetParam()); | |
3757 helper.RunToCompletion(data.get()); | |
3758 TransactionHelperResult out = helper.output(); | |
3759 EXPECT_EQ(OK, out.rv); | |
3760 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
3761 EXPECT_EQ("hello!", out.response_data); | |
3762 } | |
3763 | |
3764 // In this test, we enable compression, but get a uncompressed SynReply from | |
3765 // the server. Verify that teardown is all clean. | |
3766 TEST_P(SpdyNetworkTransactionTest, DecompressFailureOnSynReply) { | |
3767 // For this test, we turn on the normal compression. | |
3768 EnableCompression(true); | |
3769 | |
3770 scoped_ptr<spdy::SpdyFrame> compressed( | |
3771 ConstructSpdyGet(NULL, 0, true, 1, LOWEST)); | |
3772 scoped_ptr<spdy::SpdyFrame> rst( | |
3773 ConstructSpdyRstStream(1, spdy::PROTOCOL_ERROR)); | |
3774 MockWrite writes[] = { | |
3775 CreateMockWrite(*compressed), | |
3776 }; | |
3777 | |
3778 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3779 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
3780 MockRead reads[] = { | |
3781 CreateMockRead(*resp), | |
3782 }; | |
3783 | |
3784 scoped_ptr<DelayedSocketData> data( | |
3785 new DelayedSocketData(1, reads, arraysize(reads), | |
3786 writes, arraysize(writes))); | |
3787 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
3788 BoundNetLog(), GetParam()); | |
3789 helper.RunToCompletion(data.get()); | |
3790 TransactionHelperResult out = helper.output(); | |
3791 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
3792 data->Reset(); | |
3793 | |
3794 EnableCompression(false); | |
3795 } | |
3796 | |
3797 // Test that the NetLog contains good data for a simple GET request. | |
3798 TEST_P(SpdyNetworkTransactionTest, NetLog) { | |
3799 static const char* const kExtraHeaders[] = { | |
3800 "user-agent", "Chrome", | |
3801 }; | |
3802 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(kExtraHeaders, 1, false, 1, | |
3803 LOWEST)); | |
3804 MockWrite writes[] = { CreateMockWrite(*req) }; | |
3805 | |
3806 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3807 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
3808 MockRead reads[] = { | |
3809 CreateMockRead(*resp), | |
3810 CreateMockRead(*body), | |
3811 MockRead(ASYNC, 0, 0) // EOF | |
3812 }; | |
3813 | |
3814 net::CapturingBoundNetLog log(net::CapturingNetLog::kUnbounded); | |
3815 | |
3816 scoped_ptr<DelayedSocketData> data( | |
3817 new DelayedSocketData(1, reads, arraysize(reads), | |
3818 writes, arraysize(writes))); | |
3819 NormalSpdyTransactionHelper helper(CreateGetRequestWithUserAgent(), | |
3820 log.bound(), GetParam()); | |
3821 helper.RunToCompletion(data.get()); | |
3822 TransactionHelperResult out = helper.output(); | |
3823 EXPECT_EQ(OK, out.rv); | |
3824 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
3825 EXPECT_EQ("hello!", out.response_data); | |
3826 | |
3827 // Check that the NetLog was filled reasonably. | |
3828 // This test is intentionally non-specific about the exact ordering of the | |
3829 // log; instead we just check to make sure that certain events exist, and that | |
3830 // they are in the right order. | |
3831 net::CapturingNetLog::EntryList entries; | |
3832 log.GetEntries(&entries); | |
3833 | |
3834 EXPECT_LT(0u, entries.size()); | |
3835 int pos = 0; | |
3836 pos = net::ExpectLogContainsSomewhere(entries, 0, | |
3837 net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, | |
3838 net::NetLog::PHASE_BEGIN); | |
3839 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, | |
3840 net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, | |
3841 net::NetLog::PHASE_END); | |
3842 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, | |
3843 net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, | |
3844 net::NetLog::PHASE_BEGIN); | |
3845 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, | |
3846 net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, | |
3847 net::NetLog::PHASE_END); | |
3848 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, | |
3849 net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, | |
3850 net::NetLog::PHASE_BEGIN); | |
3851 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, | |
3852 net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, | |
3853 net::NetLog::PHASE_END); | |
3854 | |
3855 // Check that we logged all the headers correctly | |
3856 pos = net::ExpectLogContainsSomewhere( | |
3857 entries, 0, | |
3858 net::NetLog::TYPE_SPDY_SESSION_SYN_STREAM, | |
3859 net::NetLog::PHASE_NONE); | |
3860 CapturingNetLog::Entry entry = entries[pos]; | |
3861 NetLogSpdySynParameter* request_params = | |
3862 static_cast<NetLogSpdySynParameter*>(entry.extra_parameters.get()); | |
3863 spdy::SpdyHeaderBlock* headers = | |
3864 request_params->GetHeaders().get(); | |
3865 | |
3866 spdy::SpdyHeaderBlock expected; | |
3867 expected["host"] = "www.google.com"; | |
3868 expected["url"] = "/"; | |
3869 expected["scheme"] = "http"; | |
3870 expected["version"] = "HTTP/1.1"; | |
3871 expected["method"] = "GET"; | |
3872 expected["user-agent"] = "Chrome"; | |
3873 EXPECT_EQ(expected.size(), headers->size()); | |
3874 spdy::SpdyHeaderBlock::const_iterator end = expected.end(); | |
3875 for (spdy::SpdyHeaderBlock::const_iterator it = expected.begin(); | |
3876 it != end; | |
3877 ++it) { | |
3878 EXPECT_EQ(it->second, (*headers)[it->first]); | |
3879 } | |
3880 } | |
3881 | |
3882 // Since we buffer the IO from the stream to the renderer, this test verifies | |
3883 // that when we read out the maximum amount of data (e.g. we received 50 bytes | |
3884 // on the network, but issued a Read for only 5 of those bytes) that the data | |
3885 // flow still works correctly. | |
3886 TEST_P(SpdyNetworkTransactionTest, BufferFull) { | |
3887 SpdySession::set_use_flow_control(SpdySession::kDisableFlowControl); | |
3888 | |
3889 spdy::SpdyFramer framer; | |
3890 | |
3891 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
3892 MockWrite writes[] = { CreateMockWrite(*req) }; | |
3893 | |
3894 // 2 data frames in a single read. | |
3895 scoped_ptr<spdy::SpdyFrame> data_frame_1( | |
3896 framer.CreateDataFrame(1, "goodby", 6, spdy::DATA_FLAG_NONE)); | |
3897 scoped_ptr<spdy::SpdyFrame> data_frame_2( | |
3898 framer.CreateDataFrame(1, "e worl", 6, spdy::DATA_FLAG_NONE)); | |
3899 const spdy::SpdyFrame* data_frames[2] = { | |
3900 data_frame_1.get(), | |
3901 data_frame_2.get(), | |
3902 }; | |
3903 char combined_data_frames[100]; | |
3904 int combined_data_frames_len = | |
3905 CombineFrames(data_frames, arraysize(data_frames), | |
3906 combined_data_frames, arraysize(combined_data_frames)); | |
3907 scoped_ptr<spdy::SpdyFrame> last_frame( | |
3908 framer.CreateDataFrame(1, "d", 1, spdy::DATA_FLAG_FIN)); | |
3909 | |
3910 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3911 MockRead reads[] = { | |
3912 CreateMockRead(*resp), | |
3913 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause | |
3914 MockRead(ASYNC, combined_data_frames, combined_data_frames_len), | |
3915 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause | |
3916 CreateMockRead(*last_frame), | |
3917 MockRead(ASYNC, 0, 0) // EOF | |
3918 }; | |
3919 | |
3920 scoped_ptr<DelayedSocketData> data( | |
3921 new DelayedSocketData(1, reads, arraysize(reads), | |
3922 writes, arraysize(writes))); | |
3923 | |
3924 | |
3925 TestCompletionCallback callback; | |
3926 | |
3927 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
3928 BoundNetLog(), GetParam()); | |
3929 helper.RunPreTestSetup(); | |
3930 helper.AddData(data.get()); | |
3931 HttpNetworkTransaction* trans = helper.trans(); | |
3932 int rv = trans->Start( | |
3933 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
3934 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3935 | |
3936 TransactionHelperResult out = helper.output(); | |
3937 out.rv = callback.WaitForResult(); | |
3938 EXPECT_EQ(out.rv, OK); | |
3939 | |
3940 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
3941 EXPECT_TRUE(response->headers != NULL); | |
3942 EXPECT_TRUE(response->was_fetched_via_spdy); | |
3943 out.status_line = response->headers->GetStatusLine(); | |
3944 out.response_info = *response; // Make a copy so we can verify. | |
3945 | |
3946 // Read Data | |
3947 TestCompletionCallback read_callback; | |
3948 | |
3949 std::string content; | |
3950 do { | |
3951 // Read small chunks at a time. | |
3952 const int kSmallReadSize = 3; | |
3953 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); | |
3954 rv = trans->Read(buf, kSmallReadSize, read_callback.callback()); | |
3955 if (rv == net::ERR_IO_PENDING) { | |
3956 data->CompleteRead(); | |
3957 rv = read_callback.WaitForResult(); | |
3958 } | |
3959 if (rv > 0) { | |
3960 content.append(buf->data(), rv); | |
3961 } else if (rv < 0) { | |
3962 NOTREACHED(); | |
3963 } | |
3964 } while (rv > 0); | |
3965 | |
3966 out.response_data.swap(content); | |
3967 | |
3968 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the | |
3969 // MockClientSocketFactory) are still alive. | |
3970 MessageLoop::current()->RunAllPending(); | |
3971 | |
3972 // Verify that we consumed all test data. | |
3973 helper.VerifyDataConsumed(); | |
3974 | |
3975 EXPECT_EQ(OK, out.rv); | |
3976 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
3977 EXPECT_EQ("goodbye world", out.response_data); | |
3978 | |
3979 SpdySession::set_use_flow_control(SpdySession::kFlowControlBasedOnNPN); | |
3980 } | |
3981 | |
3982 // Verify that basic buffering works; when multiple data frames arrive | |
3983 // at the same time, ensure that we don't notify a read completion for | |
3984 // each data frame individually. | |
3985 TEST_P(SpdyNetworkTransactionTest, Buffering) { | |
3986 SpdySession::set_use_flow_control(SpdySession::kDisableFlowControl); | |
3987 | |
3988 spdy::SpdyFramer framer; | |
3989 | |
3990 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
3991 MockWrite writes[] = { CreateMockWrite(*req) }; | |
3992 | |
3993 // 4 data frames in a single read. | |
3994 scoped_ptr<spdy::SpdyFrame> data_frame( | |
3995 framer.CreateDataFrame(1, "message", 7, spdy::DATA_FLAG_NONE)); | |
3996 scoped_ptr<spdy::SpdyFrame> data_frame_fin( | |
3997 framer.CreateDataFrame(1, "message", 7, spdy::DATA_FLAG_FIN)); | |
3998 const spdy::SpdyFrame* data_frames[4] = { | |
3999 data_frame.get(), | |
4000 data_frame.get(), | |
4001 data_frame.get(), | |
4002 data_frame_fin.get() | |
4003 }; | |
4004 char combined_data_frames[100]; | |
4005 int combined_data_frames_len = | |
4006 CombineFrames(data_frames, arraysize(data_frames), | |
4007 combined_data_frames, arraysize(combined_data_frames)); | |
4008 | |
4009 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4010 MockRead reads[] = { | |
4011 CreateMockRead(*resp), | |
4012 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause | |
4013 MockRead(ASYNC, combined_data_frames, combined_data_frames_len), | |
4014 MockRead(ASYNC, 0, 0) // EOF | |
4015 }; | |
4016 | |
4017 scoped_ptr<DelayedSocketData> data( | |
4018 new DelayedSocketData(1, reads, arraysize(reads), | |
4019 writes, arraysize(writes))); | |
4020 | |
4021 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
4022 BoundNetLog(), GetParam()); | |
4023 helper.RunPreTestSetup(); | |
4024 helper.AddData(data.get()); | |
4025 HttpNetworkTransaction* trans = helper.trans(); | |
4026 | |
4027 TestCompletionCallback callback; | |
4028 int rv = trans->Start( | |
4029 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4030 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4031 | |
4032 TransactionHelperResult out = helper.output(); | |
4033 out.rv = callback.WaitForResult(); | |
4034 EXPECT_EQ(out.rv, OK); | |
4035 | |
4036 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4037 EXPECT_TRUE(response->headers != NULL); | |
4038 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4039 out.status_line = response->headers->GetStatusLine(); | |
4040 out.response_info = *response; // Make a copy so we can verify. | |
4041 | |
4042 // Read Data | |
4043 TestCompletionCallback read_callback; | |
4044 | |
4045 std::string content; | |
4046 int reads_completed = 0; | |
4047 do { | |
4048 // Read small chunks at a time. | |
4049 const int kSmallReadSize = 14; | |
4050 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); | |
4051 rv = trans->Read(buf, kSmallReadSize, read_callback.callback()); | |
4052 if (rv == net::ERR_IO_PENDING) { | |
4053 data->CompleteRead(); | |
4054 rv = read_callback.WaitForResult(); | |
4055 } | |
4056 if (rv > 0) { | |
4057 EXPECT_EQ(kSmallReadSize, rv); | |
4058 content.append(buf->data(), rv); | |
4059 } else if (rv < 0) { | |
4060 FAIL() << "Unexpected read error: " << rv; | |
4061 } | |
4062 reads_completed++; | |
4063 } while (rv > 0); | |
4064 | |
4065 EXPECT_EQ(3, reads_completed); // Reads are: 14 bytes, 14 bytes, 0 bytes. | |
4066 | |
4067 out.response_data.swap(content); | |
4068 | |
4069 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the | |
4070 // MockClientSocketFactory) are still alive. | |
4071 MessageLoop::current()->RunAllPending(); | |
4072 | |
4073 // Verify that we consumed all test data. | |
4074 helper.VerifyDataConsumed(); | |
4075 | |
4076 EXPECT_EQ(OK, out.rv); | |
4077 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
4078 EXPECT_EQ("messagemessagemessagemessage", out.response_data); | |
4079 | |
4080 SpdySession::set_use_flow_control(SpdySession::kFlowControlBasedOnNPN); | |
4081 } | |
4082 | |
4083 // Verify the case where we buffer data but read it after it has been buffered. | |
4084 TEST_P(SpdyNetworkTransactionTest, BufferedAll) { | |
4085 spdy::SpdyFramer framer; | |
4086 | |
4087 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
4088 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4089 | |
4090 // 5 data frames in a single read. | |
4091 scoped_ptr<spdy::SpdyFrame> syn_reply( | |
4092 ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4093 syn_reply->set_flags(spdy::CONTROL_FLAG_NONE); // turn off FIN bit | |
4094 scoped_ptr<spdy::SpdyFrame> data_frame( | |
4095 framer.CreateDataFrame(1, "message", 7, spdy::DATA_FLAG_NONE)); | |
4096 scoped_ptr<spdy::SpdyFrame> data_frame_fin( | |
4097 framer.CreateDataFrame(1, "message", 7, spdy::DATA_FLAG_FIN)); | |
4098 const spdy::SpdyFrame* frames[5] = { | |
4099 syn_reply.get(), | |
4100 data_frame.get(), | |
4101 data_frame.get(), | |
4102 data_frame.get(), | |
4103 data_frame_fin.get() | |
4104 }; | |
4105 char combined_frames[200]; | |
4106 int combined_frames_len = | |
4107 CombineFrames(frames, arraysize(frames), | |
4108 combined_frames, arraysize(combined_frames)); | |
4109 | |
4110 MockRead reads[] = { | |
4111 MockRead(ASYNC, combined_frames, combined_frames_len), | |
4112 MockRead(ASYNC, 0, 0) // EOF | |
4113 }; | |
4114 | |
4115 scoped_ptr<DelayedSocketData> data( | |
4116 new DelayedSocketData(1, reads, arraysize(reads), | |
4117 writes, arraysize(writes))); | |
4118 | |
4119 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
4120 BoundNetLog(), GetParam()); | |
4121 helper.RunPreTestSetup(); | |
4122 helper.AddData(data.get()); | |
4123 HttpNetworkTransaction* trans = helper.trans(); | |
4124 | |
4125 TestCompletionCallback callback; | |
4126 int rv = trans->Start( | |
4127 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4128 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4129 | |
4130 TransactionHelperResult out = helper.output(); | |
4131 out.rv = callback.WaitForResult(); | |
4132 EXPECT_EQ(out.rv, OK); | |
4133 | |
4134 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4135 EXPECT_TRUE(response->headers != NULL); | |
4136 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4137 out.status_line = response->headers->GetStatusLine(); | |
4138 out.response_info = *response; // Make a copy so we can verify. | |
4139 | |
4140 // Read Data | |
4141 TestCompletionCallback read_callback; | |
4142 | |
4143 std::string content; | |
4144 int reads_completed = 0; | |
4145 do { | |
4146 // Read small chunks at a time. | |
4147 const int kSmallReadSize = 14; | |
4148 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); | |
4149 rv = trans->Read(buf, kSmallReadSize, read_callback.callback()); | |
4150 if (rv > 0) { | |
4151 EXPECT_EQ(kSmallReadSize, rv); | |
4152 content.append(buf->data(), rv); | |
4153 } else if (rv < 0) { | |
4154 FAIL() << "Unexpected read error: " << rv; | |
4155 } | |
4156 reads_completed++; | |
4157 } while (rv > 0); | |
4158 | |
4159 EXPECT_EQ(3, reads_completed); | |
4160 | |
4161 out.response_data.swap(content); | |
4162 | |
4163 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the | |
4164 // MockClientSocketFactory) are still alive. | |
4165 MessageLoop::current()->RunAllPending(); | |
4166 | |
4167 // Verify that we consumed all test data. | |
4168 helper.VerifyDataConsumed(); | |
4169 | |
4170 EXPECT_EQ(OK, out.rv); | |
4171 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
4172 EXPECT_EQ("messagemessagemessagemessage", out.response_data); | |
4173 } | |
4174 | |
4175 // Verify the case where we buffer data and close the connection. | |
4176 TEST_P(SpdyNetworkTransactionTest, BufferedClosed) { | |
4177 spdy::SpdyFramer framer; | |
4178 | |
4179 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
4180 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4181 | |
4182 // All data frames in a single read. | |
4183 // NOTE: We don't FIN the stream. | |
4184 scoped_ptr<spdy::SpdyFrame> data_frame( | |
4185 framer.CreateDataFrame(1, "message", 7, spdy::DATA_FLAG_NONE)); | |
4186 const spdy::SpdyFrame* data_frames[4] = { | |
4187 data_frame.get(), | |
4188 data_frame.get(), | |
4189 data_frame.get(), | |
4190 data_frame.get() | |
4191 }; | |
4192 char combined_data_frames[100]; | |
4193 int combined_data_frames_len = | |
4194 CombineFrames(data_frames, arraysize(data_frames), | |
4195 combined_data_frames, arraysize(combined_data_frames)); | |
4196 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4197 MockRead reads[] = { | |
4198 CreateMockRead(*resp), | |
4199 MockRead(ASYNC, ERR_IO_PENDING), // Force a wait | |
4200 MockRead(ASYNC, combined_data_frames, combined_data_frames_len), | |
4201 MockRead(ASYNC, 0, 0) // EOF | |
4202 }; | |
4203 | |
4204 scoped_ptr<DelayedSocketData> data( | |
4205 new DelayedSocketData(1, reads, arraysize(reads), | |
4206 writes, arraysize(writes))); | |
4207 | |
4208 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
4209 BoundNetLog(), GetParam()); | |
4210 helper.RunPreTestSetup(); | |
4211 helper.AddData(data.get()); | |
4212 HttpNetworkTransaction* trans = helper.trans(); | |
4213 | |
4214 TestCompletionCallback callback; | |
4215 | |
4216 int rv = trans->Start( | |
4217 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4218 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4219 | |
4220 TransactionHelperResult out = helper.output(); | |
4221 out.rv = callback.WaitForResult(); | |
4222 EXPECT_EQ(out.rv, OK); | |
4223 | |
4224 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4225 EXPECT_TRUE(response->headers != NULL); | |
4226 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4227 out.status_line = response->headers->GetStatusLine(); | |
4228 out.response_info = *response; // Make a copy so we can verify. | |
4229 | |
4230 // Read Data | |
4231 TestCompletionCallback read_callback; | |
4232 | |
4233 std::string content; | |
4234 int reads_completed = 0; | |
4235 do { | |
4236 // Read small chunks at a time. | |
4237 const int kSmallReadSize = 14; | |
4238 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); | |
4239 rv = trans->Read(buf, kSmallReadSize, read_callback.callback()); | |
4240 if (rv == net::ERR_IO_PENDING) { | |
4241 data->CompleteRead(); | |
4242 rv = read_callback.WaitForResult(); | |
4243 } | |
4244 if (rv > 0) { | |
4245 content.append(buf->data(), rv); | |
4246 } else if (rv < 0) { | |
4247 // This test intentionally closes the connection, and will get an error. | |
4248 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv); | |
4249 break; | |
4250 } | |
4251 reads_completed++; | |
4252 } while (rv > 0); | |
4253 | |
4254 EXPECT_EQ(0, reads_completed); | |
4255 | |
4256 out.response_data.swap(content); | |
4257 | |
4258 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the | |
4259 // MockClientSocketFactory) are still alive. | |
4260 MessageLoop::current()->RunAllPending(); | |
4261 | |
4262 // Verify that we consumed all test data. | |
4263 helper.VerifyDataConsumed(); | |
4264 } | |
4265 | |
4266 // Verify the case where we buffer data and cancel the transaction. | |
4267 TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) { | |
4268 spdy::SpdyFramer framer; | |
4269 | |
4270 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
4271 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4272 | |
4273 // NOTE: We don't FIN the stream. | |
4274 scoped_ptr<spdy::SpdyFrame> data_frame( | |
4275 framer.CreateDataFrame(1, "message", 7, spdy::DATA_FLAG_NONE)); | |
4276 | |
4277 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4278 MockRead reads[] = { | |
4279 CreateMockRead(*resp), | |
4280 MockRead(ASYNC, ERR_IO_PENDING), // Force a wait | |
4281 CreateMockRead(*data_frame), | |
4282 MockRead(ASYNC, 0, 0) // EOF | |
4283 }; | |
4284 | |
4285 scoped_ptr<DelayedSocketData> data( | |
4286 new DelayedSocketData(1, reads, arraysize(reads), | |
4287 writes, arraysize(writes))); | |
4288 | |
4289 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
4290 BoundNetLog(), GetParam()); | |
4291 helper.RunPreTestSetup(); | |
4292 helper.AddData(data.get()); | |
4293 HttpNetworkTransaction* trans = helper.trans(); | |
4294 TestCompletionCallback callback; | |
4295 | |
4296 int rv = trans->Start( | |
4297 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4298 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4299 | |
4300 TransactionHelperResult out = helper.output(); | |
4301 out.rv = callback.WaitForResult(); | |
4302 EXPECT_EQ(out.rv, OK); | |
4303 | |
4304 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4305 EXPECT_TRUE(response->headers != NULL); | |
4306 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4307 out.status_line = response->headers->GetStatusLine(); | |
4308 out.response_info = *response; // Make a copy so we can verify. | |
4309 | |
4310 // Read Data | |
4311 TestCompletionCallback read_callback; | |
4312 | |
4313 do { | |
4314 const int kReadSize = 256; | |
4315 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kReadSize)); | |
4316 rv = trans->Read(buf, kReadSize, read_callback.callback()); | |
4317 if (rv == net::ERR_IO_PENDING) { | |
4318 // Complete the read now, which causes buffering to start. | |
4319 data->CompleteRead(); | |
4320 // Destroy the transaction, causing the stream to get cancelled | |
4321 // and orphaning the buffered IO task. | |
4322 helper.ResetTrans(); | |
4323 break; | |
4324 } | |
4325 // We shouldn't get here in this test. | |
4326 FAIL() << "Unexpected read: " << rv; | |
4327 } while (rv > 0); | |
4328 | |
4329 // Flush the MessageLoop; this will cause the buffered IO task | |
4330 // to run for the final time. | |
4331 MessageLoop::current()->RunAllPending(); | |
4332 | |
4333 // Verify that we consumed all test data. | |
4334 helper.VerifyDataConsumed(); | |
4335 } | |
4336 | |
4337 // Test that if the server requests persistence of settings, that we save | |
4338 // the settings in the SpdySettingsStorage. | |
4339 TEST_P(SpdyNetworkTransactionTest, SettingsSaved) { | |
4340 static const SpdyHeaderInfo kSynReplyInfo = { | |
4341 spdy::SYN_REPLY, // Syn Reply | |
4342 1, // Stream ID | |
4343 0, // Associated Stream ID | |
4344 net::ConvertRequestPriorityToSpdyPriority(LOWEST), | |
4345 // Priority | |
4346 spdy::CONTROL_FLAG_NONE, // Control Flags | |
4347 false, // Compressed | |
4348 spdy::INVALID, // Status | |
4349 NULL, // Data | |
4350 0, // Data Length | |
4351 spdy::DATA_FLAG_NONE // Data Flags | |
4352 }; | |
4353 static const char* const kExtraHeaders[] = { | |
4354 "status", "200", | |
4355 "version", "HTTP/1.1" | |
4356 }; | |
4357 | |
4358 BoundNetLog net_log; | |
4359 NormalSpdyTransactionHelper helper(CreateGetRequest(), net_log, GetParam()); | |
4360 helper.RunPreTestSetup(); | |
4361 | |
4362 // Verify that no settings exist initially. | |
4363 HostPortPair host_port_pair("www.google.com", helper.port()); | |
4364 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); | |
4365 EXPECT_TRUE(spdy_session_pool->http_server_properties()->GetSpdySettings( | |
4366 host_port_pair).empty()); | |
4367 | |
4368 // Construct the request. | |
4369 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
4370 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4371 | |
4372 // Construct the reply. | |
4373 scoped_ptr<spdy::SpdyFrame> reply( | |
4374 ConstructSpdyPacket(kSynReplyInfo, | |
4375 kExtraHeaders, | |
4376 arraysize(kExtraHeaders) / 2, | |
4377 NULL, | |
4378 0)); | |
4379 | |
4380 unsigned int kSampleId1 = 0x1; | |
4381 unsigned int kSampleValue1 = 0x0a0a0a0a; | |
4382 unsigned int kSampleId2 = 0x2; | |
4383 unsigned int kSampleValue2 = 0x0b0b0b0b; | |
4384 unsigned int kSampleId3 = 0xababab; | |
4385 unsigned int kSampleValue3 = 0x0c0c0c0c; | |
4386 scoped_ptr<spdy::SpdyFrame> settings_frame; | |
4387 { | |
4388 // Construct the SETTINGS frame. | |
4389 spdy::SpdySettings settings; | |
4390 spdy::SettingsFlagsAndId setting(0); | |
4391 // First add a persisted setting | |
4392 setting.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST); | |
4393 setting.set_id(kSampleId1); | |
4394 settings.push_back(std::make_pair(setting, kSampleValue1)); | |
4395 // Next add a non-persisted setting | |
4396 setting.set_flags(0); | |
4397 setting.set_id(kSampleId2); | |
4398 settings.push_back(std::make_pair(setting, kSampleValue2)); | |
4399 // Next add another persisted setting | |
4400 setting.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST); | |
4401 setting.set_id(kSampleId3); | |
4402 settings.push_back(std::make_pair(setting, kSampleValue3)); | |
4403 settings_frame.reset(ConstructSpdySettings(settings)); | |
4404 } | |
4405 | |
4406 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
4407 MockRead reads[] = { | |
4408 CreateMockRead(*reply), | |
4409 CreateMockRead(*body), | |
4410 CreateMockRead(*settings_frame), | |
4411 MockRead(ASYNC, 0, 0) // EOF | |
4412 }; | |
4413 | |
4414 scoped_ptr<DelayedSocketData> data( | |
4415 new DelayedSocketData(1, reads, arraysize(reads), | |
4416 writes, arraysize(writes))); | |
4417 helper.AddData(data.get()); | |
4418 helper.RunDefaultTest(); | |
4419 helper.VerifyDataConsumed(); | |
4420 TransactionHelperResult out = helper.output(); | |
4421 EXPECT_EQ(OK, out.rv); | |
4422 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
4423 EXPECT_EQ("hello!", out.response_data); | |
4424 | |
4425 { | |
4426 // Verify we had two persisted settings. | |
4427 spdy::SpdySettings saved_settings = | |
4428 spdy_session_pool->http_server_properties()->GetSpdySettings( | |
4429 host_port_pair); | |
4430 ASSERT_EQ(2u, saved_settings.size()); | |
4431 | |
4432 // Verify the first persisted setting. | |
4433 spdy::SpdySetting setting = saved_settings.front(); | |
4434 saved_settings.pop_front(); | |
4435 EXPECT_EQ(spdy::SETTINGS_FLAG_PERSISTED, setting.first.flags()); | |
4436 EXPECT_EQ(kSampleId1, setting.first.id()); | |
4437 EXPECT_EQ(kSampleValue1, setting.second); | |
4438 | |
4439 // Verify the second persisted setting. | |
4440 setting = saved_settings.front(); | |
4441 saved_settings.pop_front(); | |
4442 EXPECT_EQ(spdy::SETTINGS_FLAG_PERSISTED, setting.first.flags()); | |
4443 EXPECT_EQ(kSampleId3, setting.first.id()); | |
4444 EXPECT_EQ(kSampleValue3, setting.second); | |
4445 } | |
4446 } | |
4447 | |
4448 // Test that when there are settings saved that they are sent back to the | |
4449 // server upon session establishment. | |
4450 TEST_P(SpdyNetworkTransactionTest, SettingsPlayback) { | |
4451 static const SpdyHeaderInfo kSynReplyInfo = { | |
4452 spdy::SYN_REPLY, // Syn Reply | |
4453 1, // Stream ID | |
4454 0, // Associated Stream ID | |
4455 net::ConvertRequestPriorityToSpdyPriority(LOWEST), | |
4456 // Priority | |
4457 spdy::CONTROL_FLAG_NONE, // Control Flags | |
4458 false, // Compressed | |
4459 spdy::INVALID, // Status | |
4460 NULL, // Data | |
4461 0, // Data Length | |
4462 spdy::DATA_FLAG_NONE // Data Flags | |
4463 }; | |
4464 static const char* kExtraHeaders[] = { | |
4465 "status", "200", | |
4466 "version", "HTTP/1.1" | |
4467 }; | |
4468 | |
4469 BoundNetLog net_log; | |
4470 NormalSpdyTransactionHelper helper(CreateGetRequest(), net_log, GetParam()); | |
4471 helper.RunPreTestSetup(); | |
4472 | |
4473 // Verify that no settings exist initially. | |
4474 HostPortPair host_port_pair("www.google.com", helper.port()); | |
4475 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); | |
4476 EXPECT_TRUE(spdy_session_pool->http_server_properties()->GetSpdySettings( | |
4477 host_port_pair).empty()); | |
4478 | |
4479 unsigned int kSampleId1 = 0x1; | |
4480 unsigned int kSampleValue1 = 0x0a0a0a0a; | |
4481 unsigned int kSampleId2 = 0xababab; | |
4482 unsigned int kSampleValue2 = 0x0c0c0c0c; | |
4483 // Manually insert settings into the SpdySettingsStorage here. | |
4484 { | |
4485 spdy::SpdySettings settings; | |
4486 spdy::SettingsFlagsAndId setting(0); | |
4487 // First add a persisted setting | |
4488 setting.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST); | |
4489 setting.set_id(kSampleId1); | |
4490 settings.push_back(std::make_pair(setting, kSampleValue1)); | |
4491 // Next add another persisted setting | |
4492 setting.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST); | |
4493 setting.set_id(kSampleId2); | |
4494 settings.push_back(std::make_pair(setting, kSampleValue2)); | |
4495 | |
4496 spdy_session_pool->http_server_properties()->SetSpdySettings( | |
4497 host_port_pair, settings); | |
4498 } | |
4499 | |
4500 EXPECT_EQ(2u, spdy_session_pool->http_server_properties()->GetSpdySettings( | |
4501 host_port_pair).size()); | |
4502 | |
4503 // Construct the SETTINGS frame. | |
4504 const spdy::SpdySettings& settings = | |
4505 spdy_session_pool->http_server_properties()->GetSpdySettings( | |
4506 host_port_pair); | |
4507 scoped_ptr<spdy::SpdyFrame> settings_frame(ConstructSpdySettings(settings)); | |
4508 | |
4509 // Construct the request. | |
4510 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
4511 | |
4512 MockWrite writes[] = { | |
4513 CreateMockWrite(*settings_frame), | |
4514 CreateMockWrite(*req), | |
4515 }; | |
4516 | |
4517 // Construct the reply. | |
4518 scoped_ptr<spdy::SpdyFrame> reply( | |
4519 ConstructSpdyPacket(kSynReplyInfo, | |
4520 kExtraHeaders, | |
4521 arraysize(kExtraHeaders) / 2, | |
4522 NULL, | |
4523 0)); | |
4524 | |
4525 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
4526 MockRead reads[] = { | |
4527 CreateMockRead(*reply), | |
4528 CreateMockRead(*body), | |
4529 MockRead(ASYNC, 0, 0) // EOF | |
4530 }; | |
4531 | |
4532 scoped_ptr<DelayedSocketData> data( | |
4533 new DelayedSocketData(2, reads, arraysize(reads), | |
4534 writes, arraysize(writes))); | |
4535 helper.AddData(data.get()); | |
4536 helper.RunDefaultTest(); | |
4537 helper.VerifyDataConsumed(); | |
4538 TransactionHelperResult out = helper.output(); | |
4539 EXPECT_EQ(OK, out.rv); | |
4540 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
4541 EXPECT_EQ("hello!", out.response_data); | |
4542 | |
4543 { | |
4544 // Verify we had two persisted settings. | |
4545 spdy::SpdySettings saved_settings = | |
4546 spdy_session_pool->http_server_properties()->GetSpdySettings( | |
4547 host_port_pair); | |
4548 ASSERT_EQ(2u, saved_settings.size()); | |
4549 | |
4550 // Verify the first persisted setting. | |
4551 spdy::SpdySetting setting = saved_settings.front(); | |
4552 saved_settings.pop_front(); | |
4553 EXPECT_EQ(spdy::SETTINGS_FLAG_PERSISTED, setting.first.flags()); | |
4554 EXPECT_EQ(kSampleId1, setting.first.id()); | |
4555 EXPECT_EQ(kSampleValue1, setting.second); | |
4556 | |
4557 // Verify the second persisted setting. | |
4558 setting = saved_settings.front(); | |
4559 saved_settings.pop_front(); | |
4560 EXPECT_EQ(spdy::SETTINGS_FLAG_PERSISTED, setting.first.flags()); | |
4561 EXPECT_EQ(kSampleId2, setting.first.id()); | |
4562 EXPECT_EQ(kSampleValue2, setting.second); | |
4563 } | |
4564 } | |
4565 | |
4566 TEST_P(SpdyNetworkTransactionTest, GoAwayWithActiveStream) { | |
4567 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
4568 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4569 | |
4570 scoped_ptr<spdy::SpdyFrame> go_away(ConstructSpdyGoAway()); | |
4571 MockRead reads[] = { | |
4572 CreateMockRead(*go_away), | |
4573 MockRead(ASYNC, 0, 0), // EOF | |
4574 }; | |
4575 | |
4576 scoped_ptr<DelayedSocketData> data( | |
4577 new DelayedSocketData(1, reads, arraysize(reads), | |
4578 writes, arraysize(writes))); | |
4579 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
4580 BoundNetLog(), GetParam()); | |
4581 helper.AddData(data.get()); | |
4582 helper.RunToCompletion(data.get()); | |
4583 TransactionHelperResult out = helper.output(); | |
4584 EXPECT_EQ(ERR_ABORTED, out.rv); | |
4585 } | |
4586 | |
4587 TEST_P(SpdyNetworkTransactionTest, CloseWithActiveStream) { | |
4588 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
4589 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4590 | |
4591 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4592 MockRead reads[] = { | |
4593 CreateMockRead(*resp), | |
4594 MockRead(SYNCHRONOUS, 0, 0) // EOF | |
4595 }; | |
4596 | |
4597 scoped_ptr<DelayedSocketData> data( | |
4598 new DelayedSocketData(1, reads, arraysize(reads), | |
4599 writes, arraysize(writes))); | |
4600 BoundNetLog log; | |
4601 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
4602 log, GetParam()); | |
4603 helper.RunPreTestSetup(); | |
4604 helper.AddData(data.get()); | |
4605 HttpNetworkTransaction* trans = helper.trans(); | |
4606 | |
4607 TestCompletionCallback callback; | |
4608 TransactionHelperResult out; | |
4609 out.rv = trans->Start(&CreateGetRequest(), callback.callback(), log); | |
4610 | |
4611 EXPECT_EQ(out.rv, ERR_IO_PENDING); | |
4612 out.rv = callback.WaitForResult(); | |
4613 EXPECT_EQ(out.rv, OK); | |
4614 | |
4615 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4616 EXPECT_TRUE(response->headers != NULL); | |
4617 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4618 out.rv = ReadTransaction(trans, &out.response_data); | |
4619 EXPECT_EQ(ERR_CONNECTION_CLOSED, out.rv); | |
4620 | |
4621 // Verify that we consumed all test data. | |
4622 helper.VerifyDataConsumed(); | |
4623 } | |
4624 | |
4625 // Test to make sure we can correctly connect through a proxy. | |
4626 TEST_P(SpdyNetworkTransactionTest, ProxyConnect) { | |
4627 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
4628 BoundNetLog(), GetParam()); | |
4629 helper.session_deps().reset(new SpdySessionDependencies( | |
4630 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"))); | |
4631 helper.SetSession(make_scoped_refptr( | |
4632 SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get()))); | |
4633 helper.RunPreTestSetup(); | |
4634 HttpNetworkTransaction* trans = helper.trans(); | |
4635 | |
4636 const char kConnect443[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n" | |
4637 "Host: www.google.com\r\n" | |
4638 "Proxy-Connection: keep-alive\r\n\r\n"}; | |
4639 const char kConnect80[] = {"CONNECT www.google.com:80 HTTP/1.1\r\n" | |
4640 "Host: www.google.com\r\n" | |
4641 "Proxy-Connection: keep-alive\r\n\r\n"}; | |
4642 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"}; | |
4643 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
4644 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4645 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
4646 | |
4647 MockWrite writes_SPDYNPN[] = { | |
4648 MockWrite(SYNCHRONOUS, kConnect443, arraysize(kConnect443) - 1, 0), | |
4649 CreateMockWrite(*req, 2), | |
4650 }; | |
4651 MockRead reads_SPDYNPN[] = { | |
4652 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1), | |
4653 CreateMockRead(*resp, 3), | |
4654 CreateMockRead(*body.get(), 4), | |
4655 MockRead(ASYNC, 0, 0, 5), | |
4656 }; | |
4657 | |
4658 MockWrite writes_SPDYSSL[] = { | |
4659 MockWrite(SYNCHRONOUS, kConnect80, arraysize(kConnect80) - 1, 0), | |
4660 CreateMockWrite(*req, 2), | |
4661 }; | |
4662 MockRead reads_SPDYSSL[] = { | |
4663 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1), | |
4664 CreateMockRead(*resp, 3), | |
4665 CreateMockRead(*body.get(), 4), | |
4666 MockRead(ASYNC, 0, 0, 5), | |
4667 }; | |
4668 | |
4669 MockWrite writes_SPDYNOSSL[] = { | |
4670 CreateMockWrite(*req, 0), | |
4671 }; | |
4672 | |
4673 MockRead reads_SPDYNOSSL[] = { | |
4674 CreateMockRead(*resp, 1), | |
4675 CreateMockRead(*body.get(), 2), | |
4676 MockRead(ASYNC, 0, 0, 3), | |
4677 }; | |
4678 | |
4679 scoped_ptr<OrderedSocketData> data; | |
4680 switch(GetParam()) { | |
4681 case SPDYNOSSL: | |
4682 data.reset(new OrderedSocketData(reads_SPDYNOSSL, | |
4683 arraysize(reads_SPDYNOSSL), | |
4684 writes_SPDYNOSSL, | |
4685 arraysize(writes_SPDYNOSSL))); | |
4686 break; | |
4687 case SPDYSSL: | |
4688 data.reset(new OrderedSocketData(reads_SPDYSSL, | |
4689 arraysize(reads_SPDYSSL), | |
4690 writes_SPDYSSL, | |
4691 arraysize(writes_SPDYSSL))); | |
4692 break; | |
4693 case SPDYNPN: | |
4694 data.reset(new OrderedSocketData(reads_SPDYNPN, | |
4695 arraysize(reads_SPDYNPN), | |
4696 writes_SPDYNPN, | |
4697 arraysize(writes_SPDYNPN))); | |
4698 break; | |
4699 default: | |
4700 NOTREACHED(); | |
4701 } | |
4702 | |
4703 helper.AddData(data.get()); | |
4704 TestCompletionCallback callback; | |
4705 | |
4706 int rv = trans->Start( | |
4707 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4708 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4709 | |
4710 rv = callback.WaitForResult(); | |
4711 EXPECT_EQ(0, rv); | |
4712 | |
4713 // Verify the SYN_REPLY. | |
4714 HttpResponseInfo response = *trans->GetResponseInfo(); | |
4715 EXPECT_TRUE(response.headers != NULL); | |
4716 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
4717 | |
4718 std::string response_data; | |
4719 ASSERT_EQ(OK, ReadTransaction(trans, &response_data)); | |
4720 EXPECT_EQ("hello!", response_data); | |
4721 helper.VerifyDataConsumed(); | |
4722 } | |
4723 | |
4724 // Test to make sure we can correctly connect through a proxy to www.google.com, | |
4725 // if there already exists a direct spdy connection to www.google.com. See | |
4726 // http://crbug.com/49874 | |
4727 TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) { | |
4728 // When setting up the first transaction, we store the SpdySessionPool so that | |
4729 // we can use the same pool in the second transaction. | |
4730 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
4731 BoundNetLog(), GetParam()); | |
4732 | |
4733 // Use a proxy service which returns a proxy fallback list from DIRECT to | |
4734 // myproxy:70. For this test there will be no fallback, so it is equivalent | |
4735 // to simply DIRECT. The reason for appending the second proxy is to verify | |
4736 // that the session pool key used does is just "DIRECT". | |
4737 helper.session_deps().reset(new SpdySessionDependencies( | |
4738 ProxyService::CreateFixedFromPacResult("DIRECT; PROXY myproxy:70"))); | |
4739 helper.SetSession(make_scoped_refptr( | |
4740 SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get()))); | |
4741 | |
4742 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); | |
4743 helper.RunPreTestSetup(); | |
4744 | |
4745 // Construct and send a simple GET request. | |
4746 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
4747 MockWrite writes[] = { | |
4748 CreateMockWrite(*req, 1), | |
4749 }; | |
4750 | |
4751 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4752 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
4753 MockRead reads[] = { | |
4754 CreateMockRead(*resp, 2), | |
4755 CreateMockRead(*body, 3), | |
4756 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause | |
4757 MockRead(ASYNC, 0, 5) // EOF | |
4758 }; | |
4759 scoped_ptr<OrderedSocketData> data( | |
4760 new OrderedSocketData(reads, arraysize(reads), | |
4761 writes, arraysize(writes))); | |
4762 helper.AddData(data.get()); | |
4763 HttpNetworkTransaction* trans = helper.trans(); | |
4764 | |
4765 TestCompletionCallback callback; | |
4766 TransactionHelperResult out; | |
4767 out.rv = trans->Start( | |
4768 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4769 | |
4770 EXPECT_EQ(out.rv, ERR_IO_PENDING); | |
4771 out.rv = callback.WaitForResult(); | |
4772 EXPECT_EQ(out.rv, OK); | |
4773 | |
4774 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4775 EXPECT_TRUE(response->headers != NULL); | |
4776 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4777 out.rv = ReadTransaction(trans, &out.response_data); | |
4778 EXPECT_EQ(OK, out.rv); | |
4779 out.status_line = response->headers->GetStatusLine(); | |
4780 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
4781 EXPECT_EQ("hello!", out.response_data); | |
4782 | |
4783 // Check that the SpdySession is still in the SpdySessionPool. | |
4784 HostPortPair host_port_pair("www.google.com", helper.port()); | |
4785 HostPortProxyPair session_pool_key_direct( | |
4786 host_port_pair, ProxyServer::Direct()); | |
4787 EXPECT_TRUE(spdy_session_pool->HasSession(session_pool_key_direct)); | |
4788 HostPortProxyPair session_pool_key_proxy( | |
4789 host_port_pair, | |
4790 ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP)); | |
4791 EXPECT_FALSE(spdy_session_pool->HasSession(session_pool_key_proxy)); | |
4792 | |
4793 // Set up data for the proxy connection. | |
4794 const char kConnect443[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n" | |
4795 "Host: www.google.com\r\n" | |
4796 "Proxy-Connection: keep-alive\r\n\r\n"}; | |
4797 const char kConnect80[] = {"CONNECT www.google.com:80 HTTP/1.1\r\n" | |
4798 "Host: www.google.com\r\n" | |
4799 "Proxy-Connection: keep-alive\r\n\r\n"}; | |
4800 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"}; | |
4801 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet( | |
4802 "http://www.google.com/foo.dat", false, 1, LOWEST)); | |
4803 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4804 scoped_ptr<spdy::SpdyFrame> body2(ConstructSpdyBodyFrame(1, true)); | |
4805 | |
4806 MockWrite writes_SPDYNPN[] = { | |
4807 MockWrite(SYNCHRONOUS, kConnect443, arraysize(kConnect443) - 1, 0), | |
4808 CreateMockWrite(*req2, 2), | |
4809 }; | |
4810 MockRead reads_SPDYNPN[] = { | |
4811 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1), | |
4812 CreateMockRead(*resp2, 3), | |
4813 CreateMockRead(*body2, 4), | |
4814 MockRead(ASYNC, 0, 5) // EOF | |
4815 }; | |
4816 | |
4817 MockWrite writes_SPDYNOSSL[] = { | |
4818 CreateMockWrite(*req2, 0), | |
4819 }; | |
4820 MockRead reads_SPDYNOSSL[] = { | |
4821 CreateMockRead(*resp2, 1), | |
4822 CreateMockRead(*body2, 2), | |
4823 MockRead(ASYNC, 0, 3) // EOF | |
4824 }; | |
4825 | |
4826 MockWrite writes_SPDYSSL[] = { | |
4827 MockWrite(SYNCHRONOUS, kConnect80, arraysize(kConnect80) - 1, 0), | |
4828 CreateMockWrite(*req2, 2), | |
4829 }; | |
4830 MockRead reads_SPDYSSL[] = { | |
4831 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1), | |
4832 CreateMockRead(*resp2, 3), | |
4833 CreateMockRead(*body2, 4), | |
4834 MockRead(ASYNC, 0, 0, 5), | |
4835 }; | |
4836 | |
4837 scoped_ptr<OrderedSocketData> data_proxy; | |
4838 switch(GetParam()) { | |
4839 case SPDYNPN: | |
4840 data_proxy.reset(new OrderedSocketData(reads_SPDYNPN, | |
4841 arraysize(reads_SPDYNPN), | |
4842 writes_SPDYNPN, | |
4843 arraysize(writes_SPDYNPN))); | |
4844 break; | |
4845 case SPDYNOSSL: | |
4846 data_proxy.reset(new OrderedSocketData(reads_SPDYNOSSL, | |
4847 arraysize(reads_SPDYNOSSL), | |
4848 writes_SPDYNOSSL, | |
4849 arraysize(writes_SPDYNOSSL))); | |
4850 break; | |
4851 case SPDYSSL: | |
4852 data_proxy.reset(new OrderedSocketData(reads_SPDYSSL, | |
4853 arraysize(reads_SPDYSSL), | |
4854 writes_SPDYSSL, | |
4855 arraysize(writes_SPDYSSL))); | |
4856 break; | |
4857 default: | |
4858 NOTREACHED(); | |
4859 } | |
4860 | |
4861 // Create another request to www.google.com, but this time through a proxy. | |
4862 HttpRequestInfo request_proxy; | |
4863 request_proxy.method = "GET"; | |
4864 request_proxy.url = GURL("http://www.google.com/foo.dat"); | |
4865 request_proxy.load_flags = 0; | |
4866 scoped_ptr<SpdySessionDependencies> ssd_proxy(new SpdySessionDependencies()); | |
4867 // Ensure that this transaction uses the same SpdySessionPool. | |
4868 scoped_refptr<HttpNetworkSession> session_proxy( | |
4869 SpdySessionDependencies::SpdyCreateSession(ssd_proxy.get())); | |
4870 NormalSpdyTransactionHelper helper_proxy(request_proxy, | |
4871 BoundNetLog(), GetParam()); | |
4872 HttpNetworkSessionPeer session_peer(session_proxy); | |
4873 scoped_ptr<net::ProxyService> proxy_service( | |
4874 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); | |
4875 session_peer.SetProxyService(proxy_service.get()); | |
4876 helper_proxy.session_deps().swap(ssd_proxy); | |
4877 helper_proxy.SetSession(session_proxy); | |
4878 helper_proxy.RunPreTestSetup(); | |
4879 helper_proxy.AddData(data_proxy.get()); | |
4880 | |
4881 HttpNetworkTransaction* trans_proxy = helper_proxy.trans(); | |
4882 TestCompletionCallback callback_proxy; | |
4883 int rv = trans_proxy->Start( | |
4884 &request_proxy, callback_proxy.callback(), BoundNetLog()); | |
4885 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4886 rv = callback_proxy.WaitForResult(); | |
4887 EXPECT_EQ(0, rv); | |
4888 | |
4889 HttpResponseInfo response_proxy = *trans_proxy->GetResponseInfo(); | |
4890 EXPECT_TRUE(response_proxy.headers != NULL); | |
4891 EXPECT_EQ("HTTP/1.1 200 OK", response_proxy.headers->GetStatusLine()); | |
4892 | |
4893 std::string response_data; | |
4894 ASSERT_EQ(OK, ReadTransaction(trans_proxy, &response_data)); | |
4895 EXPECT_EQ("hello!", response_data); | |
4896 | |
4897 data->CompleteRead(); | |
4898 helper_proxy.VerifyDataConsumed(); | |
4899 } | |
4900 | |
4901 // When we get a TCP-level RST, we need to retry a HttpNetworkTransaction | |
4902 // on a new connection, if the connection was previously known to be good. | |
4903 // This can happen when a server reboots without saying goodbye, or when | |
4904 // we're behind a NAT that masked the RST. | |
4905 TEST_P(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) { | |
4906 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4907 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
4908 MockRead reads[] = { | |
4909 CreateMockRead(*resp), | |
4910 CreateMockRead(*body), | |
4911 MockRead(ASYNC, ERR_IO_PENDING), | |
4912 MockRead(ASYNC, ERR_CONNECTION_RESET), | |
4913 }; | |
4914 | |
4915 MockRead reads2[] = { | |
4916 CreateMockRead(*resp), | |
4917 CreateMockRead(*body), | |
4918 MockRead(ASYNC, 0, 0) // EOF | |
4919 }; | |
4920 | |
4921 // This test has a couple of variants. | |
4922 enum { | |
4923 // Induce the RST while waiting for our transaction to send. | |
4924 VARIANT_RST_DURING_SEND_COMPLETION, | |
4925 // Induce the RST while waiting for our transaction to read. | |
4926 // In this case, the send completed - everything copied into the SNDBUF. | |
4927 VARIANT_RST_DURING_READ_COMPLETION | |
4928 }; | |
4929 | |
4930 for (int variant = VARIANT_RST_DURING_SEND_COMPLETION; | |
4931 variant <= VARIANT_RST_DURING_READ_COMPLETION; | |
4932 ++variant) { | |
4933 scoped_ptr<DelayedSocketData> data1( | |
4934 new DelayedSocketData(1, reads, arraysize(reads), | |
4935 NULL, 0)); | |
4936 | |
4937 scoped_ptr<DelayedSocketData> data2( | |
4938 new DelayedSocketData(1, reads2, arraysize(reads2), | |
4939 NULL, 0)); | |
4940 | |
4941 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
4942 BoundNetLog(), GetParam()); | |
4943 helper.AddData(data1.get()); | |
4944 helper.AddData(data2.get()); | |
4945 helper.RunPreTestSetup(); | |
4946 | |
4947 for (int i = 0; i < 2; ++i) { | |
4948 scoped_ptr<HttpNetworkTransaction> trans( | |
4949 new HttpNetworkTransaction(helper.session())); | |
4950 | |
4951 TestCompletionCallback callback; | |
4952 int rv = trans->Start( | |
4953 &helper.request(), callback.callback(), BoundNetLog()); | |
4954 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4955 // On the second transaction, we trigger the RST. | |
4956 if (i == 1) { | |
4957 if (variant == VARIANT_RST_DURING_READ_COMPLETION) { | |
4958 // Writes to the socket complete asynchronously on SPDY by running | |
4959 // through the message loop. Complete the write here. | |
4960 MessageLoop::current()->RunAllPending(); | |
4961 } | |
4962 | |
4963 // Now schedule the ERR_CONNECTION_RESET. | |
4964 EXPECT_EQ(3u, data1->read_index()); | |
4965 data1->CompleteRead(); | |
4966 EXPECT_EQ(4u, data1->read_index()); | |
4967 } | |
4968 rv = callback.WaitForResult(); | |
4969 EXPECT_EQ(OK, rv); | |
4970 | |
4971 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4972 ASSERT_TRUE(response != NULL); | |
4973 EXPECT_TRUE(response->headers != NULL); | |
4974 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4975 std::string response_data; | |
4976 rv = ReadTransaction(trans.get(), &response_data); | |
4977 EXPECT_EQ(OK, rv); | |
4978 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
4979 EXPECT_EQ("hello!", response_data); | |
4980 } | |
4981 | |
4982 helper.VerifyDataConsumed(); | |
4983 } | |
4984 } | |
4985 | |
4986 // Test that turning SPDY on and off works properly. | |
4987 TEST_P(SpdyNetworkTransactionTest, SpdyOnOffToggle) { | |
4988 net::HttpStreamFactory::set_spdy_enabled(true); | |
4989 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
4990 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
4991 | |
4992 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4993 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
4994 MockRead spdy_reads[] = { | |
4995 CreateMockRead(*resp), | |
4996 CreateMockRead(*body), | |
4997 MockRead(ASYNC, 0, 0) // EOF | |
4998 }; | |
4999 | |
5000 scoped_ptr<DelayedSocketData> data( | |
5001 new DelayedSocketData(1, | |
5002 spdy_reads, arraysize(spdy_reads), | |
5003 spdy_writes, arraysize(spdy_writes))); | |
5004 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
5005 BoundNetLog(), GetParam()); | |
5006 helper.RunToCompletion(data.get()); | |
5007 TransactionHelperResult out = helper.output(); | |
5008 EXPECT_EQ(OK, out.rv); | |
5009 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
5010 EXPECT_EQ("hello!", out.response_data); | |
5011 | |
5012 net::HttpStreamFactory::set_spdy_enabled(false); | |
5013 MockRead http_reads[] = { | |
5014 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
5015 MockRead("hello from http"), | |
5016 MockRead(SYNCHRONOUS, OK), | |
5017 }; | |
5018 scoped_ptr<DelayedSocketData> data2( | |
5019 new DelayedSocketData(1, http_reads, arraysize(http_reads), | |
5020 NULL, 0)); | |
5021 NormalSpdyTransactionHelper helper2(CreateGetRequest(), | |
5022 BoundNetLog(), GetParam()); | |
5023 helper2.SetSpdyDisabled(); | |
5024 helper2.RunToCompletion(data2.get()); | |
5025 TransactionHelperResult out2 = helper2.output(); | |
5026 EXPECT_EQ(OK, out2.rv); | |
5027 EXPECT_EQ("HTTP/1.1 200 OK", out2.status_line); | |
5028 EXPECT_EQ("hello from http", out2.response_data); | |
5029 | |
5030 net::HttpStreamFactory::set_spdy_enabled(true); | |
5031 } | |
5032 | |
5033 // Tests that Basic authentication works over SPDY | |
5034 TEST_P(SpdyNetworkTransactionTest, SpdyBasicAuth) { | |
5035 net::HttpStreamFactory::set_spdy_enabled(true); | |
5036 | |
5037 // The first request will be a bare GET, the second request will be a | |
5038 // GET with an Authorization header. | |
5039 scoped_ptr<spdy::SpdyFrame> req_get( | |
5040 ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
5041 const char* const kExtraAuthorizationHeaders[] = { | |
5042 "authorization", | |
5043 "Basic Zm9vOmJhcg==", | |
5044 }; | |
5045 scoped_ptr<spdy::SpdyFrame> req_get_authorization( | |
5046 ConstructSpdyGet( | |
5047 kExtraAuthorizationHeaders, | |
5048 arraysize(kExtraAuthorizationHeaders) / 2, | |
5049 false, 3, LOWEST)); | |
5050 MockWrite spdy_writes[] = { | |
5051 CreateMockWrite(*req_get, 1), | |
5052 CreateMockWrite(*req_get_authorization, 4), | |
5053 }; | |
5054 | |
5055 // The first response is a 401 authentication challenge, and the second | |
5056 // response will be a 200 response since the second request includes a valid | |
5057 // Authorization header. | |
5058 const char* const kExtraAuthenticationHeaders[] = { | |
5059 "www-authenticate", | |
5060 "Basic realm=\"MyRealm\"" | |
5061 }; | |
5062 scoped_ptr<spdy::SpdyFrame> resp_authentication( | |
5063 ConstructSpdySynReplyError( | |
5064 "401 Authentication Required", | |
5065 kExtraAuthenticationHeaders, | |
5066 arraysize(kExtraAuthenticationHeaders) / 2, | |
5067 1)); | |
5068 scoped_ptr<spdy::SpdyFrame> body_authentication( | |
5069 ConstructSpdyBodyFrame(1, true)); | |
5070 scoped_ptr<spdy::SpdyFrame> resp_data(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
5071 scoped_ptr<spdy::SpdyFrame> body_data(ConstructSpdyBodyFrame(3, true)); | |
5072 MockRead spdy_reads[] = { | |
5073 CreateMockRead(*resp_authentication, 2), | |
5074 CreateMockRead(*body_authentication, 3), | |
5075 CreateMockRead(*resp_data, 5), | |
5076 CreateMockRead(*body_data, 6), | |
5077 MockRead(ASYNC, 0, 7), | |
5078 }; | |
5079 | |
5080 scoped_ptr<OrderedSocketData> data( | |
5081 new OrderedSocketData(spdy_reads, arraysize(spdy_reads), | |
5082 spdy_writes, arraysize(spdy_writes))); | |
5083 HttpRequestInfo request(CreateGetRequest()); | |
5084 BoundNetLog net_log; | |
5085 NormalSpdyTransactionHelper helper(request, net_log, GetParam()); | |
5086 | |
5087 helper.RunPreTestSetup(); | |
5088 helper.AddData(data.get()); | |
5089 HttpNetworkTransaction* trans = helper.trans(); | |
5090 TestCompletionCallback callback; | |
5091 const int rv_start = trans->Start(&request, callback.callback(), net_log); | |
5092 EXPECT_EQ(ERR_IO_PENDING, rv_start); | |
5093 const int rv_start_complete = callback.WaitForResult(); | |
5094 EXPECT_EQ(OK, rv_start_complete); | |
5095 | |
5096 // Make sure the response has an auth challenge. | |
5097 const HttpResponseInfo* const response_start = trans->GetResponseInfo(); | |
5098 ASSERT_TRUE(response_start != NULL); | |
5099 ASSERT_TRUE(response_start->headers != NULL); | |
5100 EXPECT_EQ(401, response_start->headers->response_code()); | |
5101 EXPECT_TRUE(response_start->was_fetched_via_spdy); | |
5102 AuthChallengeInfo* auth_challenge = response_start->auth_challenge.get(); | |
5103 ASSERT_TRUE(auth_challenge != NULL); | |
5104 EXPECT_FALSE(auth_challenge->is_proxy); | |
5105 EXPECT_EQ("basic", auth_challenge->scheme); | |
5106 EXPECT_EQ("MyRealm", auth_challenge->realm); | |
5107 | |
5108 // Restart with a username/password. | |
5109 AuthCredentials credentials(ASCIIToUTF16("foo"), ASCIIToUTF16("bar")); | |
5110 TestCompletionCallback callback_restart; | |
5111 const int rv_restart = trans->RestartWithAuth( | |
5112 credentials, callback_restart.callback()); | |
5113 EXPECT_EQ(ERR_IO_PENDING, rv_restart); | |
5114 const int rv_restart_complete = callback_restart.WaitForResult(); | |
5115 EXPECT_EQ(OK, rv_restart_complete); | |
5116 // TODO(cbentzel): This is actually the same response object as before, but | |
5117 // data has changed. | |
5118 const HttpResponseInfo* const response_restart = trans->GetResponseInfo(); | |
5119 ASSERT_TRUE(response_restart != NULL); | |
5120 ASSERT_TRUE(response_restart->headers != NULL); | |
5121 EXPECT_EQ(200, response_restart->headers->response_code()); | |
5122 EXPECT_TRUE(response_restart->auth_challenge.get() == NULL); | |
5123 } | |
5124 | |
5125 TEST_P(SpdyNetworkTransactionTest, ServerPushWithHeaders) { | |
5126 static const unsigned char kPushBodyFrame[] = { | |
5127 0x00, 0x00, 0x00, 0x02, // header, ID | |
5128 0x01, 0x00, 0x00, 0x06, // FIN, length | |
5129 'p', 'u', 's', 'h', 'e', 'd' // "pushed" | |
5130 }; | |
5131 scoped_ptr<spdy::SpdyFrame> | |
5132 stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
5133 scoped_ptr<spdy::SpdyFrame> | |
5134 stream1_body(ConstructSpdyBodyFrame(1, true)); | |
5135 MockWrite writes[] = { | |
5136 CreateMockWrite(*stream1_syn, 1), | |
5137 }; | |
5138 | |
5139 static const char* const kInitialHeaders[] = { | |
5140 "url", | |
5141 "http://www.google.com/foo.dat", | |
5142 }; | |
5143 static const char* const kLateHeaders[] = { | |
5144 "hello", | |
5145 "bye", | |
5146 "status", | |
5147 "200", | |
5148 "version", | |
5149 "HTTP/1.1" | |
5150 }; | |
5151 scoped_ptr<spdy::SpdyFrame> | |
5152 stream2_syn(ConstructSpdyControlFrame(kInitialHeaders, | |
5153 arraysize(kInitialHeaders) / 2, | |
5154 false, | |
5155 2, | |
5156 LOWEST, | |
5157 spdy::SYN_STREAM, | |
5158 spdy::CONTROL_FLAG_NONE, | |
5159 NULL, | |
5160 0, | |
5161 1)); | |
5162 scoped_ptr<spdy::SpdyFrame> | |
5163 stream2_headers(ConstructSpdyControlFrame(kLateHeaders, | |
5164 arraysize(kLateHeaders) / 2, | |
5165 false, | |
5166 2, | |
5167 LOWEST, | |
5168 spdy::HEADERS, | |
5169 spdy::CONTROL_FLAG_NONE, | |
5170 NULL, | |
5171 0, | |
5172 0)); | |
5173 | |
5174 scoped_ptr<spdy::SpdyFrame> | |
5175 stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
5176 MockRead reads[] = { | |
5177 CreateMockRead(*stream1_reply, 2), | |
5178 CreateMockRead(*stream2_syn, 3), | |
5179 CreateMockRead(*stream2_headers, 4), | |
5180 CreateMockRead(*stream1_body, 5, SYNCHRONOUS), | |
5181 MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), | |
5182 arraysize(kPushBodyFrame), 6), | |
5183 MockRead(ASYNC, ERR_IO_PENDING, 7), // Force a pause | |
5184 }; | |
5185 | |
5186 HttpResponseInfo response; | |
5187 HttpResponseInfo response2; | |
5188 std::string expected_push_result("pushed"); | |
5189 scoped_ptr<OrderedSocketData> data(new OrderedSocketData( | |
5190 reads, | |
5191 arraysize(reads), | |
5192 writes, | |
5193 arraysize(writes))); | |
5194 RunServerPushTest(data.get(), | |
5195 &response, | |
5196 &response2, | |
5197 expected_push_result); | |
5198 | |
5199 // Verify the SYN_REPLY. | |
5200 EXPECT_TRUE(response.headers != NULL); | |
5201 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
5202 | |
5203 // Verify the pushed stream. | |
5204 EXPECT_TRUE(response2.headers != NULL); | |
5205 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
5206 } | |
5207 | |
5208 TEST_P(SpdyNetworkTransactionTest, ServerPushClaimBeforeHeaders) { | |
5209 // We push a stream and attempt to claim it before the headers come down. | |
5210 static const unsigned char kPushBodyFrame[] = { | |
5211 0x00, 0x00, 0x00, 0x02, // header, ID | |
5212 0x01, 0x00, 0x00, 0x06, // FIN, length | |
5213 'p', 'u', 's', 'h', 'e', 'd' // "pushed" | |
5214 }; | |
5215 scoped_ptr<spdy::SpdyFrame> | |
5216 stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
5217 scoped_ptr<spdy::SpdyFrame> | |
5218 stream1_body(ConstructSpdyBodyFrame(1, true)); | |
5219 MockWrite writes[] = { | |
5220 CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS), | |
5221 }; | |
5222 | |
5223 static const char* const kInitialHeaders[] = { | |
5224 "url", | |
5225 "http://www.google.com/foo.dat", | |
5226 }; | |
5227 static const char* const kLateHeaders[] = { | |
5228 "hello", | |
5229 "bye", | |
5230 "status", | |
5231 "200", | |
5232 "version", | |
5233 "HTTP/1.1" | |
5234 }; | |
5235 scoped_ptr<spdy::SpdyFrame> | |
5236 stream2_syn(ConstructSpdyControlFrame(kInitialHeaders, | |
5237 arraysize(kInitialHeaders) / 2, | |
5238 false, | |
5239 2, | |
5240 LOWEST, | |
5241 spdy::SYN_STREAM, | |
5242 spdy::CONTROL_FLAG_NONE, | |
5243 NULL, | |
5244 0, | |
5245 1)); | |
5246 scoped_ptr<spdy::SpdyFrame> | |
5247 stream2_headers(ConstructSpdyControlFrame(kLateHeaders, | |
5248 arraysize(kLateHeaders) / 2, | |
5249 false, | |
5250 2, | |
5251 LOWEST, | |
5252 spdy::HEADERS, | |
5253 spdy::CONTROL_FLAG_NONE, | |
5254 NULL, | |
5255 0, | |
5256 0)); | |
5257 | |
5258 scoped_ptr<spdy::SpdyFrame> | |
5259 stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
5260 MockRead reads[] = { | |
5261 CreateMockRead(*stream1_reply, 1), | |
5262 CreateMockRead(*stream2_syn, 2), | |
5263 CreateMockRead(*stream1_body, 3), | |
5264 CreateMockRead(*stream2_headers, 4), | |
5265 MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), | |
5266 arraysize(kPushBodyFrame), 5), | |
5267 MockRead(ASYNC, 0, 5), // EOF | |
5268 }; | |
5269 | |
5270 HttpResponseInfo response; | |
5271 HttpResponseInfo response2; | |
5272 std::string expected_push_result("pushed"); | |
5273 scoped_refptr<DeterministicSocketData> data(new DeterministicSocketData( | |
5274 reads, | |
5275 arraysize(reads), | |
5276 writes, | |
5277 arraysize(writes))); | |
5278 | |
5279 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
5280 BoundNetLog(), GetParam()); | |
5281 helper.SetDeterministic(); | |
5282 helper.AddDeterministicData(static_cast<DeterministicSocketData*>(data)); | |
5283 helper.RunPreTestSetup(); | |
5284 | |
5285 HttpNetworkTransaction* trans = helper.trans(); | |
5286 | |
5287 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM, | |
5288 // and the body of the primary stream, but before we've received the HEADERS | |
5289 // for the pushed stream. | |
5290 data->SetStop(3); | |
5291 | |
5292 // Start the transaction. | |
5293 TestCompletionCallback callback; | |
5294 int rv = trans->Start( | |
5295 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
5296 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5297 data->Run(); | |
5298 rv = callback.WaitForResult(); | |
5299 EXPECT_EQ(0, rv); | |
5300 | |
5301 // Request the pushed path. At this point, we've received the push, but the | |
5302 // headers are not yet complete. | |
5303 scoped_ptr<HttpNetworkTransaction> trans2( | |
5304 new HttpNetworkTransaction(helper.session())); | |
5305 rv = trans2->Start( | |
5306 &CreateGetPushRequest(), callback.callback(), BoundNetLog()); | |
5307 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5308 data->RunFor(3); | |
5309 MessageLoop::current()->RunAllPending(); | |
5310 | |
5311 // Read the server push body. | |
5312 std::string result2; | |
5313 ReadResult(trans2.get(), data.get(), &result2); | |
5314 // Read the response body. | |
5315 std::string result; | |
5316 ReadResult(trans, data, &result); | |
5317 | |
5318 // Verify that we consumed all test data. | |
5319 EXPECT_TRUE(data->at_read_eof()); | |
5320 EXPECT_TRUE(data->at_write_eof()); | |
5321 | |
5322 // Verify that the received push data is same as the expected push data. | |
5323 EXPECT_EQ(result2.compare(expected_push_result), 0) | |
5324 << "Received data: " | |
5325 << result2 | |
5326 << "||||| Expected data: " | |
5327 << expected_push_result; | |
5328 | |
5329 // Verify the SYN_REPLY. | |
5330 // Copy the response info, because trans goes away. | |
5331 response = *trans->GetResponseInfo(); | |
5332 response2 = *trans2->GetResponseInfo(); | |
5333 | |
5334 VerifyStreamsClosed(helper); | |
5335 | |
5336 // Verify the SYN_REPLY. | |
5337 EXPECT_TRUE(response.headers != NULL); | |
5338 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
5339 | |
5340 // Verify the pushed stream. | |
5341 EXPECT_TRUE(response2.headers != NULL); | |
5342 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
5343 } | |
5344 | |
5345 TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) { | |
5346 // We push a stream and attempt to claim it before the headers come down. | |
5347 static const unsigned char kPushBodyFrame[] = { | |
5348 0x00, 0x00, 0x00, 0x02, // header, ID | |
5349 0x01, 0x00, 0x00, 0x06, // FIN, length | |
5350 'p', 'u', 's', 'h', 'e', 'd' // "pushed" | |
5351 }; | |
5352 scoped_ptr<spdy::SpdyFrame> | |
5353 stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
5354 scoped_ptr<spdy::SpdyFrame> | |
5355 stream1_body(ConstructSpdyBodyFrame(1, true)); | |
5356 MockWrite writes[] = { | |
5357 CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS), | |
5358 }; | |
5359 | |
5360 static const char* const kInitialHeaders[] = { | |
5361 "url", | |
5362 "http://www.google.com/foo.dat", | |
5363 }; | |
5364 static const char* const kMiddleHeaders[] = { | |
5365 "hello", | |
5366 "bye", | |
5367 }; | |
5368 static const char* const kLateHeaders[] = { | |
5369 "status", | |
5370 "200", | |
5371 "version", | |
5372 "HTTP/1.1" | |
5373 }; | |
5374 scoped_ptr<spdy::SpdyFrame> | |
5375 stream2_syn(ConstructSpdyControlFrame(kInitialHeaders, | |
5376 arraysize(kInitialHeaders) / 2, | |
5377 false, | |
5378 2, | |
5379 LOWEST, | |
5380 spdy::SYN_STREAM, | |
5381 spdy::CONTROL_FLAG_NONE, | |
5382 NULL, | |
5383 0, | |
5384 1)); | |
5385 scoped_ptr<spdy::SpdyFrame> | |
5386 stream2_headers1(ConstructSpdyControlFrame(kMiddleHeaders, | |
5387 arraysize(kMiddleHeaders) / 2, | |
5388 false, | |
5389 2, | |
5390 LOWEST, | |
5391 spdy::HEADERS, | |
5392 spdy::CONTROL_FLAG_NONE, | |
5393 NULL, | |
5394 0, | |
5395 0)); | |
5396 scoped_ptr<spdy::SpdyFrame> | |
5397 stream2_headers2(ConstructSpdyControlFrame(kLateHeaders, | |
5398 arraysize(kLateHeaders) / 2, | |
5399 false, | |
5400 2, | |
5401 LOWEST, | |
5402 spdy::HEADERS, | |
5403 spdy::CONTROL_FLAG_NONE, | |
5404 NULL, | |
5405 0, | |
5406 0)); | |
5407 | |
5408 scoped_ptr<spdy::SpdyFrame> | |
5409 stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
5410 MockRead reads[] = { | |
5411 CreateMockRead(*stream1_reply, 1), | |
5412 CreateMockRead(*stream2_syn, 2), | |
5413 CreateMockRead(*stream1_body, 3), | |
5414 CreateMockRead(*stream2_headers1, 4), | |
5415 CreateMockRead(*stream2_headers2, 5), | |
5416 MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), | |
5417 arraysize(kPushBodyFrame), 6), | |
5418 MockRead(ASYNC, 0, 6), // EOF | |
5419 }; | |
5420 | |
5421 HttpResponseInfo response; | |
5422 HttpResponseInfo response2; | |
5423 std::string expected_push_result("pushed"); | |
5424 scoped_refptr<DeterministicSocketData> data(new DeterministicSocketData( | |
5425 reads, | |
5426 arraysize(reads), | |
5427 writes, | |
5428 arraysize(writes))); | |
5429 | |
5430 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
5431 BoundNetLog(), GetParam()); | |
5432 helper.SetDeterministic(); | |
5433 helper.AddDeterministicData(static_cast<DeterministicSocketData*>(data)); | |
5434 helper.RunPreTestSetup(); | |
5435 | |
5436 HttpNetworkTransaction* trans = helper.trans(); | |
5437 | |
5438 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM, | |
5439 // the first HEADERS frame, and the body of the primary stream, but before | |
5440 // we've received the final HEADERS for the pushed stream. | |
5441 data->SetStop(4); | |
5442 | |
5443 // Start the transaction. | |
5444 TestCompletionCallback callback; | |
5445 int rv = trans->Start( | |
5446 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
5447 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5448 data->Run(); | |
5449 rv = callback.WaitForResult(); | |
5450 EXPECT_EQ(0, rv); | |
5451 | |
5452 // Request the pushed path. At this point, we've received the push, but the | |
5453 // headers are not yet complete. | |
5454 scoped_ptr<HttpNetworkTransaction> trans2( | |
5455 new HttpNetworkTransaction(helper.session())); | |
5456 rv = trans2->Start( | |
5457 &CreateGetPushRequest(), callback.callback(), BoundNetLog()); | |
5458 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5459 data->RunFor(3); | |
5460 MessageLoop::current()->RunAllPending(); | |
5461 | |
5462 // Read the server push body. | |
5463 std::string result2; | |
5464 ReadResult(trans2.get(), data, &result2); | |
5465 // Read the response body. | |
5466 std::string result; | |
5467 ReadResult(trans, data, &result); | |
5468 | |
5469 // Verify that we consumed all test data. | |
5470 EXPECT_TRUE(data->at_read_eof()); | |
5471 EXPECT_TRUE(data->at_write_eof()); | |
5472 | |
5473 // Verify that the received push data is same as the expected push data. | |
5474 EXPECT_EQ(result2.compare(expected_push_result), 0) | |
5475 << "Received data: " | |
5476 << result2 | |
5477 << "||||| Expected data: " | |
5478 << expected_push_result; | |
5479 | |
5480 // Verify the SYN_REPLY. | |
5481 // Copy the response info, because trans goes away. | |
5482 response = *trans->GetResponseInfo(); | |
5483 response2 = *trans2->GetResponseInfo(); | |
5484 | |
5485 VerifyStreamsClosed(helper); | |
5486 | |
5487 // Verify the SYN_REPLY. | |
5488 EXPECT_TRUE(response.headers != NULL); | |
5489 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
5490 | |
5491 // Verify the pushed stream. | |
5492 EXPECT_TRUE(response2.headers != NULL); | |
5493 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
5494 | |
5495 // Verify we got all the headers | |
5496 EXPECT_TRUE(response2.headers->HasHeaderValue( | |
5497 "url", | |
5498 "http://www.google.com/foo.dat")); | |
5499 EXPECT_TRUE(response2.headers->HasHeaderValue("hello", "bye")); | |
5500 EXPECT_TRUE(response2.headers->HasHeaderValue("status", "200")); | |
5501 EXPECT_TRUE(response2.headers->HasHeaderValue("version", "HTTP/1.1")); | |
5502 } | |
5503 | |
5504 TEST_P(SpdyNetworkTransactionTest, SynReplyWithHeaders) { | |
5505 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
5506 MockWrite writes[] = { CreateMockWrite(*req) }; | |
5507 | |
5508 static const char* const kInitialHeaders[] = { | |
5509 "status", | |
5510 "200 OK", | |
5511 "version", | |
5512 "HTTP/1.1" | |
5513 }; | |
5514 static const char* const kLateHeaders[] = { | |
5515 "hello", | |
5516 "bye", | |
5517 }; | |
5518 scoped_ptr<spdy::SpdyFrame> | |
5519 stream1_reply(ConstructSpdyControlFrame(kInitialHeaders, | |
5520 arraysize(kInitialHeaders) / 2, | |
5521 false, | |
5522 1, | |
5523 LOWEST, | |
5524 spdy::SYN_REPLY, | |
5525 spdy::CONTROL_FLAG_NONE, | |
5526 NULL, | |
5527 0, | |
5528 0)); | |
5529 scoped_ptr<spdy::SpdyFrame> | |
5530 stream1_headers(ConstructSpdyControlFrame(kLateHeaders, | |
5531 arraysize(kLateHeaders) / 2, | |
5532 false, | |
5533 1, | |
5534 LOWEST, | |
5535 spdy::HEADERS, | |
5536 spdy::CONTROL_FLAG_NONE, | |
5537 NULL, | |
5538 0, | |
5539 0)); | |
5540 scoped_ptr<spdy::SpdyFrame> stream1_body(ConstructSpdyBodyFrame(1, true)); | |
5541 MockRead reads[] = { | |
5542 CreateMockRead(*stream1_reply), | |
5543 CreateMockRead(*stream1_headers), | |
5544 CreateMockRead(*stream1_body), | |
5545 MockRead(ASYNC, 0, 0) // EOF | |
5546 }; | |
5547 | |
5548 scoped_ptr<DelayedSocketData> data( | |
5549 new DelayedSocketData(1, reads, arraysize(reads), | |
5550 writes, arraysize(writes))); | |
5551 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
5552 BoundNetLog(), GetParam()); | |
5553 helper.RunToCompletion(data.get()); | |
5554 TransactionHelperResult out = helper.output(); | |
5555 EXPECT_EQ(OK, out.rv); | |
5556 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
5557 EXPECT_EQ("hello!", out.response_data); | |
5558 } | |
5559 | |
5560 TEST_P(SpdyNetworkTransactionTest, SynReplyWithLateHeaders) { | |
5561 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
5562 MockWrite writes[] = { CreateMockWrite(*req) }; | |
5563 | |
5564 static const char* const kInitialHeaders[] = { | |
5565 "status", | |
5566 "200 OK", | |
5567 "version", | |
5568 "HTTP/1.1" | |
5569 }; | |
5570 static const char* const kLateHeaders[] = { | |
5571 "hello", | |
5572 "bye", | |
5573 }; | |
5574 scoped_ptr<spdy::SpdyFrame> | |
5575 stream1_reply(ConstructSpdyControlFrame(kInitialHeaders, | |
5576 arraysize(kInitialHeaders) / 2, | |
5577 false, | |
5578 1, | |
5579 LOWEST, | |
5580 spdy::SYN_REPLY, | |
5581 spdy::CONTROL_FLAG_NONE, | |
5582 NULL, | |
5583 0, | |
5584 0)); | |
5585 scoped_ptr<spdy::SpdyFrame> | |
5586 stream1_headers(ConstructSpdyControlFrame(kLateHeaders, | |
5587 arraysize(kLateHeaders) / 2, | |
5588 false, | |
5589 1, | |
5590 LOWEST, | |
5591 spdy::HEADERS, | |
5592 spdy::CONTROL_FLAG_NONE, | |
5593 NULL, | |
5594 0, | |
5595 0)); | |
5596 scoped_ptr<spdy::SpdyFrame> stream1_body(ConstructSpdyBodyFrame(1, false)); | |
5597 scoped_ptr<spdy::SpdyFrame> stream1_body2(ConstructSpdyBodyFrame(1, true)); | |
5598 MockRead reads[] = { | |
5599 CreateMockRead(*stream1_reply), | |
5600 CreateMockRead(*stream1_body), | |
5601 CreateMockRead(*stream1_headers), | |
5602 CreateMockRead(*stream1_body2), | |
5603 MockRead(ASYNC, 0, 0) // EOF | |
5604 }; | |
5605 | |
5606 scoped_ptr<DelayedSocketData> data( | |
5607 new DelayedSocketData(1, reads, arraysize(reads), | |
5608 writes, arraysize(writes))); | |
5609 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
5610 BoundNetLog(), GetParam()); | |
5611 helper.RunToCompletion(data.get()); | |
5612 TransactionHelperResult out = helper.output(); | |
5613 EXPECT_EQ(OK, out.rv); | |
5614 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
5615 EXPECT_EQ("hello!hello!", out.response_data); | |
5616 } | |
5617 | |
5618 TEST_P(SpdyNetworkTransactionTest, SynReplyWithDuplicateLateHeaders) { | |
5619 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
5620 MockWrite writes[] = { CreateMockWrite(*req) }; | |
5621 | |
5622 static const char* const kInitialHeaders[] = { | |
5623 "status", | |
5624 "200 OK", | |
5625 "version", | |
5626 "HTTP/1.1" | |
5627 }; | |
5628 static const char* const kLateHeaders[] = { | |
5629 "status", | |
5630 "500 Server Error", | |
5631 }; | |
5632 scoped_ptr<spdy::SpdyFrame> | |
5633 stream1_reply(ConstructSpdyControlFrame(kInitialHeaders, | |
5634 arraysize(kInitialHeaders) / 2, | |
5635 false, | |
5636 1, | |
5637 LOWEST, | |
5638 spdy::SYN_REPLY, | |
5639 spdy::CONTROL_FLAG_NONE, | |
5640 NULL, | |
5641 0, | |
5642 0)); | |
5643 scoped_ptr<spdy::SpdyFrame> | |
5644 stream1_headers(ConstructSpdyControlFrame(kLateHeaders, | |
5645 arraysize(kLateHeaders) / 2, | |
5646 false, | |
5647 1, | |
5648 LOWEST, | |
5649 spdy::HEADERS, | |
5650 spdy::CONTROL_FLAG_NONE, | |
5651 NULL, | |
5652 0, | |
5653 0)); | |
5654 scoped_ptr<spdy::SpdyFrame> stream1_body(ConstructSpdyBodyFrame(1, false)); | |
5655 scoped_ptr<spdy::SpdyFrame> stream1_body2(ConstructSpdyBodyFrame(1, true)); | |
5656 MockRead reads[] = { | |
5657 CreateMockRead(*stream1_reply), | |
5658 CreateMockRead(*stream1_body), | |
5659 CreateMockRead(*stream1_headers), | |
5660 CreateMockRead(*stream1_body2), | |
5661 MockRead(ASYNC, 0, 0) // EOF | |
5662 }; | |
5663 | |
5664 scoped_ptr<DelayedSocketData> data( | |
5665 new DelayedSocketData(1, reads, arraysize(reads), | |
5666 writes, arraysize(writes))); | |
5667 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
5668 BoundNetLog(), GetParam()); | |
5669 helper.RunToCompletion(data.get()); | |
5670 TransactionHelperResult out = helper.output(); | |
5671 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
5672 } | |
5673 | |
5674 TEST_P(SpdyNetworkTransactionTest, ServerPushCrossOriginCorrectness) { | |
5675 // In this test we want to verify that we can't accidentally push content | |
5676 // which can't be pushed by this content server. | |
5677 // This test assumes that: | |
5678 // - if we're requesting http://www.foo.com/barbaz | |
5679 // - the browser has made a connection to "www.foo.com". | |
5680 | |
5681 // A list of the URL to fetch, followed by the URL being pushed. | |
5682 static const char* const kTestCases[] = { | |
5683 "http://www.google.com/foo.html", | |
5684 "http://www.google.com:81/foo.js", // Bad port | |
5685 | |
5686 "http://www.google.com/foo.html", | |
5687 "https://www.google.com/foo.js", // Bad protocol | |
5688 | |
5689 "http://www.google.com/foo.html", | |
5690 "ftp://www.google.com/foo.js", // Invalid Protocol | |
5691 | |
5692 "http://www.google.com/foo.html", | |
5693 "http://blat.www.google.com/foo.js", // Cross subdomain | |
5694 | |
5695 "http://www.google.com/foo.html", | |
5696 "http://www.foo.com/foo.js", // Cross domain | |
5697 }; | |
5698 | |
5699 | |
5700 static const unsigned char kPushBodyFrame[] = { | |
5701 0x00, 0x00, 0x00, 0x02, // header, ID | |
5702 0x01, 0x00, 0x00, 0x06, // FIN, length | |
5703 'p', 'u', 's', 'h', 'e', 'd' // "pushed" | |
5704 }; | |
5705 | |
5706 for (size_t index = 0; index < arraysize(kTestCases); index += 2) { | |
5707 const char* url_to_fetch = kTestCases[index]; | |
5708 const char* url_to_push = kTestCases[index + 1]; | |
5709 | |
5710 scoped_ptr<spdy::SpdyFrame> | |
5711 stream1_syn(ConstructSpdyGet(url_to_fetch, false, 1, LOWEST)); | |
5712 scoped_ptr<spdy::SpdyFrame> | |
5713 stream1_body(ConstructSpdyBodyFrame(1, true)); | |
5714 scoped_ptr<spdy::SpdyFrame> push_rst( | |
5715 ConstructSpdyRstStream(2, spdy::REFUSED_STREAM)); | |
5716 MockWrite writes[] = { | |
5717 CreateMockWrite(*stream1_syn, 1), | |
5718 CreateMockWrite(*push_rst, 4), | |
5719 }; | |
5720 | |
5721 scoped_ptr<spdy::SpdyFrame> | |
5722 stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
5723 scoped_ptr<spdy::SpdyFrame> | |
5724 stream2_syn(ConstructSpdyPush(NULL, | |
5725 0, | |
5726 2, | |
5727 1, | |
5728 url_to_push)); | |
5729 scoped_ptr<spdy::SpdyFrame> rst( | |
5730 ConstructSpdyRstStream(2, spdy::CANCEL)); | |
5731 | |
5732 MockRead reads[] = { | |
5733 CreateMockRead(*stream1_reply, 2), | |
5734 CreateMockRead(*stream2_syn, 3), | |
5735 CreateMockRead(*stream1_body, 5, SYNCHRONOUS), | |
5736 MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), | |
5737 arraysize(kPushBodyFrame), 6), | |
5738 MockRead(ASYNC, ERR_IO_PENDING, 7), // Force a pause | |
5739 }; | |
5740 | |
5741 HttpResponseInfo response; | |
5742 scoped_ptr<OrderedSocketData> data(new OrderedSocketData( | |
5743 reads, | |
5744 arraysize(reads), | |
5745 writes, | |
5746 arraysize(writes))); | |
5747 | |
5748 HttpRequestInfo request; | |
5749 request.method = "GET"; | |
5750 request.url = GURL(url_to_fetch); | |
5751 request.load_flags = 0; | |
5752 NormalSpdyTransactionHelper helper(request, | |
5753 BoundNetLog(), GetParam()); | |
5754 helper.RunPreTestSetup(); | |
5755 helper.AddData(data.get()); | |
5756 | |
5757 HttpNetworkTransaction* trans = helper.trans(); | |
5758 | |
5759 // Start the transaction with basic parameters. | |
5760 TestCompletionCallback callback; | |
5761 | |
5762 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5763 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5764 rv = callback.WaitForResult(); | |
5765 | |
5766 // Read the response body. | |
5767 std::string result; | |
5768 ReadResult(trans, data.get(), &result); | |
5769 | |
5770 // Verify that we consumed all test data. | |
5771 EXPECT_TRUE(data->at_read_eof()); | |
5772 EXPECT_TRUE(data->at_write_eof()); | |
5773 | |
5774 // Verify the SYN_REPLY. | |
5775 // Copy the response info, because trans goes away. | |
5776 response = *trans->GetResponseInfo(); | |
5777 | |
5778 VerifyStreamsClosed(helper); | |
5779 | |
5780 // Verify the SYN_REPLY. | |
5781 EXPECT_TRUE(response.headers != NULL); | |
5782 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
5783 } | |
5784 } | |
5785 | |
5786 TEST_P(SpdyNetworkTransactionTest, RetryAfterRefused) { | |
5787 // Construct the request. | |
5788 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
5789 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); | |
5790 MockWrite writes[] = { | |
5791 CreateMockWrite(*req, 1), | |
5792 CreateMockWrite(*req2, 3), | |
5793 }; | |
5794 | |
5795 scoped_ptr<spdy::SpdyFrame> refused( | |
5796 ConstructSpdyRstStream(1, spdy::REFUSED_STREAM)); | |
5797 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
5798 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(3, true)); | |
5799 MockRead reads[] = { | |
5800 CreateMockRead(*refused, 2), | |
5801 CreateMockRead(*resp, 4), | |
5802 CreateMockRead(*body, 5), | |
5803 MockRead(ASYNC, 0, 6) // EOF | |
5804 }; | |
5805 | |
5806 scoped_ptr<OrderedSocketData> data( | |
5807 new OrderedSocketData(reads, arraysize(reads), | |
5808 writes, arraysize(writes))); | |
5809 NormalSpdyTransactionHelper helper(CreateGetRequest(), | |
5810 BoundNetLog(), GetParam()); | |
5811 | |
5812 helper.RunPreTestSetup(); | |
5813 helper.AddData(data.get()); | |
5814 | |
5815 HttpNetworkTransaction* trans = helper.trans(); | |
5816 | |
5817 // Start the transaction with basic parameters. | |
5818 TestCompletionCallback callback; | |
5819 int rv = trans->Start( | |
5820 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
5821 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5822 rv = callback.WaitForResult(); | |
5823 EXPECT_EQ(OK, rv); | |
5824 | |
5825 // Verify that we consumed all test data. | |
5826 EXPECT_TRUE(data->at_read_eof()) << "Read count: " | |
5827 << data->read_count() | |
5828 << " Read index: " | |
5829 << data->read_index(); | |
5830 EXPECT_TRUE(data->at_write_eof()) << "Write count: " | |
5831 << data->write_count() | |
5832 << " Write index: " | |
5833 << data->write_index(); | |
5834 | |
5835 // Verify the SYN_REPLY. | |
5836 HttpResponseInfo response = *trans->GetResponseInfo(); | |
5837 EXPECT_TRUE(response.headers != NULL); | |
5838 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
5839 } | |
5840 | |
5841 } // namespace net | |
OLD | NEW |