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