1// Copyright (c) 2012 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 MalwareDetailsRedirectsCollector class.
6
7#include "chrome/browser/safe_browsing/malware_details_history.h"
8
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "chrome/browser/chrome_notification_types.h"
12#include "chrome/browser/history/history_service_factory.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/browser/safe_browsing/malware_details.h"
15#include "content/public/browser/browser_thread.h"
16#include "content/public/browser/notification_details.h"
17#include "content/public/browser/notification_source.h"
18#include "content/public/browser/render_view_host.h"
19#include "content/public/browser/web_contents.h"
20
21using content::BrowserThread;
22
23MalwareDetailsRedirectsCollector::MalwareDetailsRedirectsCollector(
24    Profile* profile)
25    : profile_(profile),
26      has_started_(false) {
27  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
28  if (profile) {
29    registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
30                   content::Source<Profile>(profile));
31  }
32}
33
34void MalwareDetailsRedirectsCollector::StartHistoryCollection(
35    const std::vector<GURL>& urls,
36    const base::Closure& callback) {
37  DVLOG(1) << "Num of urls to check in history service: " << urls.size();
38  has_started_ = true;
39  callback_ = callback;
40
41  if (urls.size() == 0) {
42    AllDone();
43    return;
44  }
45
46  BrowserThread::PostTask(
47      BrowserThread::UI, FROM_HERE,
48      base::Bind(&MalwareDetailsRedirectsCollector::StartGetRedirects,
49                 this, urls));
50}
51
52bool MalwareDetailsRedirectsCollector::HasStarted() const {
53  return has_started_;
54}
55
56const std::vector<safe_browsing::RedirectChain>&
57MalwareDetailsRedirectsCollector::GetCollectedUrls() const {
58  return redirects_urls_;
59}
60
61void MalwareDetailsRedirectsCollector::Observe(
62    int type,
63    const content::NotificationSource& source,
64    const content::NotificationDetails& details) {
65  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
66  DCHECK_EQ(type, chrome::NOTIFICATION_PROFILE_DESTROYED);
67  DVLOG(1) << "Profile gone.";
68  profile_ = NULL;
69}
70
71MalwareDetailsRedirectsCollector::~MalwareDetailsRedirectsCollector() {}
72
73void MalwareDetailsRedirectsCollector::StartGetRedirects(
74        const std::vector<GURL>& urls) {
75  // History access from profile needs to happen in UI thread
76  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
77  for (size_t i = 0; i < urls.size(); ++i) {
78    urls_.push_back(urls[i]);
79  }
80  urls_it_ = urls_.begin();
81  GetRedirects(*urls_it_);
82}
83
84void MalwareDetailsRedirectsCollector::GetRedirects(const GURL& url) {
85  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
86  if (!profile_) {
87    AllDone();
88    return;
89  }
90
91  HistoryService* history = HistoryServiceFactory::GetForProfile(
92      profile_, Profile::EXPLICIT_ACCESS);
93  if (!history) {
94    AllDone();
95    return;
96  }
97
98  history->QueryRedirectsTo(
99      url,
100      base::Bind(&MalwareDetailsRedirectsCollector::OnGotQueryRedirectsTo,
101                 base::Unretained(this),
102                 url),
103      &request_tracker_);
104}
105
106void MalwareDetailsRedirectsCollector::OnGotQueryRedirectsTo(
107    const GURL& url,
108    const history::RedirectList* redirect_list) {
109  if (!redirect_list->empty()) {
110    std::vector<GURL> urllist;
111    urllist.push_back(url);
112    urllist.insert(urllist.end(), redirect_list->begin(), redirect_list->end());
113    redirects_urls_.push_back(urllist);
114  }
115
116  // Proceed to next url
117  ++urls_it_;
118
119  if (urls_it_ == urls_.end()) {
120    AllDone();
121    return;
122  }
123
124  GetRedirects(*urls_it_);
125}
126
127void MalwareDetailsRedirectsCollector::AllDone() {
128  DVLOG(1) << "AllDone";
129  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback_);
130  callback_.Reset();
131}
132