15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implementation of the MalwareDetails class.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/safe_browsing/malware_details.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/md5.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/net/chrome_url_request_context_getter.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/safe_browsing/malware_details_cache.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/safe_browsing/report.pb.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/safe_browsing/safe_browsing_service.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/host_port_pair.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/load_flags.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_response_headers.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_status.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using safe_browsing::ClientMalwareReportRequest;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Only send small files for now, a better strategy would use the size
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of the whole report and the user's bandwidth.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const uint32 kMaxBodySizeBytes = 1024;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MalwareDetailsCacheCollector::MalwareDetailsCacheCollector()
347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    : resources_(NULL), result_(NULL), has_started_(false) {}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MalwareDetailsCacheCollector::StartCacheCollection(
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::URLRequestContextGetter* request_context_getter,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    safe_browsing::ResourceMap* resources,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool* result,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Closure& callback) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start the data collection from the HTTP cache. We use a URLFetcher
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and set the right flags so we only hit the cache.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Getting cache data for all urls...";
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_context_getter_ = request_context_getter;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resources_ = resources;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resources_it_ = resources_->begin();
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result_ = result;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_ = callback;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  has_started_ = true;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Post a task in the message loop, so the callers don't need to
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // check if we call their callback immediately.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::IO, FROM_HERE,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&MalwareDetailsCacheCollector::OpenEntry, this));
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MalwareDetailsCacheCollector::HasStarted() {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return has_started_;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MalwareDetailsCacheCollector::~MalwareDetailsCacheCollector() {}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Fetch a URL and advance to the next one when done.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MalwareDetailsCacheCollector::OpenEntry() {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "OpenEntry";
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (resources_it_ == resources_->end()) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AllDone(true);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!request_context_getter_.get()) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Missing request context getter";
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AllDone(false);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_fetch_.reset(net::URLFetcher::Create(
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GURL(resources_it_->first), net::URLFetcher::GET, this));
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  current_fetch_->SetRequestContext(request_context_getter_.get());
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only from cache, and don't save cookies.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_fetch_->SetLoadFlags(net::LOAD_ONLY_FROM_CACHE |
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               net::LOAD_DO_NOT_SAVE_COOKIES);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_fetch_->SetAutomaticallyRetryOn5xx(false);  // No retries.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_fetch_->Start();  // OnURLFetchComplete will be called when done.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ClientMalwareReportRequest::Resource* MalwareDetailsCacheCollector::GetResource(
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  safe_browsing::ResourceMap::iterator it = resources_->find(url.spec());
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != resources_->end()) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return it->second.get();
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MalwareDetailsCacheCollector::OnURLFetchComplete(
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLFetcher* source) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "OnUrlFetchComplete";
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(current_fetch_.get());
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (source->GetStatus().status() != net::URLRequestStatus::SUCCESS &&
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      source->GetStatus().error() == net::ERR_CACHE_MISS) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Cache miss, skip this resource.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Cache miss for url: " << source->GetURL();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AdvanceEntry();
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (source->GetStatus().status() != net::URLRequestStatus::SUCCESS) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Some other error occurred, e.g. the request could have been cancelled.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Unsuccessful fetch: " << source->GetURL();
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AdvanceEntry();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the response headers and body to the right resource, which
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // might not be the same as the one we asked for.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For redirects, resources_it_->first != url.spec().
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientMalwareReportRequest::Resource* resource =
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetResource(source->GetURL());
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!resource) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Cannot find resource for url:" << source->GetURL();
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AdvanceEntry();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReadResponse(resource, source);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string data;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  source->GetResponseAsString(&data);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReadData(resource, data);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AdvanceEntry();
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MalwareDetailsCacheCollector::ReadResponse(
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClientMalwareReportRequest::Resource* pb_resource,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLFetcher* source) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "ReadResponse";
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::HttpResponseHeaders* headers = source->GetResponseHeaders();
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!headers) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Missing response headers.";
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientMalwareReportRequest::HTTPResponse* pb_response =
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pb_resource->mutable_response();
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pb_response->mutable_firstline()->set_code(headers->response_code());
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* iter = NULL;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string name, value;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClientMalwareReportRequest::HTTPHeader* pb_header =
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pb_response->add_headers();
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pb_header->set_name(name);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Strip any Set-Cookie headers.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (LowerCaseEqualsASCII(name, "set-cookie")) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pb_header->set_value("");
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pb_header->set_value(value);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!source->WasFetchedViaProxy()) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pb_response->set_remote_ip(source->GetSocketAddress().ToString());
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MalwareDetailsCacheCollector::ReadData(
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClientMalwareReportRequest::Resource* pb_resource,
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& data) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "ReadData";
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientMalwareReportRequest::HTTPResponse* pb_response =
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pb_resource->mutable_response();
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data.size() <= kMaxBodySizeBytes) {  // Only send small bodies for now.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pb_response->set_body(data);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pb_response->set_bodylength(data.size());
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MD5Digest digest;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MD5Sum(data.c_str(), data.size(), &digest);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pb_response->set_bodydigest(base::MD5DigestToBase16(digest));
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MalwareDetailsCacheCollector::AdvanceEntry() {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "AdvanceEntry";
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Advance to the next resource.
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ++resources_it_;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_fetch_.reset(NULL);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a task so we don't take over the IO thread for too long.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::IO, FROM_HERE,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&MalwareDetailsCacheCollector::OpenEntry, this));
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MalwareDetailsCacheCollector::AllDone(bool success) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "AllDone";
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *result_ = success;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback_);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_.Reset();
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
207