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 "chrome/browser/transport_security_persister.h"
6
7#include "base/file_path.h"
8#include "base/file_util.h"
9#include "base/message_loop.h"
10#include "base/path_service.h"
11#include "chrome/common/chrome_paths.h"
12#include "content/browser/browser_thread.h"
13#include "net/base/transport_security_state.h"
14
15TransportSecurityPersister::TransportSecurityPersister(bool readonly)
16  : ALLOW_THIS_IN_INITIALIZER_LIST(save_coalescer_(this)),
17    readonly_(readonly) {
18}
19
20TransportSecurityPersister::~TransportSecurityPersister() {
21  transport_security_state_->SetDelegate(NULL);
22}
23
24void TransportSecurityPersister::Initialize(
25    net::TransportSecurityState* state, const FilePath& profile_path) {
26  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
27  transport_security_state_ = state;
28  state_file_ =
29      profile_path.Append(FILE_PATH_LITERAL("TransportSecurity"));
30  state->SetDelegate(this);
31
32  Task* task = NewRunnableMethod(this,
33      &TransportSecurityPersister::Load);
34  BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE, task, 1000);
35}
36
37void TransportSecurityPersister::Load() {
38  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
39
40  std::string state;
41  if (!file_util::ReadFileToString(state_file_, &state))
42    return;
43
44  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
45      NewRunnableMethod(this,
46                        &TransportSecurityPersister::CompleteLoad,
47                        state));
48}
49
50void TransportSecurityPersister::CompleteLoad(const std::string& state) {
51  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
52
53  bool dirty = false;
54  if (!transport_security_state_->LoadEntries(state, &dirty)) {
55    LOG(ERROR) << "Failed to deserialize state: " << state;
56    return;
57  }
58  if (dirty)
59    StateIsDirty(transport_security_state_);
60}
61
62void TransportSecurityPersister::StateIsDirty(
63    net::TransportSecurityState* state) {
64  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
65  DCHECK(state == transport_security_state_);
66
67  if (readonly_)
68    return;
69
70  if (!save_coalescer_.empty())
71    return;
72
73  Task* task = save_coalescer_.NewRunnableMethod(
74      &TransportSecurityPersister::Save);
75  MessageLoop::current()->PostDelayedTask(FROM_HERE, task, 1000);
76}
77
78void TransportSecurityPersister::Save() {
79  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
80
81  std::string state;
82  if (!transport_security_state_->Serialise(&state))
83    return;
84
85  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
86      NewRunnableMethod(this,
87                        &TransportSecurityPersister::CompleteSave,
88                        state));
89}
90
91void TransportSecurityPersister::CompleteSave(const std::string& state) {
92  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
93  DCHECK(!readonly_);
94
95  file_util::WriteFile(state_file_, state.data(), state.size());
96}
97