OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/browser/content_verify_job.h" | 5 #include "extensions/browser/content_verify_job.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "base/task_runner_util.h" | 10 #include "base/task_runner_util.h" |
11 #include "content/public/browser/browser_thread.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" |
12 | 15 |
13 namespace extensions { | 16 namespace extensions { |
14 | 17 |
15 namespace { | 18 namespace { |
16 | 19 |
17 ContentVerifyJob::TestDelegate* g_test_delegate = NULL; | 20 ContentVerifyJob::TestDelegate* g_test_delegate = NULL; |
18 | 21 |
19 } // namespace | 22 } // namespace |
20 | 23 |
21 ContentVerifyJob::ContentVerifyJob(const std::string& extension_id, | 24 ContentVerifyJob::ContentVerifyJob(ContentHashReader* hash_reader, |
22 const FailureCallback& failure_callback) | 25 const FailureCallback& failure_callback) |
23 : extension_id_(extension_id), failure_callback_(failure_callback) { | 26 : done_reading_(false), |
| 27 hashes_ready_(false), |
| 28 total_bytes_read_(0), |
| 29 current_block_(0), |
| 30 current_hash_byte_count_(0), |
| 31 hash_reader_(hash_reader), |
| 32 failure_callback_(failure_callback) { |
24 // It's ok for this object to be constructed on a different thread from where | 33 // It's ok for this object to be constructed on a different thread from where |
25 // it's used. | 34 // it's used. |
26 thread_checker_.DetachFromThread(); | 35 thread_checker_.DetachFromThread(); |
27 } | 36 } |
28 | 37 |
29 ContentVerifyJob::~ContentVerifyJob() { | 38 ContentVerifyJob::~ContentVerifyJob() { |
30 } | 39 } |
31 | 40 |
32 void ContentVerifyJob::Start() { | 41 void ContentVerifyJob::Start() { |
33 DCHECK(thread_checker_.CalledOnValidThread()); | 42 DCHECK(thread_checker_.CalledOnValidThread()); |
| 43 base::PostTaskAndReplyWithResult( |
| 44 content::BrowserThread::GetBlockingPool(), |
| 45 FROM_HERE, |
| 46 base::Bind(&ContentHashReader::Init, hash_reader_), |
| 47 base::Bind(&ContentVerifyJob::OnHashesReady, this)); |
34 } | 48 } |
35 | 49 |
36 void ContentVerifyJob::BytesRead(int count, const char* data) { | 50 void ContentVerifyJob::BytesRead(int count, const char* data) { |
37 DCHECK(thread_checker_.CalledOnValidThread()); | 51 DCHECK(thread_checker_.CalledOnValidThread()); |
38 if (g_test_delegate) { | 52 if (g_test_delegate) { |
39 FailureReason reason = | 53 FailureReason reason = |
40 g_test_delegate->BytesRead(extension_id_, count, data); | 54 g_test_delegate->BytesRead(hash_reader_->extension_id(), count, data); |
41 if (reason != NONE) | 55 if (reason != NONE) |
42 return DispatchFailureCallback(reason); | 56 return DispatchFailureCallback(reason); |
43 } | 57 } |
| 58 if (!hashes_ready_) { |
| 59 queue_.append(data, count); |
| 60 return; |
| 61 } |
| 62 DCHECK_GE(count, 0); |
| 63 int bytes_added = 0; |
| 64 |
| 65 while (bytes_added < count) { |
| 66 if (current_block_ >= hash_reader_->block_count()) |
| 67 return DispatchFailureCallback(HASH_MISMATCH); |
| 68 |
| 69 if (!current_hash_.get()) { |
| 70 current_hash_byte_count_ = 0; |
| 71 current_hash_.reset( |
| 72 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); |
| 73 } |
| 74 // Compute how many bytes we should hash, and add them to the current hash. |
| 75 int bytes_to_hash = |
| 76 std::min(hash_reader_->block_size() - current_hash_byte_count_, |
| 77 count - bytes_added); |
| 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; |
| 82 |
| 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()) |
| 86 FinishBlock(); |
| 87 } |
44 } | 88 } |
45 | 89 |
46 void ContentVerifyJob::DoneReading() { | 90 void ContentVerifyJob::DoneReading() { |
47 DCHECK(thread_checker_.CalledOnValidThread()); | 91 DCHECK(thread_checker_.CalledOnValidThread()); |
48 if (g_test_delegate) { | 92 if (g_test_delegate) { |
49 FailureReason reason = g_test_delegate->DoneReading(extension_id_); | 93 FailureReason reason = |
| 94 g_test_delegate->DoneReading(hash_reader_->extension_id()); |
50 if (reason != NONE) { | 95 if (reason != NONE) { |
51 DispatchFailureCallback(reason); | 96 DispatchFailureCallback(reason); |
52 return; | 97 return; |
53 } | 98 } |
54 } | 99 } |
| 100 done_reading_ = true; |
| 101 if (hashes_ready_) |
| 102 FinishBlock(); |
| 103 } |
| 104 |
| 105 void ContentVerifyJob::FinishBlock() { |
| 106 if (current_hash_byte_count_ <= 0) |
| 107 return; |
| 108 std::string final(crypto::kSHA256Length, 0); |
| 109 current_hash_->Finish(string_as_array(&final), final.size()); |
| 110 |
| 111 const std::string* expected_hash = NULL; |
| 112 if (!hash_reader_->GetHashForBlock(current_block_, &expected_hash)) |
| 113 return DispatchFailureCallback(HASH_MISMATCH); |
| 114 |
| 115 if (*expected_hash != final) |
| 116 return DispatchFailureCallback(HASH_MISMATCH); |
| 117 |
| 118 current_hash_.reset(); |
| 119 current_hash_byte_count_ = 0; |
| 120 current_block_++; |
| 121 } |
| 122 |
| 123 void ContentVerifyJob::OnHashesReady(bool success) { |
| 124 if (!success) |
| 125 return DispatchFailureCallback(NO_HASHES); |
| 126 |
| 127 hashes_ready_ = true; |
| 128 if (!queue_.empty()) { |
| 129 std::string tmp; |
| 130 queue_.swap(tmp); |
| 131 BytesRead(tmp.size(), string_as_array(&tmp)); |
| 132 } |
| 133 if (done_reading_) |
| 134 FinishBlock(); |
55 } | 135 } |
56 | 136 |
57 // static | 137 // static |
58 void ContentVerifyJob::SetDelegateForTests(TestDelegate* delegate) { | 138 void ContentVerifyJob::SetDelegateForTests(TestDelegate* delegate) { |
59 g_test_delegate = delegate; | 139 g_test_delegate = delegate; |
60 } | 140 } |
61 | 141 |
62 void ContentVerifyJob::DispatchFailureCallback(FailureReason reason) { | 142 void ContentVerifyJob::DispatchFailureCallback(FailureReason reason) { |
63 if (!failure_callback_.is_null()) { | 143 if (!failure_callback_.is_null()) { |
64 failure_callback_.Run(reason); | 144 failure_callback_.Run(reason); |
65 failure_callback_.Reset(); | 145 failure_callback_.Reset(); |
66 } | 146 } |
67 } | 147 } |
68 | 148 |
69 } // namespace extensions | 149 } // namespace extensions |
OLD | NEW |