Home | History | Annotate | Download | only in http
      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/http/http_pipelined_host_pool.h"
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "base/rand_util.h"
      9 #include "net/http/http_pipelined_host.h"
     10 #include "net/http/http_pipelined_host_capability.h"
     11 #include "net/http/http_server_properties_impl.h"
     12 #include "net/proxy/proxy_info.h"
     13 #include "net/ssl/ssl_config_service.h"
     14 #include "testing/gmock/include/gmock/gmock.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 
     17 using testing::_;
     18 using testing::Ref;
     19 using testing::Return;
     20 using testing::ReturnNull;
     21 
     22 namespace net {
     23 
     24 namespace {
     25 
     26 ClientSocketHandle* kDummyConnection =
     27     reinterpret_cast<ClientSocketHandle*>(188);
     28 HttpPipelinedStream* kDummyStream =
     29     reinterpret_cast<HttpPipelinedStream*>(99);
     30 
     31 class MockPoolDelegate : public HttpPipelinedHostPool::Delegate {
     32  public:
     33   MOCK_METHOD1(OnHttpPipelinedHostHasAdditionalCapacity,
     34                void(HttpPipelinedHost* host));
     35 };
     36 
     37 class MockHostFactory : public HttpPipelinedHost::Factory {
     38  public:
     39   MOCK_METHOD5(CreateNewHost, HttpPipelinedHost*(
     40       HttpPipelinedHost::Delegate* delegate,
     41       const HttpPipelinedHost::Key& key,
     42       HttpPipelinedConnection::Factory* factory,
     43       HttpPipelinedHostCapability capability,
     44       bool force_pipelining));
     45 };
     46 
     47 class MockHost : public HttpPipelinedHost {
     48  public:
     49   MockHost(const Key& key)
     50       : key_(key) {
     51   }
     52 
     53   MOCK_METHOD6(CreateStreamOnNewPipeline, HttpPipelinedStream*(
     54       ClientSocketHandle* connection,
     55       const SSLConfig& used_ssl_config,
     56       const ProxyInfo& used_proxy_info,
     57       const BoundNetLog& net_log,
     58       bool was_npn_negotiated,
     59       NextProto protocol_negotiated));
     60   MOCK_METHOD0(CreateStreamOnExistingPipeline, HttpPipelinedStream*());
     61   MOCK_CONST_METHOD0(IsExistingPipelineAvailable, bool());
     62   MOCK_CONST_METHOD0(PipelineInfoToValue, base::Value*());
     63 
     64   virtual const Key& GetKey() const OVERRIDE { return key_; }
     65 
     66  private:
     67   Key key_;
     68 };
     69 
     70 class HttpPipelinedHostPoolTest : public testing::Test {
     71  public:
     72   HttpPipelinedHostPoolTest()
     73       : key_(HostPortPair("host", 123)),
     74         factory_(new MockHostFactory),  // Owned by pool_.
     75         host_(new MockHost(key_)),  // Owned by pool_.
     76         http_server_properties_(new HttpServerPropertiesImpl()),
     77         pool_(new HttpPipelinedHostPool(
     78             &delegate_, factory_,
     79             http_server_properties_->GetWeakPtr(), false)),
     80         was_npn_negotiated_(false),
     81         protocol_negotiated_(kProtoUnknown) {
     82   }
     83 
     84   void CreateDummyStream(const HttpPipelinedHost::Key& key,
     85                          ClientSocketHandle* connection,
     86                          HttpPipelinedStream* stream,
     87                          MockHost* host) {
     88     EXPECT_CALL(*host, CreateStreamOnNewPipeline(connection,
     89                                                  Ref(ssl_config_),
     90                                                  Ref(proxy_info_),
     91                                                  Ref(net_log_),
     92                                                  was_npn_negotiated_,
     93                                                  protocol_negotiated_))
     94         .Times(1)
     95         .WillOnce(Return(stream));
     96     EXPECT_EQ(stream,
     97               pool_->CreateStreamOnNewPipeline(key, connection,
     98                                                ssl_config_, proxy_info_,
     99                                                net_log_, was_npn_negotiated_,
    100                                                protocol_negotiated_));
    101   }
    102 
    103   MockHost* CreateDummyHost(const HttpPipelinedHost::Key& key) {
    104     MockHost* mock_host = new MockHost(key);
    105     EXPECT_CALL(*factory_, CreateNewHost(pool_.get(), Ref(key), _,
    106                                          PIPELINE_UNKNOWN, false))
    107         .Times(1)
    108         .WillOnce(Return(mock_host));
    109     ClientSocketHandle* dummy_connection =
    110         reinterpret_cast<ClientSocketHandle*>(base::RandUint64());
    111     HttpPipelinedStream* dummy_stream =
    112         reinterpret_cast<HttpPipelinedStream*>(base::RandUint64());
    113     CreateDummyStream(key, dummy_connection, dummy_stream, mock_host);
    114     return mock_host;
    115   }
    116 
    117   HttpPipelinedHost::Key key_;
    118   MockPoolDelegate delegate_;
    119   MockHostFactory* factory_;
    120   MockHost* host_;
    121   scoped_ptr<HttpServerPropertiesImpl> http_server_properties_;
    122   scoped_ptr<HttpPipelinedHostPool> pool_;
    123 
    124   const SSLConfig ssl_config_;
    125   const ProxyInfo proxy_info_;
    126   const BoundNetLog net_log_;
    127   bool was_npn_negotiated_;
    128   NextProto protocol_negotiated_;
    129 };
    130 
    131 TEST_F(HttpPipelinedHostPoolTest, DefaultUnknown) {
    132   EXPECT_TRUE(pool_->IsKeyEligibleForPipelining(key_));
    133   EXPECT_CALL(*factory_, CreateNewHost(pool_.get(), Ref(key_), _,
    134                                        PIPELINE_UNKNOWN, false))
    135       .Times(1)
    136       .WillOnce(Return(host_));
    137 
    138   CreateDummyStream(key_, kDummyConnection, kDummyStream, host_);
    139   pool_->OnHostIdle(host_);
    140 }
    141 
    142 TEST_F(HttpPipelinedHostPoolTest, RemembersIncapable) {
    143   EXPECT_CALL(*factory_, CreateNewHost(pool_.get(), Ref(key_), _,
    144                                        PIPELINE_UNKNOWN, false))
    145       .Times(1)
    146       .WillOnce(Return(host_));
    147 
    148   CreateDummyStream(key_, kDummyConnection, kDummyStream, host_);
    149   pool_->OnHostDeterminedCapability(host_, PIPELINE_INCAPABLE);
    150   pool_->OnHostIdle(host_);
    151   EXPECT_FALSE(pool_->IsKeyEligibleForPipelining(key_));
    152   EXPECT_CALL(*factory_, CreateNewHost(pool_.get(), Ref(key_), _,
    153                                        PIPELINE_INCAPABLE, false))
    154       .Times(0);
    155   EXPECT_EQ(NULL,
    156             pool_->CreateStreamOnNewPipeline(key_, kDummyConnection,
    157                                              ssl_config_, proxy_info_, net_log_,
    158                                              was_npn_negotiated_,
    159                                              protocol_negotiated_));
    160 }
    161 
    162 TEST_F(HttpPipelinedHostPoolTest, RemembersCapable) {
    163   EXPECT_CALL(*factory_, CreateNewHost(pool_.get(), Ref(key_), _,
    164                                        PIPELINE_UNKNOWN, false))
    165       .Times(1)
    166       .WillOnce(Return(host_));
    167 
    168   CreateDummyStream(key_, kDummyConnection, kDummyStream, host_);
    169   pool_->OnHostDeterminedCapability(host_, PIPELINE_CAPABLE);
    170   pool_->OnHostIdle(host_);
    171   EXPECT_TRUE(pool_->IsKeyEligibleForPipelining(key_));
    172 
    173   host_ = new MockHost(key_);
    174   EXPECT_CALL(*factory_, CreateNewHost(pool_.get(), Ref(key_), _,
    175                                        PIPELINE_CAPABLE, false))
    176       .Times(1)
    177       .WillOnce(Return(host_));
    178   CreateDummyStream(key_, kDummyConnection, kDummyStream, host_);
    179   pool_->OnHostIdle(host_);
    180 }
    181 
    182 TEST_F(HttpPipelinedHostPoolTest, IncapableIsSticky) {
    183   EXPECT_CALL(*factory_, CreateNewHost(pool_.get(), Ref(key_), _,
    184                                        PIPELINE_UNKNOWN, false))
    185       .Times(1)
    186       .WillOnce(Return(host_));
    187 
    188   CreateDummyStream(key_, kDummyConnection, kDummyStream, host_);
    189   pool_->OnHostDeterminedCapability(host_, PIPELINE_CAPABLE);
    190   pool_->OnHostDeterminedCapability(host_, PIPELINE_INCAPABLE);
    191   pool_->OnHostDeterminedCapability(host_, PIPELINE_CAPABLE);
    192   pool_->OnHostIdle(host_);
    193   EXPECT_FALSE(pool_->IsKeyEligibleForPipelining(key_));
    194 }
    195 
    196 TEST_F(HttpPipelinedHostPoolTest, RemainsUnknownWithoutFeedback) {
    197   EXPECT_CALL(*factory_, CreateNewHost(pool_.get(), Ref(key_), _,
    198                                        PIPELINE_UNKNOWN, false))
    199       .Times(1)
    200       .WillOnce(Return(host_));
    201 
    202   CreateDummyStream(key_, kDummyConnection, kDummyStream, host_);
    203   pool_->OnHostIdle(host_);
    204   EXPECT_TRUE(pool_->IsKeyEligibleForPipelining(key_));
    205 
    206   host_ = new MockHost(key_);
    207   EXPECT_CALL(*factory_, CreateNewHost(pool_.get(), Ref(key_), _,
    208                                        PIPELINE_UNKNOWN, false))
    209       .Times(1)
    210       .WillOnce(Return(host_));
    211 
    212   CreateDummyStream(key_, kDummyConnection, kDummyStream, host_);
    213   pool_->OnHostIdle(host_);
    214 }
    215 
    216 TEST_F(HttpPipelinedHostPoolTest, PopulatesServerProperties) {
    217   EXPECT_EQ(PIPELINE_UNKNOWN,
    218             http_server_properties_->GetPipelineCapability(
    219                 host_->GetKey().origin()));
    220   pool_->OnHostDeterminedCapability(host_, PIPELINE_CAPABLE);
    221   EXPECT_EQ(PIPELINE_CAPABLE,
    222             http_server_properties_->GetPipelineCapability(
    223                 host_->GetKey().origin()));
    224   delete host_;  // Must manually delete, because it's never added to |pool_|.
    225 }
    226 
    227 TEST_F(HttpPipelinedHostPoolTest, MultipleKeys) {
    228   HttpPipelinedHost::Key key1(HostPortPair("host", 123));
    229   HttpPipelinedHost::Key key2(HostPortPair("host", 456));
    230   HttpPipelinedHost::Key key3(HostPortPair("other", 456));
    231   HttpPipelinedHost::Key key4(HostPortPair("other", 789));
    232   MockHost* host1 = CreateDummyHost(key1);
    233   MockHost* host2 = CreateDummyHost(key2);
    234   MockHost* host3 = CreateDummyHost(key3);
    235 
    236   EXPECT_CALL(*host1, IsExistingPipelineAvailable())
    237       .Times(1)
    238       .WillOnce(Return(true));
    239   EXPECT_TRUE(pool_->IsExistingPipelineAvailableForKey(key1));
    240 
    241   EXPECT_CALL(*host2, IsExistingPipelineAvailable())
    242       .Times(1)
    243       .WillOnce(Return(false));
    244   EXPECT_FALSE(pool_->IsExistingPipelineAvailableForKey(key2));
    245 
    246   EXPECT_CALL(*host3, IsExistingPipelineAvailable())
    247       .Times(1)
    248       .WillOnce(Return(true));
    249   EXPECT_TRUE(pool_->IsExistingPipelineAvailableForKey(key3));
    250 
    251   EXPECT_FALSE(pool_->IsExistingPipelineAvailableForKey(key4));
    252 
    253   pool_->OnHostIdle(host1);
    254   pool_->OnHostIdle(host2);
    255   pool_->OnHostIdle(host3);
    256 
    257   delete host_;  // Must manually delete, because it's never added to |pool_|.
    258 }
    259 
    260 }  // anonymous namespace
    261 
    262 }  // namespace net
    263