Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(22)

Side by Side Diff: chrome/browser/safe_browsing/malware_details_cache.cc

Issue 6611023: The optional Malware Details also collects HTTP cache information. See design... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 // Implementation of the MalwareDetails class.
6
7 #include "chrome/browser/safe_browsing/malware_details.h"
8
9 #include "base/callback.h"
10 #include "base/lazy_instance.h"
11 #include "base/md5.h"
12 #include "chrome/browser/net/chrome_url_request_context.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/safe_browsing/malware_details_cache.h"
15 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
16 #include "chrome/browser/safe_browsing/report.pb.h"
17 #include "chrome/common/net/url_request_context_getter.h"
18 #include "content/browser/browser_thread.h"
19 #include "net/base/io_buffer.h"
20 #include "net/disk_cache/disk_cache.h"
21 #include "net/http/http_cache.h"
22 #include "net/http/http_response_headers.h"
23 #include "net/http/http_response_info.h"
24
25 using safe_browsing::ClientMalwareReportRequest;
26
27 // Only send small files for now, a better strategy would use the size
28 // of the whole report and the user's bandwidth.
29 static const int kMaxBodySize = 1024;
noelutz 2011/04/06 20:34:19 Is this in bytes or KB?
panayiotis 2011/04/07 20:08:32 Done.
30
31 MalwareDetailsCacheCollector::MalwareDetailsCacheCollector()
32 : cache_state_(STATE_NONE),
33 ALLOW_THIS_IN_INITIALIZER_LIST(
34 cache_callback_(this , &MalwareDetailsCacheCollector::CacheLoop)),
35 ALLOW_THIS_IN_INITIALIZER_LIST(
36 entry_callback_(
37 new net::CancelableCompletionCallback<
38 MalwareDetailsCacheCollector>(
39 this, &MalwareDetailsCacheCollector::CacheLoop))) {
40 }
41
42 MalwareDetailsCacheCollector::~MalwareDetailsCacheCollector() {
43 }
44
45 // We modify |resources| and |result|, so it must remain alive.
noelutz 2011/04/06 20:34:19 Consider moving this comment to the header file.
panayiotis 2011/04/07 20:08:32 Done.
46 void MalwareDetailsCacheCollector::StartCacheCollection(
47 URLRequestContextGetter* request_context_getter,
48 safe_browsing::ResourceMap* resources,
49 int* result,
50 Task* callback) {
51 // Start the data collection from the HTTP cache.
52 DVLOG(1) << "Getting disk_cache data for all urls...";
53 request_context_getter_ = request_context_getter;
54 resources_ = resources;
55 resources_it_ = resources_->begin();
56 cache_state_ = STATE_OPEN_CACHE;
57 result_ = result;
58 callback_ = callback;
59
60 AddRef(); // The cache_callback_ calls are asynchronous and not refcounted.
61
62 // Post a task in the message loop, so the callers don't need to
63 // check if we call their callback immediately.
64 BrowserThread::PostTask(
65 BrowserThread::IO, FROM_HERE,
66 NewRunnableMethod(
67 this, &MalwareDetailsCacheCollector::CacheLoop, net::OK));
68 }
69
70 bool MalwareDetailsCacheCollector::InProgress() {
71 return cache_state_ != STATE_NONE;
noelutz 2011/04/06 20:34:19 I assume this is also always called on the IO thre
panayiotis 2011/04/07 20:08:32 Done.
72 }
73
74 // The IO thread loop. Called once the DOM details are callected,
75 // and then is passed to all the cache lookups as a callback.
76 void MalwareDetailsCacheCollector::CacheLoop(int result) {
77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
78 DCHECK(cache_state_ != STATE_NONE);
79
80 int rv = result;
81 do {
82 DVLOG(1) << "cache_state_:" << cache_state_;
83 CacheState state = cache_state_;
84 cache_state_ = STATE_NONE;
85 switch (state) {
86 case STATE_OPEN_CACHE:
87 rv = DoOpenCache();
88 break;
89 case STATE_OPEN_CACHE_COMPLETE:
90 rv = DoOpenCacheComplete(rv);
91 break;
92 case STATE_OPEN_ENTRY:
93 rv = DoOpenEntry();
94 break;
95 case STATE_OPEN_ENTRY_COMPLETE:
96 rv = DoOpenEntryComplete(rv);
97 break;
98 case STATE_READ_RESPONSE:
99 rv = DoReadResponse();
100 break;
101 case STATE_READ_RESPONSE_COMPLETE:
102 rv = DoReadResponseComplete(rv);
103 break;
104 case STATE_READ_DATA:
105 rv = DoReadData();
106 break;
107 case STATE_READ_DATA_COMPLETE:
108 rv = DoReadDataComplete(rv);
109 break;
110 default:
111 NOTREACHED() << "Bad state:" << state;
112 rv = net::ERR_FAILED;
113 break;
114 }
115 } while (rv != net::ERR_IO_PENDING && cache_state_ != STATE_NONE);
noelutz 2011/04/06 20:34:19 I'm wondering if it's OK to do all these operation
panayiotis 2011/04/07 20:08:32 Done.
116
117 if (rv != net::ERR_IO_PENDING) {
118 DVLOG(1) << "CacheIO done.";
119 DoCacheDone(rv);
120 }
121 }
122
123 net::URLRequestContext* MalwareDetailsCacheCollector::GetURLRequestContext() {
124 if (!request_context_getter_) {
125 DVLOG(1) << "Missing request context getter";
126 return NULL;
127 }
128 return request_context_getter_->GetURLRequestContext();
129 }
130
131 int MalwareDetailsCacheCollector::DoOpenCache() {
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
133 cache_state_ = STATE_OPEN_CACHE_COMPLETE;
134
135 net::URLRequestContext* context = GetURLRequestContext();
136 if (!context) {
137 LOG(ERROR) << "Could not get URLRequestContext";
noelutz 2011/04/06 20:34:19 Is there a particular reason you LOG(ERROR) here b
panayiotis 2011/04/07 20:08:32 Done.
138 cache_state_ = STATE_NONE;
139 return net::ERR_FAILED;
140 }
141
142 if (!context->http_transaction_factory()) {
143 DVLOG(1) << "Could not get HTTP transaction factory";
144 cache_state_ = STATE_NONE;
145 return net::ERR_FAILED;
146 }
147
148 net::HttpCache* http_cache =
149 context->http_transaction_factory()->GetCache();
150 if (!http_cache) {
151 DVLOG(1) << "Could not get http cache";
152 cache_state_ = STATE_NONE;
153 return net::ERR_FAILED;
154 }
155
156 return http_cache->GetBackend(&cache_, &cache_callback_);
157 }
158
159 int MalwareDetailsCacheCollector::DoOpenCacheComplete(int result) {
160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
161 cache_state_ = STATE_OPEN_ENTRY;
162
163 if (result == net::ERR_FAILED || !cache_) {
164 LOG(ERROR) << "Could not get disk cache";
165 cache_state_ = STATE_NONE;
166 return net::ERR_FAILED;
167 }
168
169 return net::OK;
170 }
171
172 int MalwareDetailsCacheCollector::DoOpenEntry() {
173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
174 cache_state_ = STATE_OPEN_ENTRY_COMPLETE;
175
176 if (resources_it_ == resources_->end()) {
177 cache_state_ = STATE_NONE;
178 return net::OK;
179 }
180
181 entry_ = NULL; // Reset the entry.
182 return cache_->OpenEntry(resources_it_->first, &entry_, &cache_callback_);
noelutz 2011/04/06 20:34:19 Maybe mention what resources_it_ refers to?
panayiotis 2011/04/07 20:08:32 Done.
183 }
184
185 int MalwareDetailsCacheCollector::DoOpenEntryComplete(int rv) {
186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
187 cache_state_ = STATE_READ_RESPONSE;
188 return net::OK;
noelutz 2011/04/06 20:34:19 I think there might be a bug here. I think OpenEn
panayiotis 2011/04/07 20:08:32 Done.
189 }
190
191 int MalwareDetailsCacheCollector::DoReadResponse() {
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
193 cache_state_ = STATE_READ_RESPONSE_COMPLETE;
194
195 if (!entry_) { // No entry in the cache for this url.
noelutz 2011/04/06 20:34:19 Is that how you handle errors mentioned above? Ar
panayiotis 2011/04/07 20:08:32 Done.
196 return net::OK;
197 }
198
199 // net::HttpCache::kResponseInfoIndex = 0.
200 buf_len_ = entry_->GetDataSize(0);
noelutz 2011/04/06 20:34:19 why not use the constant then?
panayiotis 2011/04/07 20:08:32 It's not public.
201 if (!buf_len_) {
202 DVLOG(1) << "Empty response";
203 return buf_len_;
noelutz 2011/04/06 20:34:19 This is confusing. You always return net::somethi
panayiotis 2011/04/07 20:08:32 well, now we return net::ERR_PENDING but DoReadRe
204 }
205
206 buf_ = new net::IOBuffer(buf_len_);
207 return entry_->ReadData(0, 0, buf_, buf_len_, entry_callback_);
208 }
209
210 int MalwareDetailsCacheCollector::DoReadResponseComplete(int result) {
211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
212 cache_state_ = STATE_READ_DATA;
213
214 if (!entry_ || !result || result != buf_len_) {
215 DVLOG(1) << "No entry";
216 } else {
217 linked_ptr<ClientMalwareReportRequest::Resource>
218 pb_resource = resources_it_->second;
219 net::HttpResponseInfo response;
220 bool truncated;
221 if (net::HttpCache::ParseResponseInfo(buf_->data(), buf_len_, &response,
222 &truncated)) {
223 if (!truncated) {
224 if (response.headers) {
225 ClientMalwareReportRequest::HTTPResponse* pb_response =
226 pb_resource->mutable_response();
227 pb_response->mutable_firstline()->set_code(
228 response.headers->response_code());
229 void* iter = NULL;
230 std::string name, value;
231 while (response.headers->EnumerateHeaderLines(&iter, &name, &value)) {
232 // Strip any Set-Cookie headers.
233 if (LowerCaseEqualsASCII(name, "set-cookie")) {
234 continue;
235 }
236 ClientMalwareReportRequest::HTTPHeader* pb_header =
237 pb_response->add_headers();
238 pb_header->set_name(name);
239 pb_header->set_value(value);
240 }
241 } else {
242 DVLOG(1) << "Missing response headers.";
243 }
244 } else {
245 DVLOG(1) << "Response truncated";
246 }
247 } else {
248 LOG(ERROR) << "Could not parse HTTP cache entry";
249 }
250 }
251
252 return net::OK;
253 }
254
255 int MalwareDetailsCacheCollector::DoReadData() {
256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
257 cache_state_ = STATE_READ_DATA_COMPLETE;
noelutz 2011/04/06 20:34:19 skip this stage too if entry_ wasn't set?
panayiotis 2011/04/07 20:08:32 Done.
258
259 if (!entry_) { // No entry in the cache for this url.
260 return net::OK;
261 }
262
263 // net::HttpCache::kResponseContentIndex = 1.
264 buf_len_ = entry_->GetDataSize(1);
noelutz 2011/04/06 20:34:19 why not use the contant here too?
panayiotis 2011/04/07 20:08:32 same reason as above, not public.
265 if (!buf_len_) {
266 DVLOG(1) << "Empty data";
267 return buf_len_;
268 }
269
270 buf_ = new net::IOBuffer(buf_len_);
271 return entry_->ReadData(1, 0, buf_, buf_len_, entry_callback_);
noelutz 2011/04/06 20:34:19 also use the contant here?
panayiotis 2011/04/07 20:08:32 same
272 }
273
274 int MalwareDetailsCacheCollector::DoReadDataComplete(int result) {
275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
276 cache_state_ = STATE_OPEN_ENTRY;
277
278 if (entry_ && result && result == buf_len_) {
279 linked_ptr<ClientMalwareReportRequest::Resource>
280 pb_resource = resources_it_->second;
281 ClientMalwareReportRequest::HTTPResponse* pb_response =
282 pb_resource->mutable_response();
283 if (buf_len_ <= kMaxBodySize) { // Only send small bodies for now.
noelutz 2011/04/06 20:34:19 you know in the previous stage (DoReadData) that y
panayiotis 2011/04/07 20:08:32 Done.
noelutz 2011/04/11 20:32:10 I don't think this is done. Is there any reason n
panayiotis 2011/04/11 21:42:16 Oh sorry, I missed this. I actually do read the re
noelutz 2011/04/11 21:49:15 sounds good. i missed the digest part.
284 pb_response->set_body(buf_->data(), buf_len_);
285 }
286 pb_response->set_bodylength(buf_len_);
287 MD5Digest digest;
288 MD5Sum(buf_->data(), buf_len_, &digest);
289 pb_response->set_bodydigest(MD5DigestToBase16(digest));
290 entry_->Close();
noelutz 2011/04/06 20:34:19 If you do what I mentioned above make sure to clos
panayiotis 2011/04/07 20:08:32 Done.
291 }
292
293 ++resources_it_; // Advance to the next entry.
noelutz 2011/04/06 20:34:19 A few things here: - Before you go read the next
panayiotis 2011/04/07 20:08:32 setting buf_ = NULL now. I verified this releases
294 return net::OK;
295 }
296
297 void MalwareDetailsCacheCollector::DoCacheDone(int result) {
298 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
299 *result_ = result;
300 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback_);
301
302 Release();
303 // We are now deleted.
304 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698