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/logging.h"
8#include "base/stl_util.h"
9#include "base/values.h"
10#include "net/http/http_pipelined_host_capability.h"
11#include "net/http/http_pipelined_host_forced.h"
12#include "net/http/http_pipelined_host_impl.h"
13#include "net/http/http_server_properties.h"
14
15namespace net {
16
17class HttpPipelinedHostImplFactory : public HttpPipelinedHost::Factory {
18 public:
19  virtual HttpPipelinedHost* CreateNewHost(
20      HttpPipelinedHost::Delegate* delegate,
21      const HttpPipelinedHost::Key& key,
22      HttpPipelinedConnection::Factory* factory,
23      HttpPipelinedHostCapability capability,
24      bool force_pipelining) OVERRIDE {
25    if (force_pipelining) {
26      return new HttpPipelinedHostForced(delegate, key, factory);
27    } else {
28      return new HttpPipelinedHostImpl(delegate, key, factory, capability);
29    }
30  }
31};
32
33HttpPipelinedHostPool::HttpPipelinedHostPool(
34    Delegate* delegate,
35    HttpPipelinedHost::Factory* factory,
36    const base::WeakPtr<HttpServerProperties>& http_server_properties,
37    bool force_pipelining)
38    : delegate_(delegate),
39      factory_(factory),
40      http_server_properties_(http_server_properties),
41      force_pipelining_(force_pipelining) {
42  if (!factory) {
43    factory_.reset(new HttpPipelinedHostImplFactory);
44  }
45}
46
47HttpPipelinedHostPool::~HttpPipelinedHostPool() {
48  CHECK(host_map_.empty());
49}
50
51bool HttpPipelinedHostPool::IsKeyEligibleForPipelining(
52    const HttpPipelinedHost::Key& key) {
53  HttpPipelinedHostCapability capability =
54      http_server_properties_->GetPipelineCapability(key.origin());
55  return capability != PIPELINE_INCAPABLE;
56}
57
58HttpPipelinedStream* HttpPipelinedHostPool::CreateStreamOnNewPipeline(
59    const HttpPipelinedHost::Key& key,
60    ClientSocketHandle* connection,
61    const SSLConfig& used_ssl_config,
62    const ProxyInfo& used_proxy_info,
63    const BoundNetLog& net_log,
64    bool was_npn_negotiated,
65    NextProto protocol_negotiated) {
66  HttpPipelinedHost* host = GetPipelinedHost(key, true);
67  if (!host) {
68    return NULL;
69  }
70  return host->CreateStreamOnNewPipeline(connection, used_ssl_config,
71                                         used_proxy_info, net_log,
72                                         was_npn_negotiated,
73                                         protocol_negotiated);
74}
75
76HttpPipelinedStream* HttpPipelinedHostPool::CreateStreamOnExistingPipeline(
77    const HttpPipelinedHost::Key& key) {
78  HttpPipelinedHost* host = GetPipelinedHost(key, false);
79  if (!host) {
80    return NULL;
81  }
82  return host->CreateStreamOnExistingPipeline();
83}
84
85bool HttpPipelinedHostPool::IsExistingPipelineAvailableForKey(
86    const HttpPipelinedHost::Key& key) {
87  HttpPipelinedHost* host = GetPipelinedHost(key, false);
88  if (!host) {
89    return false;
90  }
91  return host->IsExistingPipelineAvailable();
92}
93
94HttpPipelinedHost* HttpPipelinedHostPool::GetPipelinedHost(
95    const HttpPipelinedHost::Key& key, bool create_if_not_found) {
96  HostMap::iterator host_it = host_map_.find(key);
97  if (host_it != host_map_.end()) {
98    CHECK(host_it->second);
99    return host_it->second;
100  } else if (!create_if_not_found) {
101    return NULL;
102  }
103
104  HttpPipelinedHostCapability capability =
105      http_server_properties_->GetPipelineCapability(key.origin());
106  if (capability == PIPELINE_INCAPABLE) {
107    return NULL;
108  }
109
110  HttpPipelinedHost* host = factory_->CreateNewHost(
111      this, key, NULL, capability, force_pipelining_);
112  host_map_[key] = host;
113  return host;
114}
115
116void HttpPipelinedHostPool::OnHostIdle(HttpPipelinedHost* host) {
117  const HttpPipelinedHost::Key& key = host->GetKey();
118  CHECK(ContainsKey(host_map_, key));
119  host_map_.erase(key);
120  delete host;
121}
122
123void HttpPipelinedHostPool::OnHostHasAdditionalCapacity(
124    HttpPipelinedHost* host) {
125  delegate_->OnHttpPipelinedHostHasAdditionalCapacity(host);
126}
127
128void HttpPipelinedHostPool::OnHostDeterminedCapability(
129    HttpPipelinedHost* host,
130    HttpPipelinedHostCapability capability) {
131  http_server_properties_->SetPipelineCapability(host->GetKey().origin(),
132                                                 capability);
133}
134
135base::Value* HttpPipelinedHostPool::PipelineInfoToValue() const {
136  base::ListValue* list = new base::ListValue();
137  for (HostMap::const_iterator it = host_map_.begin();
138       it != host_map_.end(); ++it) {
139    base::Value* value = it->second->PipelineInfoToValue();
140    list->Append(value);
141  }
142  return list;
143}
144
145}  // namespace net
146