Broke ContentSettingBubbleModelTest.Plugins on Android.
[chromium-blink-merge.git] / content / browser / cert_store_impl.cc
blob5a171f7bc1e6324cdd0193ecd1450335d2fc63de
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.
5 #include "content/browser/cert_store_impl.h"
7 #include <algorithm>
8 #include <functional>
10 #include "base/bind.h"
11 #include "base/stl_util.h"
12 #include "content/browser/renderer_host/render_process_host_impl.h"
13 #include "content/browser/renderer_host/render_view_host_impl.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/notification_types.h"
18 template <typename T>
19 struct MatchSecond {
20 explicit MatchSecond(const T& t) : value(t) {}
22 template<typename Pair>
23 bool operator()(const Pair& p) const {
24 return (value == p.second);
26 T value;
29 namespace content {
31 // static
32 CertStore* CertStore::GetInstance() {
33 return CertStoreImpl::GetInstance();
36 // static
37 CertStoreImpl* CertStoreImpl::GetInstance() {
38 return Singleton<CertStoreImpl>::get();
41 CertStoreImpl::CertStoreImpl() : next_cert_id_(1) {
42 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
43 RegisterForNotification();
44 } else {
45 BrowserThread::PostTask(
46 BrowserThread::UI, FROM_HERE,
47 base::Bind(&CertStoreImpl::RegisterForNotification,
48 base::Unretained(this)));
52 CertStoreImpl::~CertStoreImpl() {
55 void CertStoreImpl::RegisterForNotification() {
56 // We watch for RenderProcess termination, as this is how we clear
57 // certificates for now.
58 // TODO(jcampan): we should be listening to events such as resource cached/
59 // removed from cache, and remove the cert when we know it
60 // is not used anymore.
62 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED,
63 NotificationService::AllBrowserContextsAndSources());
64 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED,
65 NotificationService::AllBrowserContextsAndSources());
68 int CertStoreImpl::StoreCert(net::X509Certificate* cert, int process_id) {
69 DCHECK(cert);
70 base::AutoLock auto_lock(cert_lock_);
72 int cert_id;
74 // Do we already know this cert?
75 ReverseCertMap::iterator cert_iter = cert_to_id_.find(cert);
76 if (cert_iter == cert_to_id_.end()) {
77 cert_id = next_cert_id_++;
78 // We use 0 as an invalid cert_id value. In the unlikely event that
79 // next_cert_id_ wraps around, we reset it to 1.
80 if (next_cert_id_ == 0)
81 next_cert_id_ = 1;
82 cert->AddRef();
83 id_to_cert_[cert_id] = cert;
84 cert_to_id_[cert] = cert_id;
85 } else {
86 cert_id = cert_iter->second;
89 // Let's update process_id_to_cert_id_.
90 std::pair<IDMap::iterator, IDMap::iterator> process_ids =
91 process_id_to_cert_id_.equal_range(process_id);
92 if (std::find_if(process_ids.first, process_ids.second,
93 MatchSecond<int>(cert_id)) == process_ids.second) {
94 process_id_to_cert_id_.insert(std::make_pair(process_id, cert_id));
97 // And cert_id_to_process_id_.
98 std::pair<IDMap::iterator, IDMap::iterator> cert_ids =
99 cert_id_to_process_id_.equal_range(cert_id);
100 if (std::find_if(cert_ids.first, cert_ids.second,
101 MatchSecond<int>(process_id)) == cert_ids.second) {
102 cert_id_to_process_id_.insert(std::make_pair(cert_id, process_id));
105 return cert_id;
108 bool CertStoreImpl::RetrieveCert(int cert_id,
109 scoped_refptr<net::X509Certificate>* cert) {
110 base::AutoLock auto_lock(cert_lock_);
112 CertMap::iterator iter = id_to_cert_.find(cert_id);
113 if (iter == id_to_cert_.end())
114 return false;
115 if (cert)
116 *cert = iter->second;
117 return true;
120 void CertStoreImpl::RemoveCertInternal(int cert_id) {
121 CertMap::iterator cert_iter = id_to_cert_.find(cert_id);
122 DCHECK(cert_iter != id_to_cert_.end());
124 ReverseCertMap::iterator id_iter = cert_to_id_.find(cert_iter->second);
125 DCHECK(id_iter != cert_to_id_.end());
126 cert_to_id_.erase(id_iter);
128 cert_iter->second->Release();
129 id_to_cert_.erase(cert_iter);
132 void CertStoreImpl::RemoveCertsForRenderProcesHost(int process_id) {
133 base::AutoLock auto_lock(cert_lock_);
135 // We iterate through all the cert ids for that process.
136 std::pair<IDMap::iterator, IDMap::iterator> process_ids =
137 process_id_to_cert_id_.equal_range(process_id);
138 for (IDMap::iterator ids_iter = process_ids.first;
139 ids_iter != process_ids.second; ++ids_iter) {
140 int cert_id = ids_iter->second;
141 // Find all the processes referring to this cert id in
142 // cert_id_to_process_id_, then locate the process being removed within
143 // that range.
144 std::pair<IDMap::iterator, IDMap::iterator> cert_ids =
145 cert_id_to_process_id_.equal_range(cert_id);
146 IDMap::iterator proc_iter =
147 std::find_if(cert_ids.first, cert_ids.second,
148 MatchSecond<int>(process_id));
149 DCHECK(proc_iter != cert_ids.second);
151 // Before removing, determine if no other processes refer to the current
152 // cert id. If |proc_iter| (the current process) is the lower bound of
153 // processes containing the current cert id and if |next_proc_iter| is the
154 // upper bound (the first process that does not), then only one process,
155 // the one being removed, refers to the cert id.
156 IDMap::iterator next_proc_iter = proc_iter;
157 ++next_proc_iter;
158 bool last_process_for_cert_id =
159 (proc_iter == cert_ids.first && next_proc_iter == cert_ids.second);
160 cert_id_to_process_id_.erase(proc_iter);
162 if (last_process_for_cert_id) {
163 // The current cert id is not referenced by any other processes, so
164 // remove it from id_to_cert_ and cert_to_id_.
165 RemoveCertInternal(cert_id);
168 if (process_ids.first != process_ids.second)
169 process_id_to_cert_id_.erase(process_ids.first, process_ids.second);
172 void CertStoreImpl::Observe(int type,
173 const NotificationSource& source,
174 const NotificationDetails& details) {
175 DCHECK(type == NOTIFICATION_RENDERER_PROCESS_TERMINATED ||
176 type == NOTIFICATION_RENDERER_PROCESS_CLOSED);
177 RenderProcessHost* rph = Source<RenderProcessHost>(source).ptr();
178 DCHECK(rph);
179 RemoveCertsForRenderProcesHost(rph->GetID());
182 } // namespace content