Index: extensions/browser/content_verify_job.cc |
diff --git a/extensions/browser/content_verify_job.cc b/extensions/browser/content_verify_job.cc |
index 399f3636eeffebfebfe27418ec6c23a9c082e179..601d66c0f9dd3b49c1a1a4ac694f907e14d2f2bc 100644 |
--- a/extensions/browser/content_verify_job.cc |
+++ b/extensions/browser/content_verify_job.cc |
@@ -9,6 +9,9 @@ |
#include "base/stl_util.h" |
#include "base/task_runner_util.h" |
#include "content/public/browser/browser_thread.h" |
+#include "crypto/secure_hash.h" |
+#include "crypto/sha2.h" |
+#include "extensions/browser/content_hash_reader.h" |
namespace extensions { |
@@ -18,9 +21,15 @@ ContentVerifyJob::TestDelegate* g_test_delegate = NULL; |
} // namespace |
-ContentVerifyJob::ContentVerifyJob(const std::string& extension_id, |
+ContentVerifyJob::ContentVerifyJob(ContentHashReader* hash_reader, |
const FailureCallback& failure_callback) |
- : extension_id_(extension_id), failure_callback_(failure_callback) { |
+ : done_reading_(false), |
+ hashes_ready_(false), |
+ total_bytes_read_(0), |
+ current_block_(0), |
+ current_hash_byte_count_(0), |
+ hash_reader_(hash_reader), |
+ failure_callback_(failure_callback) { |
// It's ok for this object to be constructed on a different thread from where |
// it's used. |
thread_checker_.DetachFromThread(); |
@@ -31,27 +40,98 @@ ContentVerifyJob::~ContentVerifyJob() { |
void ContentVerifyJob::Start() { |
DCHECK(thread_checker_.CalledOnValidThread()); |
+ base::PostTaskAndReplyWithResult( |
+ content::BrowserThread::GetBlockingPool(), |
+ FROM_HERE, |
+ base::Bind(&ContentHashReader::Init, hash_reader_), |
+ base::Bind(&ContentVerifyJob::OnHashesReady, this)); |
} |
void ContentVerifyJob::BytesRead(int count, const char* data) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
if (g_test_delegate) { |
FailureReason reason = |
- g_test_delegate->BytesRead(extension_id_, count, data); |
+ g_test_delegate->BytesRead(hash_reader_->extension_id(), count, data); |
if (reason != NONE) |
return DispatchFailureCallback(reason); |
} |
+ if (!hashes_ready_) { |
+ queue_.append(data, count); |
+ return; |
+ } |
+ DCHECK_GE(count, 0); |
+ int bytes_added = 0; |
+ |
+ while (bytes_added < count) { |
+ if (current_block_ >= hash_reader_->block_count()) |
+ return DispatchFailureCallback(HASH_MISMATCH); |
+ |
+ if (!current_hash_.get()) { |
+ current_hash_byte_count_ = 0; |
+ current_hash_.reset( |
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256)); |
+ } |
+ // Compute how many bytes we should hash, and add them to the current hash. |
+ int bytes_to_hash = |
+ std::min(hash_reader_->block_size() - current_hash_byte_count_, |
+ count - bytes_added); |
+ current_hash_->Update(data + bytes_added, bytes_to_hash); |
+ bytes_added += bytes_to_hash; |
+ current_hash_byte_count_ += bytes_to_hash; |
+ total_bytes_read_ += bytes_to_hash; |
+ |
+ // If we finished reading a block worth of data, finish computing the hash |
+ // for it and make sure the expected hash matches. |
+ if (current_hash_byte_count_ == hash_reader_->block_size()) |
+ FinishBlock(); |
+ } |
} |
void ContentVerifyJob::DoneReading() { |
DCHECK(thread_checker_.CalledOnValidThread()); |
if (g_test_delegate) { |
- FailureReason reason = g_test_delegate->DoneReading(extension_id_); |
+ FailureReason reason = |
+ g_test_delegate->DoneReading(hash_reader_->extension_id()); |
if (reason != NONE) { |
DispatchFailureCallback(reason); |
return; |
} |
} |
+ done_reading_ = true; |
+ if (hashes_ready_) |
+ FinishBlock(); |
+} |
+ |
+void ContentVerifyJob::FinishBlock() { |
+ if (current_hash_byte_count_ <= 0) |
+ return; |
+ std::string final(crypto::kSHA256Length, 0); |
+ current_hash_->Finish(string_as_array(&final), final.size()); |
+ |
+ const std::string* expected_hash = NULL; |
+ if (!hash_reader_->GetHashForBlock(current_block_, &expected_hash)) |
+ return DispatchFailureCallback(HASH_MISMATCH); |
+ |
+ if (*expected_hash != final) |
+ return DispatchFailureCallback(HASH_MISMATCH); |
+ |
+ current_hash_.reset(); |
+ current_hash_byte_count_ = 0; |
+ current_block_++; |
+} |
+ |
+void ContentVerifyJob::OnHashesReady(bool success) { |
+ if (!success) |
+ return DispatchFailureCallback(NO_HASHES); |
+ |
+ hashes_ready_ = true; |
+ if (!queue_.empty()) { |
+ std::string tmp; |
+ queue_.swap(tmp); |
+ BytesRead(tmp.size(), string_as_array(&tmp)); |
+ } |
+ if (done_reading_) |
+ FinishBlock(); |
} |
// static |