| 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,304 @@
|
| +// 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 "chrome/common/net/url_request_context_getter.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"
|
| +
|
| +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 kMaxBodySize = 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() {
|
| +}
|
| +
|
| +// We modify |resources|, so it must remain alive.
|
| +void MalwareDetailsCacheCollector::StartCacheCollection(
|
| + URLRequestContextGetter* request_context_getter,
|
| + safe_browsing::ResourceMap* resources,
|
| + MalwareDetailsCacheCollectorCallback* 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;
|
| + callback_ = callback;
|
| +
|
| + AddRef(); // The cache calls are asynchronous.
|
| +
|
| + // 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() {
|
| + 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) {
|
| + LOG(ERROR) << "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_) {
|
| + LOG(ERROR) << "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.
|
| + return cache_->OpenEntry(resources_it_->first, &entry_, &cache_callback_);
|
| +}
|
| +
|
| +int MalwareDetailsCacheCollector::DoOpenEntryComplete(int rv) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + cache_state_ = STATE_READ_RESPONSE;
|
| + return net::OK;
|
| +}
|
| +
|
| +int MalwareDetailsCacheCollector::DoReadResponse() {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + cache_state_ = STATE_READ_RESPONSE_COMPLETE;
|
| + // entry_callback_->AddRef();
|
| +
|
| + if (!entry_) { // No entry in the cache for this url.
|
| + return net::OK;
|
| + }
|
| +
|
| + // net::HttpCache::kResponseInfoIndex = 0.
|
| + buf_len_ = entry_->GetDataSize(0);
|
| + if (!buf_len_) {
|
| + DVLOG(1) << "Empty response";
|
| + return buf_len_;
|
| + }
|
| +
|
| + buf_ = new net::IOBuffer(buf_len_);
|
| + return entry_->ReadData(0, 0, buf_, buf_len_, entry_callback_);
|
| +}
|
| +
|
| +int MalwareDetailsCacheCollector::DoReadResponseComplete(int result) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + cache_state_ = STATE_READ_DATA;
|
| + // entry_callback_->Release();
|
| +
|
| + if (!entry_ || !result || result != buf_len_) {
|
| + DVLOG(1) << "No entry";
|
| + } else {
|
| + 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)) {
|
| + // Strip any Set-Cookie headers.
|
| + if (LowerCaseEqualsASCII(name, "set-cookie")) {
|
| + continue;
|
| + }
|
| + ClientMalwareReportRequest::HTTPHeader* pb_header =
|
| + pb_response->add_headers();
|
| + pb_header->set_name(name);
|
| + pb_header->set_value(value);
|
| + }
|
| + } else {
|
| + DVLOG(1) << "Missing response headers.";
|
| + }
|
| + } else {
|
| + DVLOG(1) << "Response truncated";
|
| + }
|
| + } else {
|
| + LOG(ERROR) << "Could not parse HTTP cache entry";
|
| + }
|
| + }
|
| +
|
| + return net::OK;
|
| +}
|
| +
|
| +int MalwareDetailsCacheCollector::DoReadData() {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + cache_state_ = STATE_READ_DATA_COMPLETE;
|
| + // entry_callback_->AddRef();
|
| +
|
| + if (!entry_) { // No entry in the cache for this url.
|
| + return net::OK;
|
| + }
|
| +
|
| + // net::HttpCache::kResponseContentIndex = 1.
|
| + buf_len_ = entry_->GetDataSize(1);
|
| + if (!buf_len_) {
|
| + DVLOG(1) << "Empty data";
|
| + return buf_len_;
|
| + }
|
| +
|
| + buf_ = new net::IOBuffer(buf_len_);
|
| + return entry_->ReadData(1, 0, buf_, buf_len_, entry_callback_);
|
| +}
|
| +
|
| +int MalwareDetailsCacheCollector::DoReadDataComplete(int result) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + cache_state_ = STATE_OPEN_ENTRY;
|
| + // entry_callback_->Release();
|
| +
|
| + if (entry_ && result && result == buf_len_) {
|
| + linked_ptr<ClientMalwareReportRequest::Resource>
|
| + pb_resource = resources_it_->second;
|
| + ClientMalwareReportRequest::HTTPResponse* pb_response =
|
| + pb_resource->mutable_response();
|
| + if (buf_len_ <= kMaxBodySize) { // 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));
|
| + entry_->Close();
|
| + }
|
| +
|
| + ++resources_it_; // Advance to the next entry.
|
| + return net::OK;
|
| +}
|
| +
|
| +void MalwareDetailsCacheCollector::DoCacheDone(int result) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + callback_->Run(result); // Runs MalwareDetails::OnCacheCollectionReady.
|
| +
|
| + Release();
|
| + // We are now deleted.
|
| +}
|
|
|
| Property changes on: chrome/browser/safe_browsing/malware_details_cache.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|