Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(480)

Side by Side Diff: net/spdy/spdy_network_transaction_spdy21_unittest.cc

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

Powered by Google App Engine
This is Rietveld 408576698