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