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 "net/spdy/spdy_http_stream.h"
      6 #include "net/spdy/spdy_session.h"
      7 #include "net/spdy/spdy_test_util.h"
      8 #include "testing/gtest/include/gtest/gtest.h"
      9 
     10 namespace net {
     11 
     12 class SpdyHttpStreamTest : public testing::Test {
     13  public:
     14   OrderedSocketData* data() { return data_; }
     15  protected:
     16   SpdyHttpStreamTest() {}
     17 
     18   void EnableCompression(bool enabled) {
     19     spdy::SpdyFramer::set_enable_compression_default(enabled);
     20   }
     21 
     22   virtual void TearDown() {
     23     MessageLoop::current()->RunAllPending();
     24   }
     25   int InitSession(MockRead* reads, size_t reads_count,
     26                   MockWrite* writes, size_t writes_count,
     27                   HostPortPair& host_port_pair) {
     28     HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
     29     data_ = new OrderedSocketData(reads, reads_count, writes, writes_count);
     30     session_deps_.socket_factory->AddSocketDataProvider(data_.get());
     31     http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
     32     session_ = http_session_->spdy_session_pool()->Get(pair, BoundNetLog());
     33     transport_params_ = new TransportSocketParams(host_port_pair,
     34                                       MEDIUM, GURL(), false, false);
     35     TestCompletionCallback callback;
     36     scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
     37     EXPECT_EQ(ERR_IO_PENDING,
     38               connection->Init(host_port_pair.ToString(),
     39                                 transport_params_,
     40                                 MEDIUM,
     41                                 &callback,
     42                                 http_session_->transport_socket_pool(),
     43                                 BoundNetLog()));
     44     EXPECT_EQ(OK, callback.WaitForResult());
     45     return session_->InitializeWithSocket(connection.release(), false, OK);
     46   }
     47   SpdySessionDependencies session_deps_;
     48   scoped_refptr<OrderedSocketData> data_;
     49   scoped_refptr<HttpNetworkSession> http_session_;
     50   scoped_refptr<SpdySession> session_;
     51   scoped_refptr<TransportSocketParams> transport_params_;
     52 };
     53 
     54 TEST_F(SpdyHttpStreamTest, SendRequest) {
     55   EnableCompression(false);
     56   SpdySession::SetSSLMode(false);
     57 
     58   scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
     59   MockWrite writes[] = {
     60     CreateMockWrite(*req.get(), 1),
     61   };
     62   scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
     63   MockRead reads[] = {
     64     CreateMockRead(*resp, 2),
     65     MockRead(false, 0, 3)  // EOF
     66   };
     67 
     68   HostPortPair host_port_pair("www.google.com", 80);
     69   HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
     70   EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
     71       host_port_pair));
     72 
     73   HttpRequestInfo request;
     74   request.method = "GET";
     75   request.url = GURL("http://www.google.com/");
     76   TestCompletionCallback callback;
     77   HttpResponseInfo response;
     78   HttpRequestHeaders headers;
     79   BoundNetLog net_log;
     80   scoped_ptr<SpdyHttpStream> http_stream(
     81       new SpdyHttpStream(session_.get(), true));
     82   ASSERT_EQ(
     83       OK,
     84       http_stream->InitializeStream(&request, net_log, NULL));
     85 
     86   EXPECT_EQ(ERR_IO_PENDING,
     87             http_stream->SendRequest(headers, NULL, &response, &callback));
     88   EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
     89 
     90   // This triggers the MockWrite and read 2
     91   callback.WaitForResult();
     92 
     93   // This triggers read 3. The empty read causes the session to shut down.
     94   data()->CompleteRead();
     95 
     96   // Because we abandoned the stream, we don't expect to find a session in the
     97   // pool anymore.
     98   EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
     99   EXPECT_TRUE(data()->at_read_eof());
    100   EXPECT_TRUE(data()->at_write_eof());
    101 }
    102 
    103 TEST_F(SpdyHttpStreamTest, SendChunkedPost) {
    104   EnableCompression(false);
    105   SpdySession::SetSSLMode(false);
    106   UploadDataStream::set_merge_chunks(false);
    107 
    108   scoped_ptr<spdy::SpdyFrame> req(ConstructChunkedSpdyPost(NULL, 0));
    109   scoped_ptr<spdy::SpdyFrame> chunk1(ConstructSpdyBodyFrame(1, false));
    110   scoped_ptr<spdy::SpdyFrame> chunk2(ConstructSpdyBodyFrame(1, true));
    111   MockWrite writes[] = {
    112     CreateMockWrite(*req.get(), 1),
    113     CreateMockWrite(*chunk1, 2),  // POST upload frames
    114     CreateMockWrite(*chunk2, 3),
    115   };
    116   scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
    117   MockRead reads[] = {
    118     CreateMockRead(*resp, 4),
    119     CreateMockRead(*chunk1, 5),
    120     CreateMockRead(*chunk2, 5),
    121     MockRead(false, 0, 6)  // EOF
    122   };
    123 
    124   HostPortPair host_port_pair("www.google.com", 80);
    125   HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
    126   EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
    127                             host_port_pair));
    128 
    129   HttpRequestInfo request;
    130   request.method = "POST";
    131   request.url = GURL("http://www.google.com/");
    132   request.upload_data = new UploadData();
    133   request.upload_data->set_is_chunked(true);
    134   request.upload_data->AppendChunk(kUploadData, kUploadDataSize, false);
    135   request.upload_data->AppendChunk(kUploadData, kUploadDataSize, true);
    136   TestCompletionCallback callback;
    137   HttpResponseInfo response;
    138   HttpRequestHeaders headers;
    139   BoundNetLog net_log;
    140   SpdyHttpStream http_stream(session_.get(), true);
    141   ASSERT_EQ(
    142       OK,
    143       http_stream.InitializeStream(&request, net_log, NULL));
    144 
    145   UploadDataStream* upload_stream =
    146       UploadDataStream::Create(request.upload_data, NULL);
    147   EXPECT_EQ(ERR_IO_PENDING, http_stream.SendRequest(
    148       headers, upload_stream, &response, &callback));
    149   EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
    150 
    151   // This triggers the MockWrite and read 2
    152   callback.WaitForResult();
    153 
    154   // This triggers read 3. The empty read causes the session to shut down.
    155   data()->CompleteRead();
    156   MessageLoop::current()->RunAllPending();
    157 
    158   // Because we abandoned the stream, we don't expect to find a session in the
    159   // pool anymore.
    160   EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
    161   EXPECT_TRUE(data()->at_read_eof());
    162   EXPECT_TRUE(data()->at_write_eof());
    163 }
    164 
    165 // Test case for bug: http://code.google.com/p/chromium/issues/detail?id=50058
    166 TEST_F(SpdyHttpStreamTest, SpdyURLTest) {
    167   EnableCompression(false);
    168   SpdySession::SetSSLMode(false);
    169 
    170   const char * const full_url = "http://www.google.com/foo?query=what#anchor";
    171   const char * const base_url = "http://www.google.com/foo?query=what";
    172   scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(base_url, false, 1, LOWEST));
    173   MockWrite writes[] = {
    174     CreateMockWrite(*req.get(), 1),
    175   };
    176   scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
    177   MockRead reads[] = {
    178     CreateMockRead(*resp, 2),
    179     MockRead(false, 0, 3)  // EOF
    180   };
    181 
    182   HostPortPair host_port_pair("www.google.com", 80);
    183   HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
    184   EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
    185       host_port_pair));
    186 
    187   HttpRequestInfo request;
    188   request.method = "GET";
    189   request.url = GURL(full_url);
    190   TestCompletionCallback callback;
    191   HttpResponseInfo response;
    192   HttpRequestHeaders headers;
    193   BoundNetLog net_log;
    194   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
    195   ASSERT_EQ(
    196       OK,
    197       http_stream->InitializeStream(&request, net_log, NULL));
    198 
    199   EXPECT_EQ(ERR_IO_PENDING,
    200             http_stream->SendRequest(headers, NULL, &response, &callback));
    201 
    202   spdy::SpdyHeaderBlock* spdy_header =
    203     http_stream->stream()->spdy_headers().get();
    204   EXPECT_TRUE(spdy_header != NULL);
    205   if (spdy_header->find("url") != spdy_header->end())
    206     EXPECT_EQ("/foo?query=what", spdy_header->find("url")->second);
    207   else
    208     FAIL() << "No url is set in spdy_header!";
    209 
    210   // This triggers the MockWrite and read 2
    211   callback.WaitForResult();
    212 
    213   // This triggers read 3. The empty read causes the session to shut down.
    214   data()->CompleteRead();
    215 
    216   // Because we abandoned the stream, we don't expect to find a session in the
    217   // pool anymore.
    218   EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
    219   EXPECT_TRUE(data()->at_read_eof());
    220   EXPECT_TRUE(data()->at_write_eof());
    221 }
    222 
    223 // TODO(willchan): Write a longer test for SpdyStream that exercises all
    224 // methods.
    225 
    226 }  // namespace net
    227