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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/safe_browsing/malware_details_cache.cc
===================================================================
--- chrome/browser/safe_browsing/malware_details_cache.cc (revision 0)
+++ chrome/browser/safe_browsing/malware_details_cache.cc (revision 0)
@@ -0,0 +1,328 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Implementation of the MalwareDetails class.
+
+#include "chrome/browser/safe_browsing/malware_details.h"
+
+#include "base/callback.h"
+#include "base/lazy_instance.h"
+#include "base/md5.h"
+#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/safe_browsing/malware_details_cache.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/safe_browsing/report.pb.h"
+#include "content/browser/browser_thread.h"
+#include "net/base/io_buffer.h"
+#include "net/disk_cache/disk_cache.h"
+#include "net/http/http_cache.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_response_info.h"
+#include "net/url_request/url_request_context_getter.h"
+
+using safe_browsing::ClientMalwareReportRequest;
+
+// Only send small files for now, a better strategy would use the size
+// of the whole report and the user's bandwidth.
+static const int kMaxBodySizeBytes = 1024;
+
+MalwareDetailsCacheCollector::MalwareDetailsCacheCollector()
+ : cache_state_(STATE_NONE),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ cache_callback_(this , &MalwareDetailsCacheCollector::CacheLoop)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ entry_callback_(
+ new net::CancelableCompletionCallback<
+ MalwareDetailsCacheCollector>(
+ this, &MalwareDetailsCacheCollector::CacheLoop))) {
+}
+
+MalwareDetailsCacheCollector::~MalwareDetailsCacheCollector() {
+}
+
+void MalwareDetailsCacheCollector::StartCacheCollection(
+ net::URLRequestContextGetter* request_context_getter,
+ safe_browsing::ResourceMap* resources,
+ int* result,
+ Task* callback) {
+ // Start the data collection from the HTTP cache.
+ DVLOG(1) << "Getting disk_cache data for all urls...";
+ request_context_getter_ = request_context_getter;
+ resources_ = resources;
+ resources_it_ = resources_->begin();
+ cache_state_ = STATE_OPEN_CACHE;
+ result_ = result;
+ callback_ = callback;
+
+ AddRef(); // The cache_callback_ calls are asynchronous and not refcounted.
+
+ // Post a task in the message loop, so the callers don't need to
+ // check if we call their callback immediately.
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ this, &MalwareDetailsCacheCollector::CacheLoop, net::OK));
+}
+
+bool MalwareDetailsCacheCollector::InProgress() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ return cache_state_ != STATE_NONE;
+}
+
+// The IO thread loop. Called once the DOM details are callected,
+// and then is passed to all the cache lookups as a callback.
+void MalwareDetailsCacheCollector::CacheLoop(int result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(cache_state_ != STATE_NONE);
+
+ int rv = result;
+ do {
+ DVLOG(1) << "cache_state_:" << cache_state_;
+ CacheState state = cache_state_;
+ cache_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_OPEN_CACHE:
+ rv = DoOpenCache();
+ break;
+ case STATE_OPEN_CACHE_COMPLETE:
+ rv = DoOpenCacheComplete(rv);
+ break;
+ case STATE_OPEN_ENTRY:
+ rv = DoOpenEntry();
+ break;
+ case STATE_OPEN_ENTRY_COMPLETE:
+ rv = DoOpenEntryComplete(rv);
+ break;
+ case STATE_READ_RESPONSE:
+ rv = DoReadResponse();
+ break;
+ case STATE_READ_RESPONSE_COMPLETE:
+ rv = DoReadResponseComplete(rv);
+ break;
+ case STATE_READ_DATA:
+ rv = DoReadData();
+ break;
+ case STATE_READ_DATA_COMPLETE:
+ rv = DoReadDataComplete(rv);
+ break;
+ default:
+ NOTREACHED() << "Bad state:" << state;
+ rv = net::ERR_FAILED;
+ break;
+ }
+ } while (rv != net::ERR_IO_PENDING && cache_state_ != STATE_NONE);
+
+ if (rv != net::ERR_IO_PENDING) {
+ DVLOG(1) << "CacheIO done.";
+ DoCacheDone(rv);
+ }
+}
+
+net::URLRequestContext* MalwareDetailsCacheCollector::GetURLRequestContext() {
+ if (!request_context_getter_) {
+ DVLOG(1) << "Missing request context getter";
+ return NULL;
+ }
+ return request_context_getter_->GetURLRequestContext();
+}
+
+int MalwareDetailsCacheCollector::DoOpenCache() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ cache_state_ = STATE_OPEN_CACHE_COMPLETE;
+
+ net::URLRequestContext* context = GetURLRequestContext();
+ if (!context) {
+ DVLOG(1) << "Could not get URLRequestContext";
+ cache_state_ = STATE_NONE;
+ return net::ERR_FAILED;
+ }
+
+ if (!context->http_transaction_factory()) {
+ DVLOG(1) << "Could not get HTTP transaction factory";
+ cache_state_ = STATE_NONE;
+ return net::ERR_FAILED;
+ }
+
+ net::HttpCache* http_cache =
+ context->http_transaction_factory()->GetCache();
+ if (!http_cache) {
+ DVLOG(1) << "Could not get http cache";
+ cache_state_ = STATE_NONE;
+ return net::ERR_FAILED;
+ }
+
+ return http_cache->GetBackend(&cache_, &cache_callback_);
+}
+
+int MalwareDetailsCacheCollector::DoOpenCacheComplete(int result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ cache_state_ = STATE_OPEN_ENTRY;
+
+ if (result == net::ERR_FAILED || !cache_) {
+ DVLOG(1) << "Could not get disk cache";
+ cache_state_ = STATE_NONE;
+ return net::ERR_FAILED;
+ }
+
+ return net::OK;
+}
+
+int MalwareDetailsCacheCollector::DoOpenEntry() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ cache_state_ = STATE_OPEN_ENTRY_COMPLETE;
+
+ if (resources_it_ == resources_->end()) {
+ cache_state_ = STATE_NONE;
+ return net::OK;
+ }
+
+ entry_ = NULL; // Reset the entry.
+ // resources_it_ is an iterator to a map, key = URL, value =
+ // ClientMalwareReportRequest::Resource.
+ return cache_->OpenEntry(resources_it_->first, &entry_, &cache_callback_);
+}
+
+int MalwareDetailsCacheCollector::DoOpenEntryComplete(int rv) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (rv != net::OK || !entry_) {
+ DVLOG(1) << "Error opening entry, or entry not found: Advancing.";
+ return AdvanceEntry();
+ }
+
+ cache_state_ = STATE_READ_RESPONSE;
+ return net::OK;
+}
+
+int MalwareDetailsCacheCollector::DoReadResponse() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ cache_state_ = STATE_READ_RESPONSE_COMPLETE;
+
+ // net::HttpCache::kResponseInfoIndex = 0.
+ buf_len_ = entry_->GetDataSize(0);
+ if (!buf_len_) {
+ DVLOG(1) << "Empty response";
+ return AdvanceEntry();
+ }
+
+ buf_ = new net::IOBuffer(buf_len_);
+ return entry_->ReadData(0, 0, buf_, buf_len_, entry_callback_);
+}
+
+// Here, |result| is the length of the buffer read.
+int MalwareDetailsCacheCollector::DoReadResponseComplete(int result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ cache_state_ = STATE_READ_DATA;
+
+ if (!result || result != buf_len_) {
+ DVLOG(1) << "Empty buffer or buffer length mismatch.";
+ // Reset buf_ and buf_len_.
+ buf_ = NULL;
+ buf_len_ = 0;
noelutz 2011/04/11 20:32:11 Before you set buf_ to NULL do you need to delete
panayiotis 2011/04/11 21:42:16 Since buf_ is a scoped_refptr, we shouldn't delete
noelutz 2011/04/11 21:49:15 Woops. I missed that. LG.
+ return AdvanceEntry();
+ }
+
+ linked_ptr<ClientMalwareReportRequest::Resource>
+ pb_resource = resources_it_->second;
+ net::HttpResponseInfo response;
+ bool truncated;
+ if (net::HttpCache::ParseResponseInfo(buf_->data(), buf_len_, &response,
+ &truncated)) {
+ if (!truncated) {
+ if (response.headers) {
+ ClientMalwareReportRequest::HTTPResponse* pb_response =
+ pb_resource->mutable_response();
+ pb_response->mutable_firstline()->set_code(
+ response.headers->response_code());
+ void* iter = NULL;
+ std::string name, value;
+ while (response.headers->EnumerateHeaderLines(&iter, &name, &value)) {
+ ClientMalwareReportRequest::HTTPHeader* pb_header =
+ pb_response->add_headers();
+ pb_header->set_name(name);
+ // Strip any Set-Cookie headers.
+ if (LowerCaseEqualsASCII(name, "set-cookie")) {
+ pb_header->set_value("");
+ } else {
+ pb_header->set_value(value);
+ }
+ }
+ } else {
+ DVLOG(1) << "Missing response headers.";
+ }
+ } else {
+ DVLOG(1) << "Response truncated";
+ }
+ } else {
+ DVLOG(1) << "Could not parse HTTP cache entry";
+ }
+
+ // Reset buf_ and buf_len_.
+ buf_ = NULL;
noelutz 2011/04/11 20:32:11 Same here? Delete buf_?
panayiotis 2011/04/11 21:42:16 same
+ buf_len_ = 0;
+ return net::OK;
+}
+
+int MalwareDetailsCacheCollector::DoReadData() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ cache_state_ = STATE_READ_DATA_COMPLETE;
+
+ // net::HttpCache::kResponseContentIndex = 1.
+ buf_len_ = entry_->GetDataSize(1);
+ if (!buf_len_) {
+ DVLOG(1) << "Empty data";
+ return AdvanceEntry();
+ }
+
+ buf_ = new net::IOBuffer(buf_len_);
+ return entry_->ReadData(1, 0, buf_, buf_len_, entry_callback_);
+}
+
+// Here, |result| is the length of the buffer read.
+int MalwareDetailsCacheCollector::DoReadDataComplete(int result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ if (result && result == buf_len_) {
+ linked_ptr<ClientMalwareReportRequest::Resource>
+ pb_resource = resources_it_->second;
+ ClientMalwareReportRequest::HTTPResponse* pb_response =
+ pb_resource->mutable_response();
+ if (buf_len_ <= kMaxBodySizeBytes) { // Only send small bodies for now.
+ pb_response->set_body(buf_->data(), buf_len_);
+ }
+ pb_response->set_bodylength(buf_len_);
+ MD5Digest digest;
+ MD5Sum(buf_->data(), buf_len_, &digest);
+ pb_response->set_bodydigest(MD5DigestToBase16(digest));
+ }
+
+ // Reset buf_ and buf_len.
+ buf_ = NULL;
noelutz 2011/04/11 20:32:11 Same here?
panayiotis 2011/04/11 21:42:16 same
+ buf_len_ = 0;
+ return AdvanceEntry();
+}
+
+int MalwareDetailsCacheCollector::AdvanceEntry() {
+ // Close this entry, advance to the next one. Create a task so we don't
+ // take over the IO thread for too long.
+ cache_state_ = STATE_OPEN_ENTRY;
+ ++resources_it_;
+ if (entry_)
+ entry_->Close();
noelutz 2011/04/11 20:32:11 Maybe set entry_ to NULL?
panayiotis 2011/04/11 21:42:16 Done.
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ this, &MalwareDetailsCacheCollector::CacheLoop, net::OK));
+
+ return net::ERR_IO_PENDING;
+}
+
+void MalwareDetailsCacheCollector::DoCacheDone(int result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ *result_ = result;
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback_);
+
+ Release();
+ // We are now deleted.
+}
Property changes on: chrome/browser/safe_browsing/malware_details_cache.cc
___________________________________________________________________
Added: svn:eol-style
+ LF
« no previous file with comments | « chrome/browser/safe_browsing/malware_details_cache.h ('k') | chrome/browser/safe_browsing/malware_details_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698