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" |
(...skipping 11 matching lines...) Expand all Loading... |
22 } // namespace | 22 } // namespace |
23 | 23 |
24 ContentVerifyJob::ContentVerifyJob(ContentHashReader* hash_reader, | 24 ContentVerifyJob::ContentVerifyJob(ContentHashReader* hash_reader, |
25 const FailureCallback& failure_callback) | 25 const FailureCallback& failure_callback) |
26 : done_reading_(false), | 26 : done_reading_(false), |
27 hashes_ready_(false), | 27 hashes_ready_(false), |
28 total_bytes_read_(0), | 28 total_bytes_read_(0), |
29 current_block_(0), | 29 current_block_(0), |
30 current_hash_byte_count_(0), | 30 current_hash_byte_count_(0), |
31 hash_reader_(hash_reader), | 31 hash_reader_(hash_reader), |
32 failure_callback_(failure_callback) { | 32 failure_callback_(failure_callback), |
| 33 failed_(false) { |
33 // It's ok for this object to be constructed on a different thread from where | 34 // It's ok for this object to be constructed on a different thread from where |
34 // it's used. | 35 // it's used. |
35 thread_checker_.DetachFromThread(); | 36 thread_checker_.DetachFromThread(); |
36 } | 37 } |
37 | 38 |
38 ContentVerifyJob::~ContentVerifyJob() { | 39 ContentVerifyJob::~ContentVerifyJob() { |
39 } | 40 } |
40 | 41 |
41 void ContentVerifyJob::Start() { | 42 void ContentVerifyJob::Start() { |
42 DCHECK(thread_checker_.CalledOnValidThread()); | 43 DCHECK(thread_checker_.CalledOnValidThread()); |
43 base::PostTaskAndReplyWithResult( | 44 base::PostTaskAndReplyWithResult( |
44 content::BrowserThread::GetBlockingPool(), | 45 content::BrowserThread::GetBlockingPool(), |
45 FROM_HERE, | 46 FROM_HERE, |
46 base::Bind(&ContentHashReader::Init, hash_reader_), | 47 base::Bind(&ContentHashReader::Init, hash_reader_), |
47 base::Bind(&ContentVerifyJob::OnHashesReady, this)); | 48 base::Bind(&ContentVerifyJob::OnHashesReady, this)); |
48 } | 49 } |
49 | 50 |
50 void ContentVerifyJob::BytesRead(int count, const char* data) { | 51 void ContentVerifyJob::BytesRead(int count, const char* data) { |
51 DCHECK(thread_checker_.CalledOnValidThread()); | 52 DCHECK(thread_checker_.CalledOnValidThread()); |
| 53 if (failed_) |
| 54 return; |
52 if (g_test_delegate) { | 55 if (g_test_delegate) { |
53 FailureReason reason = | 56 FailureReason reason = |
54 g_test_delegate->BytesRead(hash_reader_->extension_id(), count, data); | 57 g_test_delegate->BytesRead(hash_reader_->extension_id(), count, data); |
55 if (reason != NONE) | 58 if (reason != NONE) |
56 return DispatchFailureCallback(reason); | 59 return DispatchFailureCallback(reason); |
57 } | 60 } |
58 if (!hashes_ready_) { | 61 if (!hashes_ready_) { |
59 queue_.append(data, count); | 62 queue_.append(data, count); |
60 return; | 63 return; |
61 } | 64 } |
62 DCHECK_GE(count, 0); | 65 DCHECK_GE(count, 0); |
63 int bytes_added = 0; | 66 int bytes_added = 0; |
64 | 67 |
65 while (bytes_added < count) { | 68 while (bytes_added < count) { |
66 if (current_block_ >= hash_reader_->block_count()) | 69 if (current_block_ >= hash_reader_->block_count()) |
67 return DispatchFailureCallback(HASH_MISMATCH); | 70 return DispatchFailureCallback(HASH_MISMATCH); |
68 | 71 |
69 if (!current_hash_.get()) { | 72 if (!current_hash_.get()) { |
70 current_hash_byte_count_ = 0; | 73 current_hash_byte_count_ = 0; |
71 current_hash_.reset( | 74 current_hash_.reset( |
72 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); | 75 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); |
73 } | 76 } |
74 // Compute how many bytes we should hash, and add them to the current hash. | 77 // Compute how many bytes we should hash, and add them to the current hash. |
75 int bytes_to_hash = | 78 int bytes_to_hash = |
76 std::min(hash_reader_->block_size() - current_hash_byte_count_, | 79 std::min(hash_reader_->block_size() - current_hash_byte_count_, |
77 count - bytes_added); | 80 count - bytes_added); |
| 81 DCHECK(bytes_to_hash > 0); |
78 current_hash_->Update(data + bytes_added, bytes_to_hash); | 82 current_hash_->Update(data + bytes_added, bytes_to_hash); |
79 bytes_added += bytes_to_hash; | 83 bytes_added += bytes_to_hash; |
80 current_hash_byte_count_ += bytes_to_hash; | 84 current_hash_byte_count_ += bytes_to_hash; |
81 total_bytes_read_ += bytes_to_hash; | 85 total_bytes_read_ += bytes_to_hash; |
82 | 86 |
83 // If we finished reading a block worth of data, finish computing the hash | 87 // If we finished reading a block worth of data, finish computing the hash |
84 // for it and make sure the expected hash matches. | 88 // for it and make sure the expected hash matches. |
85 if (current_hash_byte_count_ == hash_reader_->block_size()) | 89 if (current_hash_byte_count_ == hash_reader_->block_size() && |
86 FinishBlock(); | 90 !FinishBlock()) { |
| 91 DispatchFailureCallback(HASH_MISMATCH); |
| 92 return; |
| 93 } |
87 } | 94 } |
88 } | 95 } |
89 | 96 |
90 void ContentVerifyJob::DoneReading() { | 97 void ContentVerifyJob::DoneReading() { |
91 DCHECK(thread_checker_.CalledOnValidThread()); | 98 DCHECK(thread_checker_.CalledOnValidThread()); |
| 99 if (failed_) |
| 100 return; |
92 if (g_test_delegate) { | 101 if (g_test_delegate) { |
93 FailureReason reason = | 102 FailureReason reason = |
94 g_test_delegate->DoneReading(hash_reader_->extension_id()); | 103 g_test_delegate->DoneReading(hash_reader_->extension_id()); |
95 if (reason != NONE) { | 104 if (reason != NONE) { |
96 DispatchFailureCallback(reason); | 105 DispatchFailureCallback(reason); |
97 return; | 106 return; |
98 } | 107 } |
99 } | 108 } |
100 done_reading_ = true; | 109 done_reading_ = true; |
101 if (hashes_ready_) | 110 if (hashes_ready_ && !FinishBlock()) |
102 FinishBlock(); | 111 DispatchFailureCallback(HASH_MISMATCH); |
103 } | 112 } |
104 | 113 |
105 void ContentVerifyJob::FinishBlock() { | 114 bool ContentVerifyJob::FinishBlock() { |
106 if (current_hash_byte_count_ <= 0) | 115 if (current_hash_byte_count_ <= 0) |
107 return; | 116 return true; |
108 std::string final(crypto::kSHA256Length, 0); | 117 std::string final(crypto::kSHA256Length, 0); |
109 current_hash_->Finish(string_as_array(&final), final.size()); | 118 current_hash_->Finish(string_as_array(&final), final.size()); |
110 | 119 |
111 const std::string* expected_hash = NULL; | 120 const std::string* expected_hash = NULL; |
112 if (!hash_reader_->GetHashForBlock(current_block_, &expected_hash)) | 121 if (!hash_reader_->GetHashForBlock(current_block_, &expected_hash) || |
113 return DispatchFailureCallback(HASH_MISMATCH); | 122 *expected_hash != final) |
114 | 123 return false; |
115 if (*expected_hash != final) | |
116 return DispatchFailureCallback(HASH_MISMATCH); | |
117 | 124 |
118 current_hash_.reset(); | 125 current_hash_.reset(); |
119 current_hash_byte_count_ = 0; | 126 current_hash_byte_count_ = 0; |
120 current_block_++; | 127 current_block_++; |
| 128 return true; |
121 } | 129 } |
122 | 130 |
123 void ContentVerifyJob::OnHashesReady(bool success) { | 131 void ContentVerifyJob::OnHashesReady(bool success) { |
124 if (!success && !g_test_delegate) | 132 if (!success && !g_test_delegate) { |
125 return DispatchFailureCallback(NO_HASHES); | 133 if (hash_reader_->have_verified_contents() && |
| 134 hash_reader_->have_computed_hashes()) |
| 135 DispatchFailureCallback(NO_HASHES_FOR_FILE); |
| 136 else |
| 137 DispatchFailureCallback(MISSING_ALL_HASHES); |
| 138 return; |
| 139 } |
126 | 140 |
127 hashes_ready_ = true; | 141 hashes_ready_ = true; |
128 if (!queue_.empty()) { | 142 if (!queue_.empty()) { |
129 std::string tmp; | 143 std::string tmp; |
130 queue_.swap(tmp); | 144 queue_.swap(tmp); |
131 BytesRead(tmp.size(), string_as_array(&tmp)); | 145 BytesRead(tmp.size(), string_as_array(&tmp)); |
132 } | 146 } |
133 if (done_reading_) | 147 if (done_reading_ && !FinishBlock()) |
134 FinishBlock(); | 148 DispatchFailureCallback(HASH_MISMATCH); |
135 } | 149 } |
136 | 150 |
137 // static | 151 // static |
138 void ContentVerifyJob::SetDelegateForTests(TestDelegate* delegate) { | 152 void ContentVerifyJob::SetDelegateForTests(TestDelegate* delegate) { |
139 g_test_delegate = delegate; | 153 g_test_delegate = delegate; |
140 } | 154 } |
141 | 155 |
142 void ContentVerifyJob::DispatchFailureCallback(FailureReason reason) { | 156 void ContentVerifyJob::DispatchFailureCallback(FailureReason reason) { |
| 157 DCHECK(!failed_); |
| 158 failed_ = true; |
143 if (!failure_callback_.is_null()) { | 159 if (!failure_callback_.is_null()) { |
| 160 VLOG(1) << "job failed for " << hash_reader_->extension_id() << " " |
| 161 << hash_reader_->relative_path().MaybeAsASCII() |
| 162 << " reason:" << reason; |
144 failure_callback_.Run(reason); | 163 failure_callback_.Run(reason); |
145 failure_callback_.Reset(); | 164 failure_callback_.Reset(); |
146 } | 165 } |
147 } | 166 } |
148 | 167 |
149 } // namespace extensions | 168 } // namespace extensions |
OLD | NEW |