Home | History | Annotate | Download | only in spdy
      1 // Copyright (c) 2011 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 "base/memory/ref_counted.h"
      6 #include "net/spdy/spdy_stream.h"
      7 #include "net/spdy/spdy_http_utils.h"
      8 #include "net/spdy/spdy_session.h"
      9 #include "net/spdy/spdy_test_util.h"
     10 #include "testing/gtest/include/gtest/gtest.h"
     11 
     12 namespace net {
     13 
     14 // TODO(ukai): factor out common part with spdy_http_stream_unittest.cc
     15 class SpdySessionPoolPeer {
     16  public:
     17   explicit SpdySessionPoolPeer(SpdySessionPool* pool)
     18       : pool_(pool) {}
     19 
     20   void RemoveSpdySession(const scoped_refptr<SpdySession>& session) {
     21     pool_->Remove(session);
     22   }
     23 
     24  private:
     25   SpdySessionPool* const pool_;
     26 
     27   DISALLOW_COPY_AND_ASSIGN(SpdySessionPoolPeer);
     28 };
     29 
     30 namespace {
     31 
     32 class TestSpdyStreamDelegate : public SpdyStream::Delegate {
     33  public:
     34   TestSpdyStreamDelegate(SpdyStream* stream,
     35                          IOBufferWithSize* buf,
     36                          CompletionCallback* callback)
     37       : stream_(stream),
     38         buf_(buf),
     39         callback_(callback),
     40         send_headers_completed_(false),
     41         response_(new spdy::SpdyHeaderBlock),
     42         data_sent_(0),
     43         closed_(false) {}
     44   virtual ~TestSpdyStreamDelegate() {}
     45 
     46   virtual bool OnSendHeadersComplete(int status) {
     47     send_headers_completed_ = true;
     48     return true;
     49   }
     50   virtual int OnSendBody() {
     51     ADD_FAILURE() << "OnSendBody should not be called";
     52     return ERR_UNEXPECTED;
     53   }
     54   virtual int OnSendBodyComplete(int /*status*/, bool* /*eof*/) {
     55     ADD_FAILURE() << "OnSendBodyComplete should not be called";
     56     return ERR_UNEXPECTED;
     57   }
     58 
     59   virtual int OnResponseReceived(const spdy::SpdyHeaderBlock& response,
     60                                  base::Time response_time,
     61                                  int status) {
     62     EXPECT_TRUE(send_headers_completed_);
     63     *response_ = response;
     64     if (buf_) {
     65       EXPECT_EQ(ERR_IO_PENDING,
     66                 stream_->WriteStreamData(buf_.get(), buf_->size(),
     67                                          spdy::DATA_FLAG_NONE));
     68     }
     69     return status;
     70   }
     71   virtual void OnDataReceived(const char* buffer, int bytes) {
     72     received_data_ += std::string(buffer, bytes);
     73   }
     74   virtual void OnDataSent(int length) {
     75     data_sent_ += length;
     76   }
     77   virtual void OnClose(int status) {
     78     closed_ = true;
     79     CompletionCallback* callback = callback_;
     80     callback_ = NULL;
     81     callback->Run(OK);
     82   }
     83   virtual void set_chunk_callback(net::ChunkCallback *) {}
     84 
     85   bool send_headers_completed() const { return send_headers_completed_; }
     86   const linked_ptr<spdy::SpdyHeaderBlock>& response() const {
     87     return response_;
     88   }
     89   const std::string& received_data() const { return received_data_; }
     90   int data_sent() const { return data_sent_; }
     91   bool closed() const {  return closed_; }
     92 
     93  private:
     94   SpdyStream* stream_;
     95   scoped_refptr<IOBufferWithSize> buf_;
     96   CompletionCallback* callback_;
     97   bool send_headers_completed_;
     98   linked_ptr<spdy::SpdyHeaderBlock> response_;
     99   std::string received_data_;
    100   int data_sent_;
    101   bool closed_;
    102 };
    103 
    104 spdy::SpdyFrame* ConstructSpdyBodyFrame(const char* data, int length) {
    105   spdy::SpdyFramer framer;
    106   return framer.CreateDataFrame(1, data, length, spdy::DATA_FLAG_NONE);
    107 }
    108 
    109 }  // anonymous namespace
    110 
    111 class SpdyStreamTest : public testing::Test {
    112  protected:
    113   SpdyStreamTest() {
    114   }
    115 
    116   scoped_refptr<SpdySession> CreateSpdySession() {
    117     spdy::SpdyFramer::set_enable_compression_default(false);
    118     HostPortPair host_port_pair("www.google.com", 80);
    119     HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
    120     scoped_refptr<SpdySession> session(
    121         session_->spdy_session_pool()->Get(pair, BoundNetLog()));
    122     return session;
    123   }
    124 
    125   virtual void TearDown() {
    126     MessageLoop::current()->RunAllPending();
    127   }
    128 
    129   scoped_refptr<HttpNetworkSession> session_;
    130 };
    131 
    132 TEST_F(SpdyStreamTest, SendDataAfterOpen) {
    133   SpdySessionDependencies session_deps;
    134 
    135   session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps);
    136   SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool());
    137 
    138   const SpdyHeaderInfo kSynStartHeader = {
    139     spdy::SYN_STREAM,
    140     1,
    141     0,
    142     net::ConvertRequestPriorityToSpdyPriority(LOWEST),
    143     spdy::CONTROL_FLAG_NONE,
    144     false,
    145     spdy::INVALID,
    146     NULL,
    147     0,
    148     spdy::DATA_FLAG_NONE
    149   };
    150   static const char* const kGetHeaders[] = {
    151     "method",
    152     "GET",
    153     "scheme",
    154     "http",
    155     "host",
    156     "www.google.com",
    157     "path",
    158     "/",
    159     "version",
    160     "HTTP/1.1",
    161   };
    162   scoped_ptr<spdy::SpdyFrame> req(
    163       ConstructSpdyPacket(
    164           kSynStartHeader, NULL, 0, kGetHeaders, arraysize(kGetHeaders) / 2));
    165   scoped_ptr<spdy::SpdyFrame> msg(
    166       ConstructSpdyBodyFrame("\0hello!\xff", 8));
    167   MockWrite writes[] = {
    168     CreateMockWrite(*req),
    169     CreateMockWrite(*msg),
    170   };
    171   writes[0].sequence_number = 0;
    172   writes[1].sequence_number = 2;
    173 
    174   scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
    175   scoped_ptr<spdy::SpdyFrame> echo(
    176       ConstructSpdyBodyFrame("\0hello!\xff", 8));
    177   MockRead reads[] = {
    178     CreateMockRead(*resp),
    179     CreateMockRead(*echo),
    180     MockRead(true, 0, 0), // EOF
    181   };
    182   reads[0].sequence_number = 1;
    183   reads[1].sequence_number = 3;
    184   reads[2].sequence_number = 4;
    185 
    186   scoped_refptr<OrderedSocketData> data(
    187       new OrderedSocketData(reads, arraysize(reads),
    188                             writes, arraysize(writes)));
    189   MockConnect connect_data(false, OK);
    190   data->set_connect_data(connect_data);
    191 
    192   session_deps.socket_factory->AddSocketDataProvider(data.get());
    193   SpdySession::SetSSLMode(false);
    194 
    195   scoped_refptr<SpdySession> session(CreateSpdySession());
    196   const char* kStreamUrl = "http://www.google.com/";
    197   GURL url(kStreamUrl);
    198 
    199   HostPortPair host_port_pair("www.google.com", 80);
    200   scoped_refptr<TransportSocketParams> transport_params(
    201       new TransportSocketParams(host_port_pair, LOWEST, GURL(), false, false));
    202 
    203   scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
    204   EXPECT_EQ(OK,
    205             connection->Init(host_port_pair.ToString(),
    206                              transport_params,
    207                              LOWEST,
    208                              NULL,
    209                              session_->transport_socket_pool(),
    210                              BoundNetLog()));
    211   session->InitializeWithSocket(connection.release(), false, OK);
    212 
    213   scoped_refptr<SpdyStream> stream;
    214   ASSERT_EQ(
    215       OK,
    216       session->CreateStream(url, LOWEST, &stream, BoundNetLog(), NULL));
    217   scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(8));
    218   memcpy(buf->data(), "\0hello!\xff", 8);
    219   TestCompletionCallback callback;
    220 
    221   scoped_ptr<TestSpdyStreamDelegate> delegate(
    222       new TestSpdyStreamDelegate(stream.get(), buf.get(), &callback));
    223   stream->SetDelegate(delegate.get());
    224 
    225   EXPECT_FALSE(stream->HasUrl());
    226 
    227   linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock);
    228   (*headers)["method"] = "GET";
    229   (*headers)["scheme"] = url.scheme();
    230   (*headers)["host"] = url.host();
    231   (*headers)["path"] = url.path();
    232   (*headers)["version"] = "HTTP/1.1";
    233   stream->set_spdy_headers(headers);
    234   EXPECT_TRUE(stream->HasUrl());
    235   EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
    236 
    237   EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(true));
    238 
    239   EXPECT_EQ(OK, callback.WaitForResult());
    240 
    241   EXPECT_TRUE(delegate->send_headers_completed());
    242   EXPECT_EQ("200", (*delegate->response())["status"]);
    243   EXPECT_EQ("HTTP/1.1", (*delegate->response())["version"]);
    244   EXPECT_EQ(std::string("\0hello!\xff", 8), delegate->received_data());
    245   EXPECT_EQ(8, delegate->data_sent());
    246   EXPECT_TRUE(delegate->closed());
    247 }
    248 
    249 TEST_F(SpdyStreamTest, PushedStream) {
    250   const char kStreamUrl[] = "http://www.google.com/";
    251 
    252   SpdySessionDependencies session_deps;
    253   session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps);
    254   SpdySessionPoolPeer pool_peer_(session_->spdy_session_pool());
    255   scoped_refptr<SpdySession> spdy_session(CreateSpdySession());
    256   BoundNetLog net_log;
    257 
    258   // Conjure up a stream.
    259   scoped_refptr<SpdyStream> stream = new SpdyStream(spdy_session,
    260                                                     2,
    261                                                     true,
    262                                                     net_log);
    263   EXPECT_FALSE(stream->response_received());
    264   EXPECT_FALSE(stream->HasUrl());
    265 
    266   // Set a couple of headers.
    267   spdy::SpdyHeaderBlock response;
    268   response["url"] = kStreamUrl;
    269   stream->OnResponseReceived(response);
    270 
    271   // Send some basic headers.
    272   spdy::SpdyHeaderBlock headers;
    273   response["status"] = "200";
    274   response["version"] = "OK";
    275   stream->OnHeaders(headers);
    276 
    277   stream->set_response_received();
    278   EXPECT_TRUE(stream->response_received());
    279   EXPECT_TRUE(stream->HasUrl());
    280   EXPECT_EQ(kStreamUrl, stream->GetUrl().spec());
    281 }
    282 
    283 
    284 }  // namespace net
    285