Chromium Code Reviews| 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,200 @@ |
| +// 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/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/load_flags.h" |
| +#include "net/http/http_response_headers.h" |
| +#include "net/url_request/url_request_context_getter.h" |
| +#include "net/url_request/url_request_status.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 uint32 kMaxBodySizeBytes = 1024; |
| + |
| +MalwareDetailsCacheCollector::MalwareDetailsCacheCollector() |
| + : has_started_(false), |
| + current_fetch_(NULL) { |
| +} |
| + |
| +MalwareDetailsCacheCollector::~MalwareDetailsCacheCollector() { |
| +} |
| + |
| +void MalwareDetailsCacheCollector::StartCacheCollection( |
| + net::URLRequestContextGetter* request_context_getter, |
| + safe_browsing::ResourceMap* resources, |
| + bool* result, |
| + Task* callback) { |
| + // Start the data collection from the HTTP cache. We use a URLFetcher |
| + // and set the right flags so we only hit the cache. |
| + DVLOG(1) << "Getting cache data for all urls..."; |
| + request_context_getter_ = request_context_getter; |
| + resources_ = resources; |
| + resources_it_ = resources_->begin(); |
| + result_ = result; |
| + callback_ = callback; |
| + has_started_ = true; |
| + |
| + // 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::OpenEntry)); |
| +} |
| + |
| +bool MalwareDetailsCacheCollector::HasStarted() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + return has_started_; |
| +} |
| + |
| +// Fetch a URL and advance to the next one when done. |
| +void MalwareDetailsCacheCollector::OpenEntry() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DVLOG(1) << "OpenEntry"; |
| + |
| + if (resources_it_ == resources_->end()) { // We are done. |
| + AllDone(true); |
| + return; |
| + } |
| + |
| + if (!request_context_getter_) { |
| + DVLOG(1) << "Missing request context getter"; |
| + AllDone(false); |
| + return; |
| + } |
| + |
| + current_fetch_.reset(new URLFetcher( |
| + GURL(resources_it_->first), |
| + URLFetcher::GET, |
| + this)); |
| + current_fetch_->set_request_context(request_context_getter_); |
| + // Only from cache, and don't save cookies. |
| + current_fetch_->set_load_flags(net::LOAD_ONLY_FROM_CACHE | |
| + net::LOAD_DO_NOT_SAVE_COOKIES); |
| + current_fetch_->set_automatically_retry_on_5xx(false); // No retries. |
| + current_fetch_->Start(); // OnURLFetchComplete will be called when done. |
| +} |
| + |
| +ClientMalwareReportRequest::Resource* MalwareDetailsCacheCollector::GetResource( |
| + const GURL& url) { |
| + safe_browsing::ResourceMap::iterator it = resources_->find(url.spec()); |
| + if (it != resources_->end()) { |
| + return it->second.get(); |
| + } |
| + return NULL; |
| +} |
| + |
| +void MalwareDetailsCacheCollector::OnURLFetchComplete( |
| + const URLFetcher* source, |
| + const GURL& url, |
| + const net::URLRequestStatus& status, |
| + int response_code, |
| + const ResponseCookies& cookies, |
| + const std::string& data) { |
| + DVLOG(1) << "OnUrlFetchComplete"; |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK(current_fetch_.get()); |
| + if (resources_it_->first != url.spec()) { |
| + DVLOG(1) << "Mismatching urls (probably a redirect)" << |
| + resources_it_->first << " vs " << url; |
| + } |
| + |
| + if (status.status() != net::URLRequestStatus::SUCCESS && |
| + status.os_error() == net::ERR_CACHE_MISS) { |
|
mattm
2011/04/18 02:19:24
do we need a test for status != SUCCESS && os_erro
panayiotis
2011/04/18 17:26:40
Done.
|
| + // Cache miss, skip this resource. |
| + DVLOG(1) << "Cache miss for url: " << url; |
| + AdvanceEntry(); |
| + return; |
| + } |
| + |
| + // Set the response headers and body to the right resource, which |
| + // might not be the same as the one we asked for. |
| + ClientMalwareReportRequest::Resource* resource = GetResource(url); |
| + if (!resource) { |
| + DVLOG(1) << "Cannot find resource for url:" << url; |
| + AdvanceEntry(); |
| + return; |
| + } |
| + |
| + ReadResponse(resource, source); |
| + ReadData(resource, data); |
| + AdvanceEntry(); |
| +} |
| + |
| +void MalwareDetailsCacheCollector::ReadResponse( |
| + ClientMalwareReportRequest::Resource* pb_resource, |
| + const URLFetcher* source) { |
| + DVLOG(1) << "ReadResponse"; |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + net::HttpResponseHeaders* headers = source->response_headers(); |
| + if (!headers) { |
| + DVLOG(1) << "Missing response headers."; |
| + return; |
| + } |
| + |
| + ClientMalwareReportRequest::HTTPResponse* pb_response = |
| + pb_resource->mutable_response(); |
| + pb_response->mutable_firstline()->set_code(headers->response_code()); |
| + void* iter = NULL; |
| + std::string name, value; |
| + while (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); |
| + } |
| + } |
| +} |
| + |
| +void MalwareDetailsCacheCollector::ReadData( |
| + ClientMalwareReportRequest::Resource* pb_resource, |
| + const std::string& data) { |
| + DVLOG(1) << "ReadData"; |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + ClientMalwareReportRequest::HTTPResponse* pb_response = |
| + pb_resource->mutable_response(); |
| + if (data.size() <= kMaxBodySizeBytes) { // Only send small bodies for now. |
| + pb_response->set_body(data); |
| + } |
| + pb_response->set_bodylength(data.size()); |
| + MD5Digest digest; |
| + MD5Sum(data.c_str(), data.size(), &digest); |
| + pb_response->set_bodydigest(MD5DigestToBase16(digest)); |
| +} |
| + |
| +void MalwareDetailsCacheCollector::AdvanceEntry() { |
| + DVLOG(1) << "AdvanceEntry"; |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + // Advance to the next resource. |
| + ++resources_it_; |
| + current_fetch_.reset(NULL); |
| + |
| + // Create a task so we don't take over the IO thread for too long. |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, FROM_HERE, |
| + NewRunnableMethod(this, &MalwareDetailsCacheCollector::OpenEntry)); |
| +} |
| + |
| +void MalwareDetailsCacheCollector::AllDone(bool success) { |
| + DVLOG(1) << "AllDone"; |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + *result_ = success; |
| + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback_); |
| +} |
| Property changes on: chrome/browser/safe_browsing/malware_details_cache.cc |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |