Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / extensions / browser / content_verify_job.cc
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.
4
5 #include "extensions/browser/content_verify_job.h"
6
7 #include <algorithm>
8
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"
15
16 namespace extensions {
17
18 namespace {
19
20 ContentVerifyJob::TestDelegate* g_test_delegate = NULL;
21
22 }  // namespace
23
24 ContentVerifyJob::ContentVerifyJob(ContentHashReader* hash_reader,
25                                    const FailureCallback& 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) {
33   // It's ok for this object to be constructed on a different thread from where
34   // it's used.
35   thread_checker_.DetachFromThread();
36 }
37
38 ContentVerifyJob::~ContentVerifyJob() {
39 }
40
41 void ContentVerifyJob::Start() {
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));
48 }
49
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);
55     if (reason != NONE)
56       return DispatchFailureCallback(reason);
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   }
88 }
89
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());
95     if (reason != NONE) {
96       DispatchFailureCallback(reason);
97       return;
98     }
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 && !g_test_delegate)
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();
135 }
136
137 // static
138 void ContentVerifyJob::SetDelegateForTests(TestDelegate* delegate) {
139   g_test_delegate = delegate;
140 }
141
142 void ContentVerifyJob::DispatchFailureCallback(FailureReason reason) {
143   if (!failure_callback_.is_null()) {
144     failure_callback_.Run(reason);
145     failure_callback_.Reset();
146   }
147 }
148
149 }  // namespace extensions