Skip managed bookmarks at the BookmarkChangeProcessor.
[chromium-blink-merge.git] / extensions / browser / content_verify_job.cc
blobe7e8cab9dd69a7bdf4298876a6f8966138e167a6
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.
5 #include "extensions/browser/content_verify_job.h"
7 #include <algorithm>
9 #include "base/metrics/histogram.h"
10 #include "base/stl_util.h"
11 #include "base/task_runner_util.h"
12 #include "base/timer/elapsed_timer.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "crypto/secure_hash.h"
15 #include "crypto/sha2.h"
16 #include "extensions/browser/content_hash_reader.h"
18 namespace extensions {
20 namespace {
22 ContentVerifyJob::TestDelegate* g_test_delegate = NULL;
24 class ScopedElapsedTimer {
25 public:
26 ScopedElapsedTimer(base::TimeDelta* total) : total_(total) { DCHECK(total_); }
28 ~ScopedElapsedTimer() { *total_ += timer.Elapsed(); }
30 private:
31 // Some total amount of time we should add our elapsed time to at
32 // destruction.
33 base::TimeDelta* total_;
35 // A timer for how long this object has been alive.
36 base::ElapsedTimer timer;
39 } // namespace
41 ContentVerifyJob::ContentVerifyJob(ContentHashReader* hash_reader,
42 const FailureCallback& failure_callback)
43 : done_reading_(false),
44 hashes_ready_(false),
45 total_bytes_read_(0),
46 current_block_(0),
47 current_hash_byte_count_(0),
48 hash_reader_(hash_reader),
49 failure_callback_(failure_callback),
50 failed_(false) {
51 // It's ok for this object to be constructed on a different thread from where
52 // it's used.
53 thread_checker_.DetachFromThread();
56 ContentVerifyJob::~ContentVerifyJob() {
57 UMA_HISTOGRAM_COUNTS("ExtensionContentVerifyJob.TimeSpentUS",
58 time_spent_.InMicroseconds());
61 void ContentVerifyJob::Start() {
62 DCHECK(thread_checker_.CalledOnValidThread());
63 base::PostTaskAndReplyWithResult(
64 content::BrowserThread::GetBlockingPool(),
65 FROM_HERE,
66 base::Bind(&ContentHashReader::Init, hash_reader_),
67 base::Bind(&ContentVerifyJob::OnHashesReady, this));
70 void ContentVerifyJob::BytesRead(int count, const char* data) {
71 ScopedElapsedTimer timer(&time_spent_);
72 DCHECK(thread_checker_.CalledOnValidThread());
73 if (failed_)
74 return;
75 if (g_test_delegate) {
76 FailureReason reason =
77 g_test_delegate->BytesRead(hash_reader_->extension_id(), count, data);
78 if (reason != NONE)
79 return DispatchFailureCallback(reason);
81 if (!hashes_ready_) {
82 queue_.append(data, count);
83 return;
85 DCHECK_GE(count, 0);
86 int bytes_added = 0;
88 while (bytes_added < count) {
89 if (current_block_ >= hash_reader_->block_count())
90 return DispatchFailureCallback(HASH_MISMATCH);
92 if (!current_hash_.get()) {
93 current_hash_byte_count_ = 0;
94 current_hash_.reset(
95 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
97 // Compute how many bytes we should hash, and add them to the current hash.
98 int bytes_to_hash =
99 std::min(hash_reader_->block_size() - current_hash_byte_count_,
100 count - bytes_added);
101 DCHECK(bytes_to_hash > 0);
102 current_hash_->Update(data + bytes_added, bytes_to_hash);
103 bytes_added += bytes_to_hash;
104 current_hash_byte_count_ += bytes_to_hash;
105 total_bytes_read_ += bytes_to_hash;
107 // If we finished reading a block worth of data, finish computing the hash
108 // for it and make sure the expected hash matches.
109 if (current_hash_byte_count_ == hash_reader_->block_size() &&
110 !FinishBlock()) {
111 DispatchFailureCallback(HASH_MISMATCH);
112 return;
117 void ContentVerifyJob::DoneReading() {
118 ScopedElapsedTimer timer(&time_spent_);
119 DCHECK(thread_checker_.CalledOnValidThread());
120 if (failed_)
121 return;
122 if (g_test_delegate) {
123 FailureReason reason =
124 g_test_delegate->DoneReading(hash_reader_->extension_id());
125 if (reason != NONE) {
126 DispatchFailureCallback(reason);
127 return;
130 done_reading_ = true;
131 if (hashes_ready_ && !FinishBlock())
132 DispatchFailureCallback(HASH_MISMATCH);
135 bool ContentVerifyJob::FinishBlock() {
136 if (current_hash_byte_count_ <= 0)
137 return true;
138 std::string final(crypto::kSHA256Length, 0);
139 current_hash_->Finish(string_as_array(&final), final.size());
140 current_hash_.reset();
141 current_hash_byte_count_ = 0;
143 int block = current_block_++;
145 const std::string* expected_hash = NULL;
146 if (!hash_reader_->GetHashForBlock(block, &expected_hash) ||
147 *expected_hash != final)
148 return false;
150 return true;
153 void ContentVerifyJob::OnHashesReady(bool success) {
154 if (!success && !g_test_delegate) {
155 if (!hash_reader_->content_exists()) {
156 // Ignore verification of non-existent resources.
157 return;
158 } else if (hash_reader_->have_verified_contents() &&
159 hash_reader_->have_computed_hashes()) {
160 DispatchFailureCallback(NO_HASHES_FOR_FILE);
161 } else {
162 DispatchFailureCallback(MISSING_ALL_HASHES);
164 return;
167 hashes_ready_ = true;
168 if (!queue_.empty()) {
169 std::string tmp;
170 queue_.swap(tmp);
171 BytesRead(tmp.size(), string_as_array(&tmp));
173 if (done_reading_) {
174 ScopedElapsedTimer timer(&time_spent_);
175 if (!FinishBlock())
176 DispatchFailureCallback(HASH_MISMATCH);
180 // static
181 void ContentVerifyJob::SetDelegateForTests(TestDelegate* delegate) {
182 g_test_delegate = delegate;
185 void ContentVerifyJob::DispatchFailureCallback(FailureReason reason) {
186 DCHECK(!failed_);
187 failed_ = true;
188 if (!failure_callback_.is_null()) {
189 VLOG(1) << "job failed for " << hash_reader_->extension_id() << " "
190 << hash_reader_->relative_path().MaybeAsASCII()
191 << " reason:" << reason;
192 failure_callback_.Run(reason);
193 failure_callback_.Reset();
197 } // namespace extensions