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/stl_util.h"
     11 #include "base/threading/sequenced_worker_pool.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_credential_builder.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(kProtoSPDY2, 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 namespace {
    536 
    537 void GetECServerBoundCertAndProof(
    538     const std::string& host,
    539     ServerBoundCertService* server_bound_cert_service,
    540     std::string* cert,
    541     std::string* proof) {
    542   TestCompletionCallback callback;
    543   std::string key;
    544   ServerBoundCertService::RequestHandle request_handle;
    545   int rv = server_bound_cert_service->GetDomainBoundCert(
    546       host, &key, cert, callback.callback(),
    547       &request_handle);
    548   EXPECT_EQ(ERR_IO_PENDING, rv);
    549   EXPECT_EQ(OK, callback.WaitForResult());
    550 
    551   SpdyCredential credential;
    552   EXPECT_EQ(OK,
    553             SpdyCredentialBuilder::Build(
    554                 MockClientSocket::kTlsUnique, key, *cert, 2, &credential));
    555 
    556   ASSERT_FALSE(credential.certs.empty());
    557   cert->assign(credential.certs[0]);
    558   proof->assign(credential.proof);
    559 }
    560 
    561 // Constructs a standard SPDY SYN_STREAM frame for a GET request with
    562 // a credential set.
    563 SpdyFrame* ConstructCredentialRequestFrame(NextProto next_proto,
    564                                            size_t slot, const GURL& url,
    565                                            SpdyStreamId stream_id) {
    566   SpdyTestUtil util(next_proto);
    567 
    568   const SpdyHeaderInfo syn_headers = {
    569     SYN_STREAM,
    570     stream_id,
    571     0,
    572     ConvertRequestPriorityToSpdyPriority(LOWEST, 3),
    573     slot,
    574     CONTROL_FLAG_FIN,
    575     false,
    576     RST_STREAM_INVALID,
    577     NULL,
    578     0,
    579     DATA_FLAG_NONE
    580   };
    581 
    582   scoped_ptr<SpdyHeaderBlock> headers(util.ConstructGetHeaderBlock(url.spec()));
    583   return util.ConstructSpdyFrame(syn_headers, headers.Pass());
    584 }
    585 
    586 }  // namespace
    587 
    588 // TODO(rch): When openssl supports server bound certifictes, this
    589 // guard can be removed
    590 #if !defined(USE_OPENSSL)
    591 // Test that if we request a resource for a new origin on a session that
    592 // used domain bound certificates, that we send a CREDENTIAL frame for
    593 // the new domain before we send the new request.
    594 void SpdyHttpStreamTest::TestSendCredentials(
    595     ServerBoundCertService* server_bound_cert_service,
    596     const std::string& cert,
    597     const std::string& proof) {
    598   const char* kUrl1 = "https://www.google.com/";
    599   const char* kUrl2 = "https://www.gmail.com/";
    600 
    601   SpdyCredential cred;
    602   cred.slot = 2;
    603   cred.proof = proof;
    604   cred.certs.push_back(cert);
    605 
    606   scoped_ptr<SpdyFrame> req(ConstructCredentialRequestFrame(
    607       GetParam(), 1, GURL(kUrl1), 1));
    608   scoped_ptr<SpdyFrame> credential(
    609       spdy_util_.ConstructSpdyCredential(cred));
    610   scoped_ptr<SpdyFrame> req2(ConstructCredentialRequestFrame(
    611       GetParam(), 2, GURL(kUrl2), 3));
    612   MockWrite writes[] = {
    613     CreateMockWrite(*req.get(), 0),
    614     CreateMockWrite(*credential.get(), 2),
    615     CreateMockWrite(*req2.get(), 3),
    616   };
    617 
    618   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
    619   scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
    620   MockRead reads[] = {
    621     CreateMockRead(*resp, 1),
    622     CreateMockRead(*resp2, 4),
    623     MockRead(SYNCHRONOUS, 0, 5)  // EOF
    624   };
    625 
    626   HostPortPair host_port_pair(HostPortPair::FromURL(GURL(kUrl1)));
    627   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
    628                      kPrivacyModeDisabled);
    629 
    630   DeterministicMockClientSocketFactory* socket_factory =
    631       session_deps_.deterministic_socket_factory.get();
    632   DeterministicSocketData data(reads, arraysize(reads),
    633                                writes, arraysize(writes));
    634   socket_factory->AddSocketDataProvider(&data);
    635   SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
    636   ssl.channel_id_sent = true;
    637   ssl.server_bound_cert_service = server_bound_cert_service;
    638   ssl.protocol_negotiated = GetParam();
    639   socket_factory->AddSSLSocketDataProvider(&ssl);
    640   http_session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
    641       &session_deps_);
    642   session_ = CreateSecureSpdySession(http_session_, key, BoundNetLog());
    643 
    644   HttpRequestInfo request;
    645   request.method = "GET";
    646   request.url = GURL(kUrl1);
    647   HttpResponseInfo response;
    648   HttpRequestHeaders headers;
    649   BoundNetLog net_log;
    650   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
    651   ASSERT_EQ(
    652       OK,
    653       http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
    654                                     net_log, CompletionCallback()));
    655 
    656   //  EXPECT_FALSE(session_->NeedsCredentials(request.url));
    657   //  GURL new_origin(kUrl2);
    658   //  EXPECT_TRUE(session_->NeedsCredentials(new_origin));
    659 
    660   TestCompletionCallback callback;
    661   EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
    662                                                      callback.callback()));
    663   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
    664 
    665   data.RunFor(2);
    666   callback.WaitForResult();
    667 
    668   // Start up second request for resource on a new origin.
    669   scoped_ptr<SpdyHttpStream> http_stream2(new SpdyHttpStream(session_, true));
    670   request.url = GURL(kUrl2);
    671   ASSERT_EQ(
    672       OK,
    673       http_stream2->InitializeStream(&request, DEFAULT_PRIORITY,
    674                                      net_log, CompletionCallback()));
    675   EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers, &response,
    676                                                       callback.callback()));
    677   data.RunFor(2);
    678   callback.WaitForResult();
    679 
    680   EXPECT_EQ(ERR_IO_PENDING, http_stream2->ReadResponseHeaders(
    681       callback.callback()));
    682   data.RunFor(1);
    683   EXPECT_EQ(OK, callback.WaitForResult());
    684   ASSERT_TRUE(response.headers.get() != NULL);
    685   ASSERT_EQ(200, response.headers->response_code());
    686 }
    687 
    688 // The tests below are only for SPDY/3 and above.
    689 
    690 // Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be
    691 // made available is handled correctly.
    692 TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) {
    693   if (GetParam() < kProtoSPDY3)
    694     return;
    695 
    696   scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
    697   scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, true));
    698   MockWrite writes[] = {
    699     CreateMockWrite(*req.get(), 0),
    700     CreateMockWrite(*chunk1, 1),
    701   };
    702   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
    703   scoped_ptr<SpdyFrame> window_update(
    704       spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize));
    705   MockRead reads[] = {
    706     CreateMockRead(*window_update, 2),
    707     CreateMockRead(*resp, 3),
    708     CreateMockRead(*chunk1, 4),
    709     MockRead(ASYNC, 0, 5)  // EOF
    710   };
    711 
    712   HostPortPair host_port_pair("www.google.com", 80);
    713   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
    714                      kPrivacyModeDisabled);
    715 
    716   InitSessionDeterministic(reads, arraysize(reads),
    717                            writes, arraysize(writes),
    718                            key);
    719 
    720   UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
    721 
    722   HttpRequestInfo request;
    723   request.method = "POST";
    724   request.url = GURL("http://www.google.com/");
    725   request.upload_data_stream = &upload_stream;
    726 
    727   ASSERT_EQ(OK, upload_stream.Init(CompletionCallback()));
    728   upload_stream.AppendChunk(kUploadData, kUploadDataSize, true);
    729 
    730   BoundNetLog net_log;
    731   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
    732   ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
    733                                               net_log, CompletionCallback()));
    734 
    735   HttpRequestHeaders headers;
    736   HttpResponseInfo response;
    737   // This will attempt to Write() the initial request and headers, which will
    738   // complete asynchronously.
    739   TestCompletionCallback callback;
    740   EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
    741                                                      callback.callback()));
    742   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
    743 
    744   // Complete the initial request write and first chunk.
    745   deterministic_data_->RunFor(2);
    746   ASSERT_TRUE(callback.have_result());
    747   EXPECT_EQ(OK, callback.WaitForResult());
    748 
    749   // Verify that the window size has decreased.
    750   ASSERT_TRUE(http_stream->stream() != NULL);
    751   EXPECT_NE(static_cast<int>(kSpdyStreamInitialWindowSize),
    752             http_stream->stream()->send_window_size());
    753 
    754   // Read window update.
    755   deterministic_data_->RunFor(1);
    756 
    757   // Verify the window update.
    758   ASSERT_TRUE(http_stream->stream() != NULL);
    759   EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize),
    760             http_stream->stream()->send_window_size());
    761 
    762   // Read response headers.
    763   deterministic_data_->RunFor(1);
    764   ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
    765 
    766   // Read and check |chunk1| response.
    767   deterministic_data_->RunFor(1);
    768   scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
    769   ASSERT_EQ(kUploadDataSize,
    770             http_stream->ReadResponseBody(
    771                 buf1.get(), kUploadDataSize, callback.callback()));
    772   EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
    773 
    774   // Finish reading the |EOF|.
    775   deterministic_data_->RunFor(1);
    776   ASSERT_TRUE(response.headers.get());
    777   ASSERT_EQ(200, response.headers->response_code());
    778   EXPECT_TRUE(deterministic_data_->at_read_eof());
    779   EXPECT_TRUE(deterministic_data_->at_write_eof());
    780 }
    781 
    782 TEST_P(SpdyHttpStreamTest, SendCredentialsEC) {
    783   if (GetParam() < kProtoSPDY3)
    784     return;
    785 
    786   scoped_refptr<base::SequencedWorkerPool> sequenced_worker_pool =
    787       new base::SequencedWorkerPool(1, "SpdyHttpStreamSpdy3Test");
    788   scoped_ptr<ServerBoundCertService> server_bound_cert_service(
    789       new ServerBoundCertService(new DefaultServerBoundCertStore(NULL),
    790                                  sequenced_worker_pool));
    791   std::string cert;
    792   std::string proof;
    793   GetECServerBoundCertAndProof("www.gmail.com",
    794                                server_bound_cert_service.get(),
    795                                &cert, &proof);
    796 
    797   TestSendCredentials(server_bound_cert_service.get(), cert, proof);
    798 
    799   sequenced_worker_pool->Shutdown();
    800 }
    801 
    802 TEST_P(SpdyHttpStreamTest, DontSendCredentialsForHttpUrlsEC) {
    803   if (GetParam() < kProtoSPDY3)
    804     return;
    805 
    806   scoped_refptr<base::SequencedWorkerPool> sequenced_worker_pool =
    807       new base::SequencedWorkerPool(1, "SpdyHttpStreamSpdy3Test");
    808   scoped_ptr<ServerBoundCertService> server_bound_cert_service(
    809       new ServerBoundCertService(new DefaultServerBoundCertStore(NULL),
    810                                  sequenced_worker_pool));
    811   std::string cert;
    812   std::string proof;
    813   GetECServerBoundCertAndProof("proxy.google.com",
    814                                server_bound_cert_service.get(),
    815                                &cert, &proof);
    816 
    817   const char* kUrl1 = "http://www.google.com/";
    818   const char* kUrl2 = "http://www.gmail.com/";
    819 
    820   SpdyCredential cred;
    821   cred.slot = 2;
    822   cred.proof = proof;
    823   cred.certs.push_back(cert);
    824 
    825   scoped_ptr<SpdyFrame> req(ConstructCredentialRequestFrame(
    826       GetParam(), 0, GURL(kUrl1), 1));
    827   scoped_ptr<SpdyFrame> req2(ConstructCredentialRequestFrame(
    828       GetParam(), 0, GURL(kUrl2), 3));
    829   MockWrite writes[] = {
    830     CreateMockWrite(*req.get(), 0),
    831     CreateMockWrite(*req2.get(), 2),
    832   };
    833 
    834   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
    835   scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
    836   MockRead reads[] = {
    837     CreateMockRead(*resp, 1),
    838     CreateMockRead(*resp2, 3),
    839     MockRead(ASYNC, 0, 4)  // EOF
    840   };
    841 
    842   HostPortPair host_port_pair(HostPortPair::FromURL(GURL(kUrl1)));
    843   SpdySessionKey key(host_port_pair,
    844                      ProxyServer::FromURI("proxy.google.com",
    845                                           ProxyServer::SCHEME_HTTPS),
    846                      kPrivacyModeDisabled);
    847   InitSessionDeterministic(reads, arraysize(reads),
    848                            writes, arraysize(writes),
    849                            key);
    850 
    851   HttpRequestInfo request;
    852   request.method = "GET";
    853   request.url = GURL(kUrl1);
    854   HttpResponseInfo response;
    855   HttpRequestHeaders headers;
    856   BoundNetLog net_log;
    857   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
    858   ASSERT_EQ(
    859       OK,
    860       http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
    861                                     net_log, CompletionCallback()));
    862 
    863   TestCompletionCallback callback;
    864   EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
    865                                                      callback.callback()));
    866   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
    867 
    868   deterministic_data_->RunFor(2);
    869   EXPECT_EQ(OK, callback.WaitForResult());
    870 
    871   // Start up second request for resource on a new origin.
    872   scoped_ptr<SpdyHttpStream> http_stream2(new SpdyHttpStream(session_, true));
    873   request.url = GURL(kUrl2);
    874   ASSERT_EQ(
    875       OK,
    876       http_stream2->InitializeStream(&request, DEFAULT_PRIORITY,
    877                                      net_log, CompletionCallback()));
    878   EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers, &response,
    879                                                       callback.callback()));
    880   deterministic_data_->RunFor(1);
    881   EXPECT_EQ(OK, callback.WaitForResult());
    882 
    883   EXPECT_EQ(ERR_IO_PENDING, http_stream2->ReadResponseHeaders(
    884       callback.callback()));
    885   deterministic_data_->RunFor(1);
    886   EXPECT_EQ(OK, callback.WaitForResult());
    887   ASSERT_TRUE(response.headers.get() != NULL);
    888   ASSERT_EQ(200, response.headers->response_code());
    889   deterministic_data_->RunFor(1);
    890   sequenced_worker_pool->Shutdown();
    891 }
    892 
    893 #endif  // !defined(USE_OPENSSL)
    894 
    895 // TODO(willchan): Write a longer test for SpdyStream that exercises all
    896 // methods.
    897 
    898 }  // namespace net
    899