Home | History | Annotate | Download | only in spdy
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/spdy/spdy_http_stream.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/message_loop/message_loop_proxy.h"
     11 #include "base/run_loop.h"
     12 #include "base/stl_util.h"
     13 #include "crypto/ec_private_key.h"
     14 #include "crypto/ec_signature_creator.h"
     15 #include "crypto/signature_creator.h"
     16 #include "net/base/capturing_net_log.h"
     17 #include "net/base/load_timing_info.h"
     18 #include "net/base/load_timing_info_test_util.h"
     19 #include "net/base/upload_data_stream.h"
     20 #include "net/base/upload_element_reader.h"
     21 #include "net/cert/asn1_util.h"
     22 #include "net/http/http_request_info.h"
     23 #include "net/http/http_response_headers.h"
     24 #include "net/http/http_response_info.h"
     25 #include "net/socket/next_proto.h"
     26 #include "net/socket/socket_test_util.h"
     27 #include "net/spdy/spdy_http_utils.h"
     28 #include "net/spdy/spdy_session.h"
     29 #include "net/spdy/spdy_test_util_common.h"
     30 #include "net/ssl/default_server_bound_cert_store.h"
     31 #include "testing/gtest/include/gtest/gtest.h"
     32 
     33 namespace net {
     34 
     35 namespace {
     36 
     37 // Tests the load timing of a stream that's connected and is not the first
     38 // request sent on a connection.
     39 void TestLoadTimingReused(const HttpStream& stream) {
     40   LoadTimingInfo load_timing_info;
     41   EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info));
     42 
     43   EXPECT_TRUE(load_timing_info.socket_reused);
     44   EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
     45 
     46   ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
     47   ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
     48 }
     49 
     50 // Tests the load timing of a stream that's connected and using a fresh
     51 // connection.
     52 void TestLoadTimingNotReused(const HttpStream& stream) {
     53   LoadTimingInfo load_timing_info;
     54   EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info));
     55 
     56   EXPECT_FALSE(load_timing_info.socket_reused);
     57   EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
     58 
     59   ExpectConnectTimingHasTimes(load_timing_info.connect_timing,
     60                               CONNECT_TIMING_HAS_DNS_TIMES);
     61   ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
     62 }
     63 
     64 }  // namespace
     65 
     66 class SpdyHttpStreamTest : public testing::Test,
     67                            public testing::WithParamInterface<NextProto> {
     68  public:
     69   SpdyHttpStreamTest()
     70       : spdy_util_(GetParam()),
     71         session_deps_(GetParam()) {
     72     session_deps_.net_log = &net_log_;
     73   }
     74 
     75   DeterministicSocketData* deterministic_data() {
     76     return deterministic_data_.get();
     77   }
     78 
     79   OrderedSocketData* data() { return data_.get(); }
     80 
     81  protected:
     82   virtual void TearDown() OVERRIDE {
     83     crypto::ECSignatureCreator::SetFactoryForTesting(NULL);
     84     base::MessageLoop::current()->RunUntilIdle();
     85   }
     86 
     87   // Initializes the session using DeterministicSocketData.  It's advisable
     88   // to use this function rather than the OrderedSocketData, since the
     89   // DeterministicSocketData behaves in a reasonable manner.
     90   void InitSessionDeterministic(MockRead* reads, size_t reads_count,
     91                                 MockWrite* writes, size_t writes_count,
     92                                 const SpdySessionKey& key) {
     93     deterministic_data_.reset(
     94         new DeterministicSocketData(reads, reads_count, writes, writes_count));
     95     session_deps_.deterministic_socket_factory->AddSocketDataProvider(
     96         deterministic_data_.get());
     97     http_session_ =
     98         SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
     99     session_ = CreateInsecureSpdySession(http_session_, key, BoundNetLog());
    100   }
    101 
    102   // Initializes the session using the finicky OrderedSocketData class.
    103   void InitSession(MockRead* reads, size_t reads_count,
    104                    MockWrite* writes, size_t writes_count,
    105                    const SpdySessionKey& key) {
    106     data_.reset(new OrderedSocketData(reads, reads_count,
    107                                       writes, writes_count));
    108     session_deps_.socket_factory->AddSocketDataProvider(data_.get());
    109     http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
    110     session_ = CreateInsecureSpdySession(http_session_, key, BoundNetLog());
    111   }
    112 
    113   void TestSendCredentials(
    114     ServerBoundCertService* server_bound_cert_service,
    115     const std::string& cert,
    116     const std::string& proof);
    117 
    118   SpdyTestUtil spdy_util_;
    119   CapturingNetLog net_log_;
    120   SpdySessionDependencies session_deps_;
    121   scoped_ptr<OrderedSocketData> data_;
    122   scoped_ptr<DeterministicSocketData> deterministic_data_;
    123   scoped_refptr<HttpNetworkSession> http_session_;
    124   base::WeakPtr<SpdySession> session_;
    125 
    126  private:
    127   MockECSignatureCreatorFactory ec_signature_creator_factory_;
    128 };
    129 
    130 INSTANTIATE_TEST_CASE_P(
    131     NextProto,
    132     SpdyHttpStreamTest,
    133     testing::Values(kProtoDeprecatedSPDY2,
    134                     kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
    135 
    136 // SpdyHttpStream::GetUploadProgress() should still work even before the
    137 // stream is initialized.
    138 TEST_P(SpdyHttpStreamTest, GetUploadProgressBeforeInitialization) {
    139   MockRead reads[] = {
    140     MockRead(ASYNC, 0, 0)  // EOF
    141   };
    142 
    143   HostPortPair host_port_pair("www.google.com", 80);
    144   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
    145                      PRIVACY_MODE_DISABLED);
    146   InitSession(reads, arraysize(reads), NULL, 0, key);
    147 
    148   SpdyHttpStream stream(session_, false);
    149   UploadProgress progress = stream.GetUploadProgress();
    150   EXPECT_EQ(0u, progress.size());
    151   EXPECT_EQ(0u, progress.position());
    152 
    153   // Pump the event loop so |reads| is consumed before the function returns.
    154   base::RunLoop().RunUntilIdle();
    155 }
    156 
    157 TEST_P(SpdyHttpStreamTest, SendRequest) {
    158   scoped_ptr<SpdyFrame> req(
    159       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
    160   MockWrite writes[] = {
    161     CreateMockWrite(*req.get(), 1),
    162   };
    163   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
    164   MockRead reads[] = {
    165     CreateMockRead(*resp, 2),
    166     MockRead(SYNCHRONOUS, 0, 3)  // EOF
    167   };
    168 
    169   HostPortPair host_port_pair("www.google.com", 80);
    170   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
    171                      PRIVACY_MODE_DISABLED);
    172   InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
    173 
    174   HttpRequestInfo request;
    175   request.method = "GET";
    176   request.url = GURL("http://www.google.com/");
    177   TestCompletionCallback callback;
    178   HttpResponseInfo response;
    179   HttpRequestHeaders headers;
    180   BoundNetLog net_log;
    181   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
    182   // Make sure getting load timing information the stream early does not crash.
    183   LoadTimingInfo load_timing_info;
    184   EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
    185 
    186   ASSERT_EQ(
    187       OK,
    188       http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
    189                                     net_log, CompletionCallback()));
    190   EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
    191 
    192   EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
    193                                                      callback.callback()));
    194   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
    195   EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
    196 
    197   // This triggers the MockWrite and read 2
    198   callback.WaitForResult();
    199 
    200   // Can get timing information once the stream connects.
    201   TestLoadTimingNotReused(*http_stream);
    202 
    203   // This triggers read 3. The empty read causes the session to shut down.
    204   data()->CompleteRead();
    205 
    206   // Because we abandoned the stream, we don't expect to find a session in the
    207   // pool anymore.
    208   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key));
    209   EXPECT_TRUE(data()->at_read_eof());
    210   EXPECT_TRUE(data()->at_write_eof());
    211 
    212   TestLoadTimingNotReused(*http_stream);
    213   http_stream->Close(true);
    214   // Test that there's no crash when trying to get the load timing after the
    215   // stream has been closed.
    216   TestLoadTimingNotReused(*http_stream);
    217 }
    218 
    219 TEST_P(SpdyHttpStreamTest, LoadTimingTwoRequests) {
    220   scoped_ptr<SpdyFrame> req1(
    221       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
    222   scoped_ptr<SpdyFrame> req2(
    223       spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
    224   MockWrite writes[] = {
    225     CreateMockWrite(*req1, 0),
    226     CreateMockWrite(*req2, 1),
    227   };
    228   scoped_ptr<SpdyFrame> resp1(
    229       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
    230   scoped_ptr<SpdyFrame> body1(
    231       spdy_util_.ConstructSpdyBodyFrame(1, "", 0, true));
    232   scoped_ptr<SpdyFrame> resp2(
    233       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
    234   scoped_ptr<SpdyFrame> body2(
    235       spdy_util_.ConstructSpdyBodyFrame(3, "", 0, true));
    236   MockRead reads[] = {
    237     CreateMockRead(*resp1, 2),
    238     CreateMockRead(*body1, 3),
    239     CreateMockRead(*resp2, 4),
    240     CreateMockRead(*body2, 5),
    241     MockRead(ASYNC, 0, 6)  // EOF
    242   };
    243 
    244   HostPortPair host_port_pair("www.google.com", 80);
    245   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
    246                      PRIVACY_MODE_DISABLED);
    247   InitSessionDeterministic(reads, arraysize(reads),
    248                            writes, arraysize(writes),
    249                            key);
    250 
    251   HttpRequestInfo request1;
    252   request1.method = "GET";
    253   request1.url = GURL("http://www.google.com/");
    254   TestCompletionCallback callback1;
    255   HttpResponseInfo response1;
    256   HttpRequestHeaders headers1;
    257   scoped_ptr<SpdyHttpStream> http_stream1(new SpdyHttpStream(session_, true));
    258 
    259   HttpRequestInfo request2;
    260   request2.method = "GET";
    261   request2.url = GURL("http://www.google.com/");
    262   TestCompletionCallback callback2;
    263   HttpResponseInfo response2;
    264   HttpRequestHeaders headers2;
    265   scoped_ptr<SpdyHttpStream> http_stream2(new SpdyHttpStream(session_, true));
    266 
    267   // First write.
    268   ASSERT_EQ(OK,
    269             http_stream1->InitializeStream(&request1, DEFAULT_PRIORITY,
    270                                            BoundNetLog(),
    271                                            CompletionCallback()));
    272   EXPECT_EQ(ERR_IO_PENDING, http_stream1->SendRequest(headers1, &response1,
    273                                                       callback1.callback()));
    274   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
    275 
    276   deterministic_data()->RunFor(1);
    277   EXPECT_LE(0, callback1.WaitForResult());
    278 
    279   TestLoadTimingNotReused(*http_stream1);
    280   LoadTimingInfo load_timing_info1;
    281   LoadTimingInfo load_timing_info2;
    282   EXPECT_TRUE(http_stream1->GetLoadTimingInfo(&load_timing_info1));
    283   EXPECT_FALSE(http_stream2->GetLoadTimingInfo(&load_timing_info2));
    284 
    285   // Second write.
    286   ASSERT_EQ(OK,
    287             http_stream2->InitializeStream(&request2, DEFAULT_PRIORITY,
    288                                            BoundNetLog(),
    289                                            CompletionCallback()));
    290   EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers2, &response2,
    291                                                       callback2.callback()));
    292   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
    293 
    294   deterministic_data()->RunFor(1);
    295   EXPECT_LE(0, callback2.WaitForResult());
    296   TestLoadTimingReused(*http_stream2);
    297   EXPECT_TRUE(http_stream2->GetLoadTimingInfo(&load_timing_info2));
    298   EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
    299 
    300   // All the reads.
    301   deterministic_data()->RunFor(6);
    302 
    303   // Read stream 1 to completion, before making sure we can still read load
    304   // timing from both streams.
    305   scoped_refptr<IOBuffer> buf1(new IOBuffer(1));
    306   ASSERT_EQ(
    307       0, http_stream1->ReadResponseBody(buf1.get(), 1, callback1.callback()));
    308 
    309   // Stream 1 has been read to completion.
    310   TestLoadTimingNotReused(*http_stream1);
    311   // Stream 2 still has queued body data.
    312   TestLoadTimingReused(*http_stream2);
    313 }
    314 
    315 TEST_P(SpdyHttpStreamTest, SendChunkedPost) {
    316   BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
    317 
    318   scoped_ptr<SpdyFrame> req(
    319       spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
    320   scoped_ptr<SpdyFrame> body(
    321       framer.CreateDataFrame(1, kUploadData, kUploadDataSize, DATA_FLAG_FIN));
    322   std::vector<MockWrite> writes;
    323   int seq = 0;
    324   writes.push_back(CreateMockWrite(*req, seq++));
    325   writes.push_back(CreateMockWrite(*body, seq++));  // POST upload frame
    326 
    327   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
    328   std::vector<MockRead> reads;
    329   reads.push_back(CreateMockRead(*resp, seq++));
    330   reads.push_back(CreateMockRead(*body, seq++));
    331   reads.push_back(MockRead(SYNCHRONOUS, 0, seq++));  // EOF
    332 
    333   HostPortPair host_port_pair("www.google.com", 80);
    334   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
    335                      PRIVACY_MODE_DISABLED);
    336   InitSession(vector_as_array(&reads), reads.size(),
    337               vector_as_array(&writes), writes.size(),
    338               key);
    339   EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
    340 
    341   UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
    342   const int kFirstChunkSize = kUploadDataSize/2;
    343   upload_stream.AppendChunk(kUploadData, kFirstChunkSize, false);
    344   upload_stream.AppendChunk(kUploadData + kFirstChunkSize,
    345                             kUploadDataSize - kFirstChunkSize, true);
    346 
    347   HttpRequestInfo request;
    348   request.method = "POST";
    349   request.url = GURL("http://www.google.com/");
    350   request.upload_data_stream = &upload_stream;
    351 
    352   ASSERT_EQ(OK, upload_stream.Init(CompletionCallback()));
    353 
    354   TestCompletionCallback callback;
    355   HttpResponseInfo response;
    356   HttpRequestHeaders headers;
    357   BoundNetLog net_log;
    358   SpdyHttpStream http_stream(session_, true);
    359   ASSERT_EQ(
    360       OK,
    361       http_stream.InitializeStream(&request, DEFAULT_PRIORITY,
    362                                    net_log, CompletionCallback()));
    363 
    364   EXPECT_EQ(ERR_IO_PENDING, http_stream.SendRequest(
    365       headers, &response, callback.callback()));
    366   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
    367 
    368   // This results in writing the post body and reading the response headers.
    369   callback.WaitForResult();
    370 
    371   // This triggers reading the body and the EOF, causing the session to shut
    372   // down.
    373   data()->CompleteRead();
    374   base::MessageLoop::current()->RunUntilIdle();
    375 
    376   // Because we abandoned the stream, we don't expect to find a session in the
    377   // pool anymore.
    378   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key));
    379   EXPECT_TRUE(data()->at_read_eof());
    380   EXPECT_TRUE(data()->at_write_eof());
    381 }
    382 
    383 // Test to ensure the SpdyStream state machine does not get confused when a
    384 // chunk becomes available while a write is pending.
    385 TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPost) {
    386   const char kUploadData1[] = "12345678";
    387   const int kUploadData1Size = arraysize(kUploadData1)-1;
    388   scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
    389   scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, false));
    390   scoped_ptr<SpdyFrame> chunk2(
    391       spdy_util_.ConstructSpdyBodyFrame(
    392           1, kUploadData1, kUploadData1Size, false));
    393   scoped_ptr<SpdyFrame> chunk3(spdy_util_.ConstructSpdyBodyFrame(1, true));
    394   MockWrite writes[] = {
    395     CreateMockWrite(*req.get(), 0),
    396     CreateMockWrite(*chunk1, 1),  // POST upload frames
    397     CreateMockWrite(*chunk2, 2),
    398     CreateMockWrite(*chunk3, 3),
    399   };
    400   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
    401   MockRead reads[] = {
    402     CreateMockRead(*resp, 4),
    403     CreateMockRead(*chunk1, 5),
    404     CreateMockRead(*chunk2, 6),
    405     CreateMockRead(*chunk3, 7),
    406     MockRead(ASYNC, 0, 8)  // EOF
    407   };
    408 
    409   HostPortPair host_port_pair("www.google.com", 80);
    410   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
    411                      PRIVACY_MODE_DISABLED);
    412   InitSessionDeterministic(reads, arraysize(reads),
    413                            writes, arraysize(writes),
    414                            key);
    415 
    416   UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
    417 
    418   HttpRequestInfo request;
    419   request.method = "POST";
    420   request.url = GURL("http://www.google.com/");
    421   request.upload_data_stream = &upload_stream;
    422 
    423   ASSERT_EQ(OK, upload_stream.Init(CompletionCallback()));
    424   upload_stream.AppendChunk(kUploadData, kUploadDataSize, false);
    425 
    426   BoundNetLog net_log;
    427   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
    428   ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
    429                                               net_log, CompletionCallback()));
    430 
    431   TestCompletionCallback callback;
    432   HttpRequestHeaders headers;
    433   HttpResponseInfo response;
    434   // This will attempt to Write() the initial request and headers, which will
    435   // complete asynchronously.
    436   EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
    437                                                      callback.callback()));
    438   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
    439 
    440   // Complete the initial request write and the first chunk.
    441   deterministic_data()->RunFor(2);
    442   ASSERT_TRUE(callback.have_result());
    443   EXPECT_EQ(OK, callback.WaitForResult());
    444 
    445   // Now append the final two chunks which will enqueue two more writes.
    446   upload_stream.AppendChunk(kUploadData1, kUploadData1Size, false);
    447   upload_stream.AppendChunk(kUploadData, kUploadDataSize, true);
    448 
    449   // Finish writing all the chunks.
    450   deterministic_data()->RunFor(2);
    451 
    452   // Read response headers.
    453   deterministic_data()->RunFor(1);
    454   ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
    455 
    456   // Read and check |chunk1| response.
    457   deterministic_data()->RunFor(1);
    458   scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
    459   ASSERT_EQ(kUploadDataSize,
    460             http_stream->ReadResponseBody(
    461                 buf1.get(), kUploadDataSize, callback.callback()));
    462   EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
    463 
    464   // Read and check |chunk2| response.
    465   deterministic_data()->RunFor(1);
    466   scoped_refptr<IOBuffer> buf2(new IOBuffer(kUploadData1Size));
    467   ASSERT_EQ(kUploadData1Size,
    468             http_stream->ReadResponseBody(
    469                 buf2.get(), kUploadData1Size, callback.callback()));
    470   EXPECT_EQ(kUploadData1, std::string(buf2->data(), kUploadData1Size));
    471 
    472   // Read and check |chunk3| response.
    473   deterministic_data()->RunFor(1);
    474   scoped_refptr<IOBuffer> buf3(new IOBuffer(kUploadDataSize));
    475   ASSERT_EQ(kUploadDataSize,
    476             http_stream->ReadResponseBody(
    477                 buf3.get(), kUploadDataSize, callback.callback()));
    478   EXPECT_EQ(kUploadData, std::string(buf3->data(), kUploadDataSize));
    479 
    480   // Finish reading the |EOF|.
    481   deterministic_data()->RunFor(1);
    482   ASSERT_TRUE(response.headers.get());
    483   ASSERT_EQ(200, response.headers->response_code());
    484   EXPECT_TRUE(deterministic_data()->at_read_eof());
    485   EXPECT_TRUE(deterministic_data()->at_write_eof());
    486 }
    487 
    488 // Test case for bug: http://code.google.com/p/chromium/issues/detail?id=50058
    489 TEST_P(SpdyHttpStreamTest, SpdyURLTest) {
    490   const char * const full_url = "http://www.google.com/foo?query=what#anchor";
    491   const char * const base_url = "http://www.google.com/foo?query=what";
    492   scoped_ptr<SpdyFrame> req(
    493       spdy_util_.ConstructSpdyGet(base_url, false, 1, LOWEST));
    494   MockWrite writes[] = {
    495     CreateMockWrite(*req.get(), 1),
    496   };
    497   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
    498   MockRead reads[] = {
    499     CreateMockRead(*resp, 2),
    500     MockRead(SYNCHRONOUS, 0, 3)  // EOF
    501   };
    502 
    503   HostPortPair host_port_pair("www.google.com", 80);
    504   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
    505                      PRIVACY_MODE_DISABLED);
    506   InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
    507 
    508   HttpRequestInfo request;
    509   request.method = "GET";
    510   request.url = GURL(full_url);
    511   TestCompletionCallback callback;
    512   HttpResponseInfo response;
    513   HttpRequestHeaders headers;
    514   BoundNetLog net_log;
    515   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
    516   ASSERT_EQ(OK,
    517             http_stream->InitializeStream(
    518                 &request, DEFAULT_PRIORITY, net_log, CompletionCallback()));
    519 
    520   EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
    521                                                      callback.callback()));
    522 
    523   EXPECT_EQ(base_url, http_stream->stream()->GetUrlFromHeaders().spec());
    524 
    525   // This triggers the MockWrite and read 2
    526   callback.WaitForResult();
    527 
    528   // This triggers read 3. The empty read causes the session to shut down.
    529   data()->CompleteRead();
    530 
    531   // Because we abandoned the stream, we don't expect to find a session in the
    532   // pool anymore.
    533   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key));
    534   EXPECT_TRUE(data()->at_read_eof());
    535   EXPECT_TRUE(data()->at_write_eof());
    536 }
    537 
    538 // The tests below are only for SPDY/3 and above.
    539 
    540 // Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be
    541 // made available is handled correctly.
    542 TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) {
    543   if (GetParam() < kProtoSPDY3)
    544     return;
    545 
    546   scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
    547   scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, true));
    548   MockWrite writes[] = {
    549     CreateMockWrite(*req.get(), 0),
    550     CreateMockWrite(*chunk1, 1),
    551   };
    552   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
    553   scoped_ptr<SpdyFrame> window_update(
    554       spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize));
    555   MockRead reads[] = {
    556     CreateMockRead(*window_update, 2),
    557     CreateMockRead(*resp, 3),
    558     CreateMockRead(*chunk1, 4),
    559     MockRead(ASYNC, 0, 5)  // EOF
    560   };
    561 
    562   HostPortPair host_port_pair("www.google.com", 80);
    563   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
    564                      PRIVACY_MODE_DISABLED);
    565 
    566   InitSessionDeterministic(reads, arraysize(reads),
    567                            writes, arraysize(writes),
    568                            key);
    569 
    570   UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
    571 
    572   HttpRequestInfo request;
    573   request.method = "POST";
    574   request.url = GURL("http://www.google.com/");
    575   request.upload_data_stream = &upload_stream;
    576 
    577   ASSERT_EQ(OK, upload_stream.Init(CompletionCallback()));
    578   upload_stream.AppendChunk(kUploadData, kUploadDataSize, true);
    579 
    580   BoundNetLog net_log;
    581   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
    582   ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
    583                                               net_log, CompletionCallback()));
    584 
    585   HttpRequestHeaders headers;
    586   HttpResponseInfo response;
    587   // This will attempt to Write() the initial request and headers, which will
    588   // complete asynchronously.
    589   TestCompletionCallback callback;
    590   EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
    591                                                      callback.callback()));
    592   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
    593 
    594   // Complete the initial request write and first chunk.
    595   deterministic_data_->RunFor(2);
    596   ASSERT_TRUE(callback.have_result());
    597   EXPECT_EQ(OK, callback.WaitForResult());
    598 
    599   // Verify that the window size has decreased.
    600   ASSERT_TRUE(http_stream->stream() != NULL);
    601   EXPECT_NE(static_cast<int>(kSpdyStreamInitialWindowSize),
    602             http_stream->stream()->send_window_size());
    603 
    604   // Read window update.
    605   deterministic_data_->RunFor(1);
    606 
    607   // Verify the window update.
    608   ASSERT_TRUE(http_stream->stream() != NULL);
    609   EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize),
    610             http_stream->stream()->send_window_size());
    611 
    612   // Read response headers.
    613   deterministic_data_->RunFor(1);
    614   ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
    615 
    616   // Read and check |chunk1| response.
    617   deterministic_data_->RunFor(1);
    618   scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
    619   ASSERT_EQ(kUploadDataSize,
    620             http_stream->ReadResponseBody(
    621                 buf1.get(), kUploadDataSize, callback.callback()));
    622   EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
    623 
    624   // Finish reading the |EOF|.
    625   deterministic_data_->RunFor(1);
    626   ASSERT_TRUE(response.headers.get());
    627   ASSERT_EQ(200, response.headers->response_code());
    628   EXPECT_TRUE(deterministic_data_->at_read_eof());
    629   EXPECT_TRUE(deterministic_data_->at_write_eof());
    630 }
    631 
    632 // TODO(willchan): Write a longer test for SpdyStream that exercises all
    633 // methods.
    634 
    635 }  // namespace net
    636