Home | History | Annotate | Download | only in spdy
      1 // Copyright 2013 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 <cstddef>
      6 #include <string>
      7 #include <vector>
      8 
      9 #include "base/memory/ref_counted.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/stl_util.h"
     12 #include "base/strings/string_piece.h"
     13 #include "net/base/completion_callback.h"
     14 #include "net/base/net_log_unittest.h"
     15 #include "net/base/request_priority.h"
     16 #include "net/socket/next_proto.h"
     17 #include "net/socket/socket_test_util.h"
     18 #include "net/spdy/buffered_spdy_framer.h"
     19 #include "net/spdy/spdy_http_utils.h"
     20 #include "net/spdy/spdy_protocol.h"
     21 #include "net/spdy/spdy_session.h"
     22 #include "net/spdy/spdy_stream.h"
     23 #include "net/spdy/spdy_stream_test_util.h"
     24 #include "net/spdy/spdy_test_util_common.h"
     25 #include "testing/gtest/include/gtest/gtest.h"
     26 
     27 // TODO(ukai): factor out common part with spdy_http_stream_unittest.cc
     28 //
     29 namespace net {
     30 
     31 namespace test {
     32 
     33 namespace {
     34 
     35 const char kStreamUrl[] = "http://www.google.com/";
     36 const char kPostBody[] = "\0hello!\xff";
     37 const size_t kPostBodyLength = arraysize(kPostBody);
     38 const base::StringPiece kPostBodyStringPiece(kPostBody, kPostBodyLength);
     39 
     40 class SpdyStreamTest : public ::testing::Test,
     41                        public ::testing::WithParamInterface<NextProto> {
     42  protected:
     43   // A function that takes a SpdyStream and the number of bytes which
     44   // will unstall the next frame completely.
     45   typedef base::Callback<void(const base::WeakPtr<SpdyStream>&, int32)>
     46       UnstallFunction;
     47 
     48   SpdyStreamTest()
     49       : spdy_util_(GetParam()),
     50         session_deps_(GetParam()),
     51         offset_(0) {}
     52 
     53   base::WeakPtr<SpdySession> CreateDefaultSpdySession() {
     54     SpdySessionKey key(HostPortPair("www.google.com", 80),
     55                        ProxyServer::Direct(),
     56                        kPrivacyModeDisabled);
     57     return CreateInsecureSpdySession(session_, key, BoundNetLog());
     58   }
     59 
     60   virtual void TearDown() {
     61     base::MessageLoop::current()->RunUntilIdle();
     62   }
     63 
     64   void RunResumeAfterUnstallRequestResponseTest(
     65       const UnstallFunction& unstall_function);
     66 
     67   void RunResumeAfterUnstallBidirectionalTest(
     68       const UnstallFunction& unstall_function);
     69 
     70   // Add{Read,Write}() populates lists that are eventually passed to a
     71   // SocketData class. |frame| must live for the whole test.
     72 
     73   void AddRead(const SpdyFrame& frame) {
     74     reads_.push_back(CreateMockRead(frame, offset_++));
     75   }
     76 
     77   void AddWrite(const SpdyFrame& frame) {
     78     writes_.push_back(CreateMockWrite(frame, offset_++));
     79   }
     80 
     81   void AddReadEOF() {
     82     reads_.push_back(MockRead(ASYNC, 0, offset_++));
     83   }
     84 
     85   MockRead* GetReads() {
     86     return vector_as_array(&reads_);
     87   }
     88 
     89   size_t GetNumReads() const {
     90     return reads_.size();
     91   }
     92 
     93   MockWrite* GetWrites() {
     94     return vector_as_array(&writes_);
     95   }
     96 
     97   int GetNumWrites() const {
     98     return writes_.size();
     99   }
    100 
    101   SpdyTestUtil spdy_util_;
    102   SpdySessionDependencies session_deps_;
    103   scoped_refptr<HttpNetworkSession> session_;
    104 
    105  private:
    106   // Used by Add{Read,Write}() above.
    107   std::vector<MockWrite> writes_;
    108   std::vector<MockRead> reads_;
    109   int offset_;
    110 };
    111 
    112 INSTANTIATE_TEST_CASE_P(
    113     NextProto,
    114     SpdyStreamTest,
    115     testing::Values(kProtoDeprecatedSPDY2,
    116                     kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2,
    117                     kProtoHTTP2Draft04));
    118 
    119 TEST_P(SpdyStreamTest, SendDataAfterOpen) {
    120   GURL url(kStreamUrl);
    121 
    122   session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
    123 
    124   scoped_ptr<SpdyFrame> req(
    125       spdy_util_.ConstructSpdyPost(
    126           kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
    127   AddWrite(*req);
    128 
    129   scoped_ptr<SpdyFrame> resp(
    130       spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
    131   AddRead(*resp);
    132 
    133   scoped_ptr<SpdyFrame> msg(
    134       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
    135   AddWrite(*msg);
    136 
    137   scoped_ptr<SpdyFrame> echo(
    138       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
    139   AddRead(*echo);
    140 
    141   AddReadEOF();
    142 
    143   OrderedSocketData data(GetReads(), GetNumReads(),
    144                          GetWrites(), GetNumWrites());
    145   MockConnect connect_data(SYNCHRONOUS, OK);
    146   data.set_connect_data(connect_data);
    147 
    148   session_deps_.socket_factory->AddSocketDataProvider(&data);
    149 
    150   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
    151 
    152   base::WeakPtr<SpdyStream> stream =
    153       CreateStreamSynchronously(
    154           SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
    155   ASSERT_TRUE(stream.get() != NULL);
    156 
    157   StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
    158   stream->SetDelegate(&delegate);
    159 
    160   EXPECT_FALSE(stream->HasUrlFromHeaders());
    161 
    162   scoped_ptr<SpdyHeaderBlock> headers(
    163       spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
    164   EXPECT_EQ(ERR_IO_PENDING,
    165             stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
    166   EXPECT_TRUE(stream->HasUrlFromHeaders());
    167   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
    168 
    169   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
    170 
    171   EXPECT_TRUE(delegate.send_headers_completed());
    172   EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
    173   EXPECT_EQ("HTTP/1.1",
    174             delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
    175   EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
    176             delegate.TakeReceivedData());
    177   EXPECT_TRUE(data.at_write_eof());
    178 }
    179 
    180 TEST_P(SpdyStreamTest, PushedStream) {
    181   session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
    182 
    183   AddReadEOF();
    184 
    185   OrderedSocketData data(GetReads(), GetNumReads(),
    186                          GetWrites(), GetNumWrites());
    187   MockConnect connect_data(SYNCHRONOUS, OK);
    188   data.set_connect_data(connect_data);
    189 
    190   session_deps_.socket_factory->AddSocketDataProvider(&data);
    191 
    192   base::WeakPtr<SpdySession> spdy_session(CreateDefaultSpdySession());
    193 
    194   // Conjure up a stream.
    195   SpdyStream stream(SPDY_PUSH_STREAM,
    196                     spdy_session,
    197                     GURL(),
    198                     DEFAULT_PRIORITY,
    199                     kSpdyStreamInitialWindowSize,
    200                     kSpdyStreamInitialWindowSize,
    201                     BoundNetLog());
    202   stream.set_stream_id(2);
    203   EXPECT_FALSE(stream.HasUrlFromHeaders());
    204 
    205   // Set a couple of headers.
    206   SpdyHeaderBlock response;
    207   spdy_util_.AddUrlToHeaderBlock(kStreamUrl, &response);
    208   stream.OnInitialResponseHeadersReceived(
    209       response, base::Time::Now(), base::TimeTicks::Now());
    210 
    211   // Send some basic headers.
    212   SpdyHeaderBlock headers;
    213   headers[spdy_util_.GetStatusKey()] = "200";
    214   headers[spdy_util_.GetVersionKey()] = "OK";
    215   stream.OnAdditionalResponseHeadersReceived(headers);
    216 
    217   EXPECT_TRUE(stream.HasUrlFromHeaders());
    218   EXPECT_EQ(kStreamUrl, stream.GetUrlFromHeaders().spec());
    219 
    220   StreamDelegateDoNothing delegate(stream.GetWeakPtr());
    221   stream.SetDelegate(&delegate);
    222 
    223   base::MessageLoop::current()->RunUntilIdle();
    224 
    225   EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
    226 
    227   EXPECT_TRUE(spdy_session == NULL);
    228 }
    229 
    230 TEST_P(SpdyStreamTest, StreamError) {
    231   GURL url(kStreamUrl);
    232 
    233   session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
    234 
    235   scoped_ptr<SpdyFrame> req(
    236       spdy_util_.ConstructSpdyPost(
    237           kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
    238   AddWrite(*req);
    239 
    240   scoped_ptr<SpdyFrame> resp(
    241       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
    242   AddRead(*resp);
    243 
    244   scoped_ptr<SpdyFrame> msg(
    245       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
    246   AddWrite(*msg);
    247 
    248   scoped_ptr<SpdyFrame> echo(
    249       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
    250   AddRead(*echo);
    251 
    252   AddReadEOF();
    253 
    254   CapturingBoundNetLog log;
    255 
    256   OrderedSocketData data(GetReads(), GetNumReads(),
    257                          GetWrites(), GetNumWrites());
    258   MockConnect connect_data(SYNCHRONOUS, OK);
    259   data.set_connect_data(connect_data);
    260 
    261   session_deps_.socket_factory->AddSocketDataProvider(&data);
    262 
    263   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
    264 
    265   base::WeakPtr<SpdyStream> stream =
    266       CreateStreamSynchronously(
    267           SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
    268   ASSERT_TRUE(stream.get() != NULL);
    269 
    270   StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
    271   stream->SetDelegate(&delegate);
    272 
    273   EXPECT_FALSE(stream->HasUrlFromHeaders());
    274 
    275   scoped_ptr<SpdyHeaderBlock> headers(
    276       spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
    277   EXPECT_EQ(ERR_IO_PENDING,
    278             stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
    279   EXPECT_TRUE(stream->HasUrlFromHeaders());
    280   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
    281 
    282   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
    283 
    284   const SpdyStreamId stream_id = delegate.stream_id();
    285 
    286   EXPECT_TRUE(delegate.send_headers_completed());
    287   EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
    288   EXPECT_EQ("HTTP/1.1",
    289             delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
    290   EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
    291             delegate.TakeReceivedData());
    292   EXPECT_TRUE(data.at_write_eof());
    293 
    294   // Check that the NetLog was filled reasonably.
    295   net::CapturingNetLog::CapturedEntryList entries;
    296   log.GetEntries(&entries);
    297   EXPECT_LT(0u, entries.size());
    298 
    299   // Check that we logged SPDY_STREAM_ERROR correctly.
    300   int pos = net::ExpectLogContainsSomewhere(
    301       entries, 0,
    302       net::NetLog::TYPE_SPDY_STREAM_ERROR,
    303       net::NetLog::PHASE_NONE);
    304 
    305   int stream_id2;
    306   ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id2));
    307   EXPECT_EQ(static_cast<int>(stream_id), stream_id2);
    308 }
    309 
    310 // Make sure that large blocks of data are properly split up into
    311 // frame-sized chunks for a request/response (i.e., an HTTP-like)
    312 // stream.
    313 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) {
    314   GURL url(kStreamUrl);
    315 
    316   session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
    317 
    318   scoped_ptr<SpdyFrame> req(
    319       spdy_util_.ConstructSpdyPost(
    320           kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
    321   AddWrite(*req);
    322 
    323   std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
    324   scoped_ptr<SpdyFrame> chunk(
    325       spdy_util_.ConstructSpdyBodyFrame(
    326           1, chunk_data.data(), chunk_data.length(), false));
    327   AddWrite(*chunk);
    328   AddWrite(*chunk);
    329 
    330   scoped_ptr<SpdyFrame> last_chunk(
    331       spdy_util_.ConstructSpdyBodyFrame(
    332           1, chunk_data.data(), chunk_data.length(), true));
    333   AddWrite(*last_chunk);
    334 
    335   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
    336   AddRead(*resp);
    337 
    338   AddReadEOF();
    339 
    340   OrderedSocketData data(GetReads(), GetNumReads(),
    341                          GetWrites(), GetNumWrites());
    342   MockConnect connect_data(SYNCHRONOUS, OK);
    343   data.set_connect_data(connect_data);
    344 
    345   session_deps_.socket_factory->AddSocketDataProvider(&data);
    346 
    347   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
    348 
    349   base::WeakPtr<SpdyStream> stream =
    350       CreateStreamSynchronously(
    351           SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
    352   ASSERT_TRUE(stream.get() != NULL);
    353 
    354   std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
    355   StreamDelegateWithBody delegate(stream, body_data);
    356   stream->SetDelegate(&delegate);
    357 
    358   EXPECT_FALSE(stream->HasUrlFromHeaders());
    359 
    360   scoped_ptr<SpdyHeaderBlock> headers(
    361       spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
    362   EXPECT_EQ(ERR_IO_PENDING,
    363             stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
    364   EXPECT_TRUE(stream->HasUrlFromHeaders());
    365   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
    366 
    367   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
    368 
    369   EXPECT_TRUE(delegate.send_headers_completed());
    370   EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
    371   EXPECT_EQ("HTTP/1.1",
    372             delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
    373   EXPECT_EQ(std::string(), delegate.TakeReceivedData());
    374   EXPECT_TRUE(data.at_write_eof());
    375 }
    376 
    377 // Make sure that large blocks of data are properly split up into
    378 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
    379 // stream.
    380 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
    381   GURL url(kStreamUrl);
    382 
    383   session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
    384 
    385   scoped_ptr<SpdyFrame> req(
    386       spdy_util_.ConstructSpdyPost(
    387           kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
    388   AddWrite(*req);
    389 
    390   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
    391   AddRead(*resp);
    392 
    393   std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
    394   scoped_ptr<SpdyFrame> chunk(
    395       spdy_util_.ConstructSpdyBodyFrame(
    396           1, chunk_data.data(), chunk_data.length(), false));
    397   AddWrite(*chunk);
    398   AddWrite(*chunk);
    399   AddWrite(*chunk);
    400 
    401   AddReadEOF();
    402 
    403   OrderedSocketData data(GetReads(), GetNumReads(),
    404                          GetWrites(), GetNumWrites());
    405   MockConnect connect_data(SYNCHRONOUS, OK);
    406   data.set_connect_data(connect_data);
    407 
    408   session_deps_.socket_factory->AddSocketDataProvider(&data);
    409 
    410   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
    411 
    412   base::WeakPtr<SpdyStream> stream =
    413       CreateStreamSynchronously(
    414           SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
    415   ASSERT_TRUE(stream.get() != NULL);
    416 
    417   std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
    418   StreamDelegateSendImmediate delegate(stream, body_data);
    419   stream->SetDelegate(&delegate);
    420 
    421   EXPECT_FALSE(stream->HasUrlFromHeaders());
    422 
    423   scoped_ptr<SpdyHeaderBlock> headers(
    424       spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
    425   EXPECT_EQ(ERR_IO_PENDING,
    426             stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
    427   EXPECT_TRUE(stream->HasUrlFromHeaders());
    428   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
    429 
    430   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
    431 
    432   EXPECT_TRUE(delegate.send_headers_completed());
    433   EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
    434   EXPECT_EQ("HTTP/1.1",
    435             delegate.GetResponseHeaderValue(spdy_util_.GetVersionKey()));
    436   EXPECT_EQ(std::string(), delegate.TakeReceivedData());
    437   EXPECT_TRUE(data.at_write_eof());
    438 }
    439 
    440 // Receiving a header with uppercase ASCII should result in a protocol
    441 // error.
    442 TEST_P(SpdyStreamTest, UpperCaseHeaders) {
    443   GURL url(kStreamUrl);
    444 
    445   session_ =
    446       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
    447 
    448   scoped_ptr<SpdyFrame> syn(
    449       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
    450   AddWrite(*syn);
    451 
    452   const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
    453   scoped_ptr<SpdyFrame>
    454       reply(spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
    455   AddRead(*reply);
    456 
    457   scoped_ptr<SpdyFrame> rst(
    458       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
    459   AddWrite(*rst);
    460 
    461   AddReadEOF();
    462 
    463   DeterministicSocketData data(GetReads(), GetNumReads(),
    464                                GetWrites(), GetNumWrites());
    465   MockConnect connect_data(SYNCHRONOUS, OK);
    466   data.set_connect_data(connect_data);
    467 
    468   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
    469 
    470   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
    471 
    472   base::WeakPtr<SpdyStream> stream =
    473       CreateStreamSynchronously(
    474           SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
    475   ASSERT_TRUE(stream.get() != NULL);
    476 
    477   StreamDelegateDoNothing delegate(stream);
    478   stream->SetDelegate(&delegate);
    479 
    480   EXPECT_FALSE(stream->HasUrlFromHeaders());
    481 
    482   scoped_ptr<SpdyHeaderBlock> headers(
    483       spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
    484   EXPECT_EQ(ERR_IO_PENDING,
    485             stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
    486   EXPECT_TRUE(stream->HasUrlFromHeaders());
    487   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
    488 
    489   data.RunFor(4);
    490 
    491   EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
    492 }
    493 
    494 // Receiving a header with uppercase ASCII should result in a protocol
    495 // error even for a push stream.
    496 TEST_P(SpdyStreamTest, UpperCaseHeadersOnPush) {
    497   GURL url(kStreamUrl);
    498 
    499   session_ =
    500       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
    501 
    502   scoped_ptr<SpdyFrame> syn(
    503       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
    504   AddWrite(*syn);
    505 
    506   scoped_ptr<SpdyFrame>
    507       reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
    508   AddRead(*reply);
    509 
    510   const char* const extra_headers[] = {"X-UpperCase", "yes"};
    511   scoped_ptr<SpdyFrame>
    512       push(spdy_util_.ConstructSpdyPush(extra_headers, 1, 2, 1, kStreamUrl));
    513   AddRead(*push);
    514 
    515   scoped_ptr<SpdyFrame> rst(
    516       spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
    517   AddWrite(*rst);
    518 
    519   AddReadEOF();
    520 
    521   DeterministicSocketData data(GetReads(), GetNumReads(),
    522                                GetWrites(), GetNumWrites());
    523   MockConnect connect_data(SYNCHRONOUS, OK);
    524   data.set_connect_data(connect_data);
    525 
    526   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
    527 
    528   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
    529 
    530   base::WeakPtr<SpdyStream> stream =
    531       CreateStreamSynchronously(
    532           SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
    533   ASSERT_TRUE(stream.get() != NULL);
    534 
    535   StreamDelegateDoNothing delegate(stream);
    536   stream->SetDelegate(&delegate);
    537 
    538   EXPECT_FALSE(stream->HasUrlFromHeaders());
    539 
    540   scoped_ptr<SpdyHeaderBlock> headers(
    541       spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
    542   EXPECT_EQ(ERR_IO_PENDING,
    543             stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
    544   EXPECT_TRUE(stream->HasUrlFromHeaders());
    545   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
    546 
    547   data.RunFor(4);
    548 
    549   base::WeakPtr<SpdyStream> push_stream;
    550   EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
    551   EXPECT_FALSE(push_stream);
    552 
    553   data.RunFor(1);
    554 
    555   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
    556 }
    557 
    558 // Receiving a header with uppercase ASCII in a HEADERS frame should
    559 // result in a protocol error.
    560 TEST_P(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
    561   GURL url(kStreamUrl);
    562 
    563   session_ =
    564       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
    565 
    566   scoped_ptr<SpdyFrame> syn(
    567       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
    568   AddWrite(*syn);
    569 
    570   scoped_ptr<SpdyFrame>
    571       reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
    572   AddRead(*reply);
    573 
    574   scoped_ptr<SpdyFrame>
    575       push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
    576   AddRead(*push);
    577 
    578   scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
    579   (*late_headers)["X-UpperCase"] = "yes";
    580   scoped_ptr<SpdyFrame> headers_frame(
    581       spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
    582                                            false,
    583                                            2,
    584                                            LOWEST,
    585                                            HEADERS,
    586                                            CONTROL_FLAG_NONE,
    587                                            0));
    588   AddRead(*headers_frame);
    589 
    590   scoped_ptr<SpdyFrame> rst(
    591       spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
    592   AddWrite(*rst);
    593 
    594   AddReadEOF();
    595 
    596   DeterministicSocketData data(GetReads(), GetNumReads(),
    597                                GetWrites(), GetNumWrites());
    598   MockConnect connect_data(SYNCHRONOUS, OK);
    599   data.set_connect_data(connect_data);
    600 
    601   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
    602 
    603   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
    604 
    605   base::WeakPtr<SpdyStream> stream =
    606       CreateStreamSynchronously(
    607           SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
    608   ASSERT_TRUE(stream.get() != NULL);
    609 
    610   StreamDelegateDoNothing delegate(stream);
    611   stream->SetDelegate(&delegate);
    612 
    613   EXPECT_FALSE(stream->HasUrlFromHeaders());
    614 
    615   scoped_ptr<SpdyHeaderBlock> headers(
    616       spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
    617   EXPECT_EQ(ERR_IO_PENDING,
    618             stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
    619   EXPECT_TRUE(stream->HasUrlFromHeaders());
    620   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
    621 
    622   data.RunFor(3);
    623 
    624   base::WeakPtr<SpdyStream> push_stream;
    625   EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
    626   EXPECT_TRUE(push_stream);
    627 
    628   data.RunFor(1);
    629 
    630   EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
    631   EXPECT_FALSE(push_stream);
    632 
    633   data.RunFor(2);
    634 
    635   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
    636 }
    637 
    638 // Receiving a duplicate header in a HEADERS frame should result in a
    639 // protocol error.
    640 TEST_P(SpdyStreamTest, DuplicateHeaders) {
    641   GURL url(kStreamUrl);
    642 
    643   session_ =
    644       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
    645 
    646   scoped_ptr<SpdyFrame> syn(
    647       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
    648   AddWrite(*syn);
    649 
    650   scoped_ptr<SpdyFrame>
    651       reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
    652   AddRead(*reply);
    653 
    654   scoped_ptr<SpdyFrame>
    655       push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
    656   AddRead(*push);
    657 
    658   scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
    659   (*late_headers)[spdy_util_.GetStatusKey()] = "500 Server Error";
    660   scoped_ptr<SpdyFrame> headers_frame(
    661       spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
    662                                            false,
    663                                            2,
    664                                            LOWEST,
    665                                            HEADERS,
    666                                            CONTROL_FLAG_NONE,
    667                                            0));
    668   AddRead(*headers_frame);
    669 
    670   scoped_ptr<SpdyFrame> rst(
    671       spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
    672   AddWrite(*rst);
    673 
    674   AddReadEOF();
    675 
    676   DeterministicSocketData data(GetReads(), GetNumReads(),
    677                                GetWrites(), GetNumWrites());
    678   MockConnect connect_data(SYNCHRONOUS, OK);
    679   data.set_connect_data(connect_data);
    680 
    681   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
    682 
    683   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
    684 
    685   base::WeakPtr<SpdyStream> stream =
    686       CreateStreamSynchronously(
    687           SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
    688   ASSERT_TRUE(stream.get() != NULL);
    689 
    690   StreamDelegateDoNothing delegate(stream);
    691   stream->SetDelegate(&delegate);
    692 
    693   EXPECT_FALSE(stream->HasUrlFromHeaders());
    694 
    695   scoped_ptr<SpdyHeaderBlock> headers(
    696       spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
    697   EXPECT_EQ(ERR_IO_PENDING,
    698             stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
    699   EXPECT_TRUE(stream->HasUrlFromHeaders());
    700   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
    701 
    702   data.RunFor(3);
    703 
    704   base::WeakPtr<SpdyStream> push_stream;
    705   EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
    706   EXPECT_TRUE(push_stream);
    707 
    708   data.RunFor(1);
    709 
    710   EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
    711   EXPECT_FALSE(push_stream);
    712 
    713   data.RunFor(2);
    714 
    715   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
    716 }
    717 
    718 // The tests below are only for SPDY/3 and above.
    719 
    720 // Call IncreaseSendWindowSize on a stream with a large enough delta
    721 // to overflow an int32. The SpdyStream should handle that case
    722 // gracefully.
    723 TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
    724   if (spdy_util_.protocol() < kProtoSPDY3)
    725     return;
    726 
    727   session_ =
    728       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
    729 
    730   scoped_ptr<SpdyFrame> req(
    731       spdy_util_.ConstructSpdyPost(
    732           kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
    733   AddWrite(*req);
    734 
    735   // Triggered by the overflowing call to IncreaseSendWindowSize
    736   // below.
    737   scoped_ptr<SpdyFrame> rst(
    738       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
    739   AddWrite(*rst);
    740 
    741   AddReadEOF();
    742 
    743   CapturingBoundNetLog log;
    744 
    745   DeterministicSocketData data(GetReads(), GetNumReads(),
    746                                GetWrites(), GetNumWrites());
    747   MockConnect connect_data(SYNCHRONOUS, OK);
    748   data.set_connect_data(connect_data);
    749 
    750   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
    751 
    752   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
    753   GURL url(kStreamUrl);
    754 
    755   base::WeakPtr<SpdyStream> stream =
    756       CreateStreamSynchronously(
    757           SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound());
    758   ASSERT_TRUE(stream.get() != NULL);
    759   StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
    760   stream->SetDelegate(&delegate);
    761 
    762   scoped_ptr<SpdyHeaderBlock> headers(
    763       spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
    764   EXPECT_EQ(ERR_IO_PENDING,
    765             stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
    766   EXPECT_TRUE(stream->HasUrlFromHeaders());
    767   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
    768 
    769   data.RunFor(1);
    770 
    771   int32 old_send_window_size = stream->send_window_size();
    772   ASSERT_GT(old_send_window_size, 0);
    773   int32 delta_window_size = kint32max - old_send_window_size + 1;
    774   stream->IncreaseSendWindowSize(delta_window_size);
    775   EXPECT_EQ(NULL, stream.get());
    776 
    777   data.RunFor(2);
    778 
    779   EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
    780 }
    781 
    782 // Functions used with
    783 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test().
    784 
    785 void StallStream(const base::WeakPtr<SpdyStream>& stream) {
    786   // Reduce the send window size to 0 to stall.
    787   while (stream->send_window_size() > 0) {
    788     stream->DecreaseSendWindowSize(
    789         std::min(kMaxSpdyFrameChunkSize, stream->send_window_size()));
    790   }
    791 }
    792 
    793 void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
    794                                   int32 delta_window_size) {
    795   EXPECT_TRUE(stream->send_stalled_by_flow_control());
    796   stream->IncreaseSendWindowSize(delta_window_size);
    797   EXPECT_FALSE(stream->send_stalled_by_flow_control());
    798 }
    799 
    800 void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream,
    801                                 int32 delta_window_size) {
    802   // Make sure that negative adjustments are handled properly.
    803   EXPECT_TRUE(stream->send_stalled_by_flow_control());
    804   stream->AdjustSendWindowSize(-delta_window_size);
    805   EXPECT_TRUE(stream->send_stalled_by_flow_control());
    806   stream->AdjustSendWindowSize(+delta_window_size);
    807   EXPECT_TRUE(stream->send_stalled_by_flow_control());
    808   stream->AdjustSendWindowSize(+delta_window_size);
    809   EXPECT_FALSE(stream->send_stalled_by_flow_control());
    810 }
    811 
    812 // Given an unstall function, runs a test to make sure that a
    813 // request/response (i.e., an HTTP-like) stream resumes after a stall
    814 // and unstall.
    815 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
    816     const UnstallFunction& unstall_function) {
    817   GURL url(kStreamUrl);
    818 
    819   session_ =
    820       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
    821 
    822   scoped_ptr<SpdyFrame> req(
    823       spdy_util_.ConstructSpdyPost(
    824           kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
    825   AddWrite(*req);
    826 
    827   scoped_ptr<SpdyFrame> body(
    828       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
    829   AddWrite(*body);
    830 
    831   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
    832   AddRead(*resp);
    833 
    834   AddReadEOF();
    835 
    836   DeterministicSocketData data(GetReads(), GetNumReads(),
    837                                GetWrites(), GetNumWrites());
    838   MockConnect connect_data(SYNCHRONOUS, OK);
    839   data.set_connect_data(connect_data);
    840 
    841   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
    842 
    843   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
    844 
    845   base::WeakPtr<SpdyStream> stream =
    846       CreateStreamSynchronously(
    847           SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
    848   ASSERT_TRUE(stream.get() != NULL);
    849 
    850   StreamDelegateWithBody delegate(stream, kPostBodyStringPiece);
    851   stream->SetDelegate(&delegate);
    852 
    853   EXPECT_FALSE(stream->HasUrlFromHeaders());
    854   EXPECT_FALSE(stream->send_stalled_by_flow_control());
    855 
    856   scoped_ptr<SpdyHeaderBlock> headers(
    857       spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
    858   EXPECT_EQ(ERR_IO_PENDING,
    859             stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
    860   EXPECT_TRUE(stream->HasUrlFromHeaders());
    861   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
    862 
    863   StallStream(stream);
    864 
    865   data.RunFor(1);
    866 
    867   EXPECT_TRUE(stream->send_stalled_by_flow_control());
    868 
    869   unstall_function.Run(stream, kPostBodyLength);
    870 
    871   EXPECT_FALSE(stream->send_stalled_by_flow_control());
    872 
    873   data.RunFor(3);
    874 
    875   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
    876 
    877   EXPECT_TRUE(delegate.send_headers_completed());
    878   EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
    879   EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
    880   EXPECT_EQ(std::string(), delegate.TakeReceivedData());
    881   EXPECT_TRUE(data.at_write_eof());
    882 }
    883 
    884 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
    885   if (spdy_util_.protocol() < kProtoSPDY3)
    886     return;
    887 
    888   RunResumeAfterUnstallRequestResponseTest(
    889       base::Bind(&IncreaseStreamSendWindowSize));
    890 }
    891 
    892 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) {
    893   if (spdy_util_.protocol() < kProtoSPDY3)
    894     return;
    895 
    896   RunResumeAfterUnstallRequestResponseTest(
    897       base::Bind(&AdjustStreamSendWindowSize));
    898 }
    899 
    900 // Given an unstall function, runs a test to make sure that a
    901 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall
    902 // and unstall.
    903 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
    904     const UnstallFunction& unstall_function) {
    905   GURL url(kStreamUrl);
    906 
    907   session_ =
    908       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
    909 
    910   scoped_ptr<SpdyFrame> req(
    911       spdy_util_.ConstructSpdyPost(
    912           kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
    913   AddWrite(*req);
    914 
    915   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
    916   AddRead(*resp);
    917 
    918   scoped_ptr<SpdyFrame> msg(
    919       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
    920   AddWrite(*msg);
    921 
    922   scoped_ptr<SpdyFrame> echo(
    923       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
    924   AddRead(*echo);
    925 
    926   AddReadEOF();
    927 
    928   DeterministicSocketData data(GetReads(), GetNumReads(),
    929                                GetWrites(), GetNumWrites());
    930   MockConnect connect_data(SYNCHRONOUS, OK);
    931   data.set_connect_data(connect_data);
    932 
    933   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
    934 
    935   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
    936 
    937   base::WeakPtr<SpdyStream> stream =
    938       CreateStreamSynchronously(
    939           SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
    940   ASSERT_TRUE(stream.get() != NULL);
    941 
    942   StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
    943   stream->SetDelegate(&delegate);
    944 
    945   EXPECT_FALSE(stream->HasUrlFromHeaders());
    946 
    947   scoped_ptr<SpdyHeaderBlock> headers(
    948       spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
    949   EXPECT_EQ(ERR_IO_PENDING,
    950             stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND));
    951   EXPECT_TRUE(stream->HasUrlFromHeaders());
    952   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
    953 
    954   data.RunFor(1);
    955 
    956   EXPECT_FALSE(stream->send_stalled_by_flow_control());
    957 
    958   StallStream(stream);
    959 
    960   data.RunFor(1);
    961 
    962   EXPECT_TRUE(stream->send_stalled_by_flow_control());
    963 
    964   unstall_function.Run(stream, kPostBodyLength);
    965 
    966   EXPECT_FALSE(stream->send_stalled_by_flow_control());
    967 
    968   data.RunFor(3);
    969 
    970   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
    971 
    972   EXPECT_TRUE(delegate.send_headers_completed());
    973   EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
    974   EXPECT_EQ("HTTP/1.1", delegate.GetResponseHeaderValue(":version"));
    975   EXPECT_EQ(std::string(kPostBody, kPostBodyLength),
    976             delegate.TakeReceivedData());
    977   EXPECT_TRUE(data.at_write_eof());
    978 }
    979 
    980 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) {
    981   if (spdy_util_.protocol() < kProtoSPDY3)
    982     return;
    983 
    984   RunResumeAfterUnstallBidirectionalTest(
    985       base::Bind(&IncreaseStreamSendWindowSize));
    986 }
    987 
    988 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) {
    989   if (spdy_util_.protocol() < kProtoSPDY3)
    990     return;
    991 
    992   RunResumeAfterUnstallBidirectionalTest(
    993       base::Bind(&AdjustStreamSendWindowSize));
    994 }
    995 
    996 // Test calculation of amount of bytes received from network.
    997 TEST_P(SpdyStreamTest, ReceivedBytes) {
    998   GURL url(kStreamUrl);
    999 
   1000   session_ =
   1001       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
   1002 
   1003   scoped_ptr<SpdyFrame> syn(
   1004       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
   1005   AddWrite(*syn);
   1006 
   1007   scoped_ptr<SpdyFrame>
   1008       reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   1009   AddRead(*reply);
   1010 
   1011   scoped_ptr<SpdyFrame> msg(
   1012       spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
   1013   AddRead(*msg);
   1014 
   1015   AddReadEOF();
   1016 
   1017   DeterministicSocketData data(GetReads(), GetNumReads(),
   1018                                GetWrites(), GetNumWrites());
   1019   MockConnect connect_data(SYNCHRONOUS, OK);
   1020   data.set_connect_data(connect_data);
   1021 
   1022   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
   1023 
   1024   base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
   1025 
   1026   base::WeakPtr<SpdyStream> stream =
   1027       CreateStreamSynchronously(
   1028           SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
   1029   ASSERT_TRUE(stream.get() != NULL);
   1030 
   1031   StreamDelegateDoNothing delegate(stream);
   1032   stream->SetDelegate(&delegate);
   1033 
   1034   EXPECT_FALSE(stream->HasUrlFromHeaders());
   1035 
   1036   scoped_ptr<SpdyHeaderBlock> headers(
   1037       spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
   1038   EXPECT_EQ(ERR_IO_PENDING,
   1039             stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND));
   1040   EXPECT_TRUE(stream->HasUrlFromHeaders());
   1041   EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
   1042 
   1043   int64 reply_frame_len = reply->size();
   1044   int64 data_header_len = spdy_util_.CreateFramer()->GetDataFrameMinimumSize();
   1045   int64 data_frame_len = data_header_len + kPostBodyLength;
   1046   int64 response_len = reply_frame_len + data_frame_len;
   1047 
   1048   EXPECT_EQ(0, stream->raw_received_bytes());
   1049   data.RunFor(1); // SYN
   1050   EXPECT_EQ(0, stream->raw_received_bytes());
   1051   data.RunFor(1); // REPLY
   1052   EXPECT_EQ(reply_frame_len, stream->raw_received_bytes());
   1053   data.RunFor(1); // DATA
   1054   EXPECT_EQ(response_len, stream->raw_received_bytes());
   1055   data.RunFor(1); // FIN
   1056 
   1057   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
   1058 }
   1059 
   1060 }  // namespace
   1061 
   1062 }  // namespace test
   1063 
   1064 }  // namespace net
   1065