summaryrefslogtreecommitdiffstats
path: root/chrome/browser/download/download_history.cc
blob: 115541a4d24742ed52fa9ed9683f915109b60175 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// 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.

#include "chrome/browser/download/download_history.h"

#include "base/logging.h"
#include "chrome/browser/history/download_history_info.h"
#include "chrome/browser/history/history_marshaling.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/profiles/profile.h"

// Our download table ID starts at 1, so we use 0 to represent a download that
// has started, but has not yet had its data persisted in the table. We use fake
// database handles in incognito mode starting at -1 and progressively getting
// more negative.
// static
const int DownloadHistory::kUninitializedHandle = 0;

DownloadHistory::DownloadHistory(Profile* profile)
    : profile_(profile),
      next_fake_db_handle_(kUninitializedHandle - 1) {
  DCHECK(profile);
}

DownloadHistory::~DownloadHistory() {
  // For any outstanding requests to
  // HistoryService::GetVisibleVisitCountToHost(), since they'll be cancelled
  // and thus not call back to OnGotVisitCountToHost(), we need to delete the
  // associated VisitedBeforeDoneCallbacks.
  for (VisitedBeforeRequestsMap::iterator i(visited_before_requests_.begin());
       i != visited_before_requests_.end(); ++i)
    delete i->second.second;
}

void DownloadHistory::Load(HistoryService::DownloadQueryCallback* callback) {
  DCHECK(callback);
  HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
  if (!hs) {
    delete callback;
    return;
  }
  hs->QueryDownloads(&history_consumer_, callback);

  // This is the initial load, so do a cleanup of corrupt in-progress entries.
  hs->CleanUpInProgressEntries();
}

void DownloadHistory::CheckVisitedReferrerBefore(
    int32 download_id,
    const GURL& referrer_url,
    VisitedBeforeDoneCallback* callback) {
  DCHECK(callback);

  if (referrer_url.is_valid()) {
    HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
    if (hs) {
      HistoryService::Handle handle =
          hs->GetVisibleVisitCountToHost(referrer_url, &history_consumer_,
              NewCallback(this, &DownloadHistory::OnGotVisitCountToHost));
      visited_before_requests_[handle] = std::make_pair(download_id, callback);
      return;
    }
  }
  callback->Run(download_id, false);
  delete callback;
}

void DownloadHistory::AddEntry(
    DownloadItem* download_item,
    HistoryService::DownloadCreateCallback* callback) {
  DCHECK(download_item);
  // Do not store the download in the history database for a few special cases:
  // - incognito mode (that is the point of this mode)
  // - extensions (users don't think of extension installation as 'downloading')
  // - temporary download, like in drag-and-drop
  // - history service is not available (e.g. in tests)
  // We have to make sure that these handles don't collide with normal db
  // handles, so we use a negative value. Eventually, they could overlap, but
  // you'd have to do enough downloading that your ISP would likely stab you in
  // the neck first. YMMV.
  HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
  if (download_item->is_otr() || download_item->is_extension_install() ||
      download_item->is_temporary() || !hs) {
    callback->RunWithParams(
        history::DownloadCreateRequest::TupleType(download_item->id(),
                                                  GetNextFakeDbHandle()));
    delete callback;
    return;
  }

  int32 id = download_item->id();
  DownloadHistoryInfo history_info = download_item->GetHistoryInfo();
  hs->CreateDownload(id, history_info, &history_consumer_, callback);
}

void DownloadHistory::UpdateEntry(DownloadItem* download_item) {
  // Don't store info in the database if the download was initiated while in
  // incognito mode or if it hasn't been initialized in our database table.
  if (download_item->db_handle() <= kUninitializedHandle)
    return;

  HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
  if (!hs)
    return;

  hs->UpdateDownload(download_item->received_bytes(),
                     download_item->state(),
                     download_item->db_handle());
}

void DownloadHistory::UpdateDownloadPath(DownloadItem* download_item,
                                         const FilePath& new_path) {
  // No update necessary if the download was initiated while in incognito mode.
  if (download_item->db_handle() <= kUninitializedHandle)
    return;

  HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
  if (hs)
    hs->UpdateDownloadPath(new_path, download_item->db_handle());
}

void DownloadHistory::RemoveEntry(DownloadItem* download_item) {
  // No update necessary if the download was initiated while in incognito mode.
  if (download_item->db_handle() <= kUninitializedHandle)
    return;

  HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
  if (hs)
    hs->RemoveDownload(download_item->db_handle());
}

void DownloadHistory::RemoveEntriesBetween(const base::Time remove_begin,
                                           const base::Time remove_end) {
  HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
  if (hs)
    hs->RemoveDownloadsBetween(remove_begin, remove_end);
}

int64 DownloadHistory::GetNextFakeDbHandle() {
  return next_fake_db_handle_--;
}

void DownloadHistory::OnGotVisitCountToHost(HistoryService::Handle handle,
                                            bool found_visits,
                                            int count,
                                            base::Time first_visit) {
  VisitedBeforeRequestsMap::iterator request =
      visited_before_requests_.find(handle);
  DCHECK(request != visited_before_requests_.end());
  int32 download_id = request->second.first;
  VisitedBeforeDoneCallback* callback = request->second.second;
  visited_before_requests_.erase(request);
  callback->Run(download_id, found_visits && count &&
      (first_visit.LocalMidnight() < base::Time::Now().LocalMidnight()));
  delete callback;
}