1// Copyright 2014 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 "chrome/browser/browsing_data/browsing_data_channel_id_helper.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/message_loop/message_loop.h"
11#include "content/public/browser/browser_thread.h"
12#include "net/ssl/channel_id_service.h"
13#include "net/url_request/url_request_context.h"
14#include "net/url_request/url_request_context_getter.h"
15
16using content::BrowserThread;
17
18namespace {
19
20class BrowsingDataChannelIDHelperImpl
21    : public BrowsingDataChannelIDHelper {
22 public:
23  explicit BrowsingDataChannelIDHelperImpl(
24      net::URLRequestContextGetter* request_context);
25
26  // BrowsingDataChannelIDHelper methods.
27  virtual void StartFetching(const FetchResultCallback& callback) OVERRIDE;
28  virtual void DeleteChannelID(const std::string& server_id) OVERRIDE;
29
30 private:
31  virtual ~BrowsingDataChannelIDHelperImpl();
32
33  // Fetch the certs. This must be called in the IO thread.
34  void FetchOnIOThread();
35
36  void OnFetchComplete(
37      const net::ChannelIDStore::ChannelIDList& channel_id_list);
38
39  // Notifies the completion callback. This must be called in the UI thread.
40  void NotifyInUIThread(
41      const net::ChannelIDStore::ChannelIDList& channel_id_list);
42
43  // Delete a single cert. This must be called in IO thread.
44  void DeleteOnIOThread(const std::string& server_id);
45
46  // Called when deletion is done.
47  void DeleteCallback();
48
49  // Indicates whether or not we're currently fetching information:
50  // it's true when StartFetching() is called in the UI thread, and it's reset
51  // after we notify the callback in the UI thread.
52  // This member is only mutated on the UI thread.
53  bool is_fetching_;
54
55  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
56
57  // This member is only mutated on the UI thread.
58  FetchResultCallback completion_callback_;
59
60  DISALLOW_COPY_AND_ASSIGN(BrowsingDataChannelIDHelperImpl);
61};
62
63BrowsingDataChannelIDHelperImpl::BrowsingDataChannelIDHelperImpl(
64    net::URLRequestContextGetter* request_context)
65    : is_fetching_(false), request_context_getter_(request_context) {
66  DCHECK_CURRENTLY_ON(BrowserThread::UI);
67}
68
69BrowsingDataChannelIDHelperImpl::
70~BrowsingDataChannelIDHelperImpl() {
71}
72
73void BrowsingDataChannelIDHelperImpl::StartFetching(
74    const FetchResultCallback& callback) {
75  DCHECK_CURRENTLY_ON(BrowserThread::UI);
76  DCHECK(!is_fetching_);
77  DCHECK(!callback.is_null());
78  DCHECK(completion_callback_.is_null());
79  is_fetching_ = true;
80  completion_callback_ = callback;
81  BrowserThread::PostTask(
82      BrowserThread::IO,
83      FROM_HERE,
84      base::Bind(&BrowsingDataChannelIDHelperImpl::FetchOnIOThread, this));
85}
86
87void BrowsingDataChannelIDHelperImpl::DeleteChannelID(
88    const std::string& server_id) {
89  DCHECK_CURRENTLY_ON(BrowserThread::UI);
90  BrowserThread::PostTask(
91      BrowserThread::IO,
92      FROM_HERE,
93      base::Bind(
94          &BrowsingDataChannelIDHelperImpl::DeleteOnIOThread, this, server_id));
95}
96
97void BrowsingDataChannelIDHelperImpl::FetchOnIOThread() {
98  DCHECK_CURRENTLY_ON(BrowserThread::IO);
99  net::ChannelIDStore* cert_store =
100      request_context_getter_->GetURLRequestContext()->
101      channel_id_service()->GetChannelIDStore();
102  if (cert_store) {
103    cert_store->GetAllChannelIDs(base::Bind(
104        &BrowsingDataChannelIDHelperImpl::OnFetchComplete, this));
105  } else {
106    OnFetchComplete(net::ChannelIDStore::ChannelIDList());
107  }
108}
109
110void BrowsingDataChannelIDHelperImpl::OnFetchComplete(
111    const net::ChannelIDStore::ChannelIDList& channel_id_list) {
112  DCHECK_CURRENTLY_ON(BrowserThread::IO);
113  BrowserThread::PostTask(
114      BrowserThread::UI,
115      FROM_HERE,
116      base::Bind(&BrowsingDataChannelIDHelperImpl::NotifyInUIThread,
117                 this,
118                 channel_id_list));
119}
120
121void BrowsingDataChannelIDHelperImpl::NotifyInUIThread(
122    const net::ChannelIDStore::ChannelIDList& channel_id_list) {
123  DCHECK_CURRENTLY_ON(BrowserThread::UI);
124  DCHECK(is_fetching_);
125  is_fetching_ = false;
126  completion_callback_.Run(channel_id_list);
127  completion_callback_.Reset();
128}
129
130void BrowsingDataChannelIDHelperImpl::DeleteOnIOThread(
131    const std::string& server_id) {
132  DCHECK_CURRENTLY_ON(BrowserThread::IO);
133  net::ChannelIDStore* cert_store =
134      request_context_getter_->GetURLRequestContext()->
135      channel_id_service()->GetChannelIDStore();
136  if (cert_store) {
137    cert_store->DeleteChannelID(
138        server_id,
139        base::Bind(&BrowsingDataChannelIDHelperImpl::DeleteCallback,
140                   this));
141  }
142}
143
144void BrowsingDataChannelIDHelperImpl::DeleteCallback() {
145  DCHECK_CURRENTLY_ON(BrowserThread::IO);
146  // Need to close open SSL connections which may be using the channel ids we
147  // are deleting.
148  // TODO(mattm): http://crbug.com/166069 Make the server bound cert
149  // service/store have observers that can notify relevant things directly.
150  request_context_getter_->GetURLRequestContext()->ssl_config_service()->
151      NotifySSLConfigChange();
152}
153
154}  // namespace
155
156// static
157BrowsingDataChannelIDHelper* BrowsingDataChannelIDHelper::Create(
158    net::URLRequestContextGetter* request_context) {
159  return new BrowsingDataChannelIDHelperImpl(request_context);
160}
161
162CannedBrowsingDataChannelIDHelper::
163CannedBrowsingDataChannelIDHelper() {}
164
165CannedBrowsingDataChannelIDHelper::
166~CannedBrowsingDataChannelIDHelper() {}
167
168void CannedBrowsingDataChannelIDHelper::AddChannelID(
169    const net::ChannelIDStore::ChannelID& channel_id) {
170  DCHECK_CURRENTLY_ON(BrowserThread::UI);
171  channel_id_map_[channel_id.server_identifier()] =
172      channel_id;
173}
174
175void CannedBrowsingDataChannelIDHelper::Reset() {
176  channel_id_map_.clear();
177}
178
179bool CannedBrowsingDataChannelIDHelper::empty() const {
180  return channel_id_map_.empty();
181}
182
183size_t CannedBrowsingDataChannelIDHelper::GetChannelIDCount() const {
184  DCHECK_CURRENTLY_ON(BrowserThread::UI);
185  return channel_id_map_.size();
186}
187
188void CannedBrowsingDataChannelIDHelper::StartFetching(
189    const FetchResultCallback& callback) {
190  DCHECK_CURRENTLY_ON(BrowserThread::UI);
191  if (callback.is_null())
192    return;
193  // We post a task to emulate async fetching behavior.
194  completion_callback_ = callback;
195  base::MessageLoop::current()->PostTask(
196      FROM_HERE,
197      base::Bind(&CannedBrowsingDataChannelIDHelper::FinishFetching,
198                 this));
199}
200
201void CannedBrowsingDataChannelIDHelper::FinishFetching() {
202  DCHECK_CURRENTLY_ON(BrowserThread::UI);
203  net::ChannelIDStore::ChannelIDList channel_id_list;
204  for (ChannelIDMap::iterator i = channel_id_map_.begin();
205       i != channel_id_map_.end(); ++i)
206    channel_id_list.push_back(i->second);
207  completion_callback_.Run(channel_id_list);
208}
209
210void CannedBrowsingDataChannelIDHelper::DeleteChannelID(
211    const std::string& server_id) {
212  NOTREACHED();
213}
214