| 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 |