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"
9 #include "base/stl_util.h"
10 #include "base/task_runner_util.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "crypto/secure_hash.h"
13 #include "crypto/sha2.h"
14 #include "extensions/browser/content_hash_reader.h"
16 namespace extensions {
20 ContentVerifyJob::TestDelegate* g_test_delegate = NULL;
24 ContentVerifyJob::ContentVerifyJob(ContentHashReader* hash_reader,
25 const FailureCallback& failure_callback)
26 : done_reading_(false),
30 current_hash_byte_count_(0),
31 hash_reader_(hash_reader),
32 failure_callback_(failure_callback) {
33 // It's ok for this object to be constructed on a different thread from where
35 thread_checker_.DetachFromThread();
38 ContentVerifyJob::~ContentVerifyJob() {
41 void ContentVerifyJob::Start() {
42 DCHECK(thread_checker_.CalledOnValidThread());
43 base::PostTaskAndReplyWithResult(
44 content::BrowserThread::GetBlockingPool(),
46 base::Bind(&ContentHashReader::Init, hash_reader_),
47 base::Bind(&ContentVerifyJob::OnHashesReady, this));
50 void ContentVerifyJob::BytesRead(int count, const char* data) {
51 DCHECK(thread_checker_.CalledOnValidThread());
52 if (g_test_delegate) {
53 FailureReason reason =
54 g_test_delegate->BytesRead(hash_reader_->extension_id(), count, data);
56 return DispatchFailureCallback(reason);
59 queue_.append(data, count);
65 while (bytes_added < count) {
66 if (current_block_ >= hash_reader_->block_count())
67 return DispatchFailureCallback(HASH_MISMATCH);
69 if (!current_hash_.get()) {
70 current_hash_byte_count_ = 0;
72 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
74 // Compute how many bytes we should hash, and add them to the current hash.
76 std::min(hash_reader_->block_size() - current_hash_byte_count_,
78 current_hash_->Update(data + bytes_added, bytes_to_hash);
79 bytes_added += bytes_to_hash;
80 current_hash_byte_count_ += bytes_to_hash;
81 total_bytes_read_ += bytes_to_hash;
83 // If we finished reading a block worth of data, finish computing the hash
84 // for it and make sure the expected hash matches.
85 if (current_hash_byte_count_ == hash_reader_->block_size())
90 void ContentVerifyJob::DoneReading() {
91 DCHECK(thread_checker_.CalledOnValidThread());
92 if (g_test_delegate) {
93 FailureReason reason =
94 g_test_delegate->DoneReading(hash_reader_->extension_id());
96 DispatchFailureCallback(reason);
100 done_reading_ = true;
105 void ContentVerifyJob::FinishBlock() {
106 if (current_hash_byte_count_ <= 0)
108 std::string final(crypto::kSHA256Length, 0);
109 current_hash_->Finish(string_as_array(&final), final.size());
111 const std::string* expected_hash = NULL;
112 if (!hash_reader_->GetHashForBlock(current_block_, &expected_hash))
113 return DispatchFailureCallback(HASH_MISMATCH);
115 if (*expected_hash != final)
116 return DispatchFailureCallback(HASH_MISMATCH);
118 current_hash_.reset();
119 current_hash_byte_count_ = 0;
123 void ContentVerifyJob::OnHashesReady(bool success) {
124 if (!success && !g_test_delegate)
125 return DispatchFailureCallback(NO_HASHES);
127 hashes_ready_ = true;
128 if (!queue_.empty()) {
131 BytesRead(tmp.size(), string_as_array(&tmp));
138 void ContentVerifyJob::SetDelegateForTests(TestDelegate* delegate) {
139 g_test_delegate = delegate;
142 void ContentVerifyJob::DispatchFailureCallback(FailureReason reason) {
143 if (!failure_callback_.is_null()) {
144 failure_callback_.Run(reason);
145 failure_callback_.Reset();
149 } // namespace extensions