Bug 1468980 - Remove nsIDownloadHistory.idl. r=mak

MozReview-Commit-ID: IDHmOmJRJfe

--HG--
extra : rebase_source : 9f4f935740eb490ccc46620f0b4dad205289ae64
This commit is contained in:
Mark Banner 2018-07-27 15:24:53 +01:00
parent d20e34a9ab
commit 4b4fb0e535
10 changed files with 10 additions and 550 deletions

View File

@ -44,7 +44,6 @@ XPIDL_SOURCES += [
'nsIDocShellTreeItem.idl',
'nsIDocShellTreeOwner.idl',
'nsIDocumentLoaderFactory.idl',
'nsIDownloadHistory.idl',
'nsILoadContext.idl',
'nsIPrivacyTransitionObserver.idl',
'nsIReflowObserver.idl',

View File

@ -1,47 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 sts=2
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsIURI;
/**
* This interface can be used to add a download to history. There is a separate
* interface specifically for downloads in case embedders choose to track
* downloads differently from other types of history.
*/
[scriptable, uuid(4dcd6a12-a091-4f38-8360-022929635746)]
interface nsIDownloadHistory : nsISupports {
/**
* Adds a download to history. This will also notify observers that the
* URI aSource is visited with the topic NS_LINK_VISITED_EVENT_TOPIC if
* aSource has not yet been visited.
*
* @param aSource
* The source of the download we are adding to history. This cannot be
* null.
* @param aReferrer
* [optional] The referrer of source URI.
* @param aStartTime
* [optional] The time the download was started. If the start time
* is not given, the current time is used.
* @param aDestination
* [optional] The target where the download is to be saved on the local
* filesystem.
* @throws NS_ERROR_NOT_AVAILABLE
* In a situation where a history implementation is not available,
* where 'history implementation' refers to something like
* nsIGlobalHistory and friends.
* @note This addition is not guaranteed to be synchronous, since it delegates
* the actual addition to the underlying history implementation. If you
* need to observe the completion of the addition, use the underlying
* history implementation's notifications system (e.g. nsINavHistoryObserver
* for toolkit's implementation of this interface).
*/
void addDownload(in nsIURI aSource, [optional] in nsIURI aReferrer,
[optional] in PRTime aStartTime,
[optional] in nsIURI aDestination);
};

View File

@ -7,17 +7,6 @@
#ifndef nsDocShellCID_h__
#define nsDocShellCID_h__
#define NS_GLOBALHISTORY2_CONTRACTID "@mozilla.org/browser/global-history;2"
/**
* A contract for a service that will track download history. This can be
* overridden by embedders if they would like to track additional information
* about downloads.
*
* @implements nsIDownloadHistory
*/
#define NS_DOWNLOADHISTORY_CONTRACTID "@mozilla.org/browser/download-history;1"
/**
* A contract that can be used to get a service that provides
* meta-information about nsIWebNavigation objects' capabilities.

View File

@ -9,10 +9,6 @@
ChromeUtils.import("resource://gre/modules/DownloadHistory.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gDownloadHistory",
"@mozilla.org/browser/download-history;1",
Ci.nsIDownloadHistory);
let baseDate = new Date("2000-01-01");
/**
@ -153,12 +149,9 @@ add_task(async function test_DownloadHistory() {
let promiseFileAnnotation = waitForAnnotation(properties.source.url, "downloads/destinationFileURI");
let promiseMetaAnnotation = waitForAnnotation(properties.source.url, "downloads/metaData");
let promiseVisit = promiseWaitForVisit(properties.source.url);
gDownloadHistory.addDownload(Services.io.newURI(properties.source.url),
null,
properties.startTime.getTime() * 1000,
NetUtil.newURI(targetFile));
await DownloadHistory.addDownloadToHistory(download);
await promiseVisit;
DownloadHistory.updateMetaData(download);
await DownloadHistory.updateMetaData(download);
await Promise.all([promiseFileAnnotation, promiseMetaAnnotation]);
}

View File

@ -15,7 +15,6 @@
#include "History.h"
#include "nsNavHistory.h"
#include "nsNavBookmarks.h"
#include "nsAnnotationService.h"
#include "Helpers.h"
#include "PlaceInfo.h"
#include "VisitInfo.h"
@ -1466,114 +1465,6 @@ private:
RefPtr<History> mHistory;
};
/**
* Adds download-specific annotations to a download page.
*/
class SetDownloadAnnotations final : public mozIVisitInfoCallback
{
public:
NS_DECL_ISUPPORTS
explicit SetDownloadAnnotations(nsIURI* aDestination)
: mDestination(aDestination)
, mHistory(History::GetService())
{
MOZ_ASSERT(mDestination);
MOZ_ASSERT(NS_IsMainThread());
}
NS_IMETHOD GetIgnoreResults(bool *aIgnoreResults) override
{
*aIgnoreResults = false;
return NS_OK;
}
NS_IMETHOD GetIgnoreErrors(bool *aIgnoreErrors) override
{
*aIgnoreErrors = false;
return NS_OK;
}
NS_IMETHOD HandleError(nsresult aResultCode, mozIPlaceInfo *aPlaceInfo) override
{
// Just don't add the annotations in case the visit isn't added.
return NS_OK;
}
NS_IMETHOD HandleResult(mozIPlaceInfo *aPlaceInfo) override
{
// Exit silently if the download destination is not a local file.
nsCOMPtr<nsIFileURL> destinationFileURL = do_QueryInterface(mDestination);
if (!destinationFileURL) {
return NS_OK;
}
nsCOMPtr<nsIURI> source;
nsresult rv = aPlaceInfo->GetUri(getter_AddRefs(source));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString destinationURISpec;
rv = destinationFileURL->GetSpec(destinationURISpec);
NS_ENSURE_SUCCESS(rv, rv);
// Use annotations for storing the additional download metadata.
nsAnnotationService* annosvc = nsAnnotationService::GetAnnotationService();
NS_ENSURE_TRUE(annosvc, NS_ERROR_OUT_OF_MEMORY);
rv = annosvc->SetPageAnnotationString(
source,
DESTINATIONFILEURI_ANNO,
NS_ConvertUTF8toUTF16(destinationURISpec),
0,
nsIAnnotationService::EXPIRE_NEVER
);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString title;
rv = aPlaceInfo->GetTitle(title);
NS_ENSURE_SUCCESS(rv, rv);
// In case we are downloading a file that does not correspond to a web
// page for which the title is present, we populate the otherwise empty
// history title with the name of the destination file, to allow it to be
// visible and searchable in history results.
if (title.IsEmpty()) {
nsCOMPtr<nsIFile> destinationFile;
rv = destinationFileURL->GetFile(getter_AddRefs(destinationFile));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString destinationFileName;
rv = destinationFile->GetLeafName(destinationFileName);
NS_ENSURE_SUCCESS(rv, rv);
rv = mHistory->SetURITitle(source, destinationFileName);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
NS_IMETHOD HandleCompletion(uint32_t aUpdatedCount) override
{
return NS_OK;
}
private:
~SetDownloadAnnotations() {}
nsCOMPtr<nsIURI> mDestination;
/**
* Strong reference to the History object because we do not want it to
* disappear out from under us.
*/
RefPtr<History> mHistory;
};
NS_IMPL_ISUPPORTS(
SetDownloadAnnotations,
mozIVisitInfoCallback
)
/**
* Stores an embed visit, and notifies observers.
*
@ -2519,61 +2410,6 @@ History::SetURITitle(nsIURI* aURI, const nsAString& aTitle)
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
//// nsIDownloadHistory
NS_IMETHODIMP
History::AddDownload(nsIURI* aSource, nsIURI* aReferrer,
PRTime aStartTime, nsIURI* aDestination)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_ARG(aSource);
if (mShuttingDown) {
return NS_OK;
}
if (XRE_IsContentProcess()) {
NS_ERROR("Cannot add downloads to history from content process!");
return NS_ERROR_NOT_AVAILABLE;
}
nsNavHistory* navHistory = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(navHistory, NS_ERROR_OUT_OF_MEMORY);
// Silently return if URI is something we shouldn't add to DB.
bool canAdd;
nsresult rv = navHistory->CanAddURI(aSource, &canAdd);
NS_ENSURE_SUCCESS(rv, rv);
if (!canAdd) {
return NS_OK;
}
nsTArray<VisitData> placeArray(1);
NS_ENSURE_TRUE(placeArray.AppendElement(VisitData(aSource, aReferrer)),
NS_ERROR_OUT_OF_MEMORY);
VisitData& place = placeArray.ElementAt(0);
NS_ENSURE_FALSE(place.spec.IsEmpty(), NS_ERROR_INVALID_ARG);
place.visitTime = aStartTime;
place.SetTransitionType(nsINavHistoryService::TRANSITION_DOWNLOAD);
place.hidden = false;
mozIStorageConnection* dbConn = GetDBConn();
NS_ENSURE_STATE(dbConn);
nsMainThreadPtrHandle<mozIVisitInfoCallback> callback;
if (aDestination) {
callback = new nsMainThreadPtrHolder<mozIVisitInfoCallback>(
"mozIVisitInfoCallback", new SetDownloadAnnotations(aDestination));
}
rv = InsertVisitedURIs::Start(dbConn, placeArray, callback);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
//// mozIAsyncHistory
@ -2784,7 +2620,6 @@ History::Observe(nsISupports* aSubject, const char* aTopic,
NS_IMPL_ISUPPORTS(
History
, IHistory
, nsIDownloadHistory
, mozIAsyncHistory
, nsIObserver
, nsIMemoryReporter

View File

@ -11,7 +11,6 @@
#include "mozilla/MemoryReporting.h"
#include "mozilla/Mutex.h"
#include "mozIAsyncHistory.h"
#include "nsIDownloadHistory.h"
#include "Database.h"
#include "mozilla/dom/Link.h"
@ -47,7 +46,6 @@ class ConcurrentStatementsHolder;
#define NOTIFY_VISITS_CHUNK_SIZE 100
class History final : public IHistory
, public nsIDownloadHistory
, public mozIAsyncHistory
, public nsIObserver
, public nsIMemoryReporter
@ -55,7 +53,6 @@ class History final : public IHistory
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_IHISTORY
NS_DECL_NSIDOWNLOADHISTORY
NS_DECL_MOZIASYNCHISTORY
NS_DECL_NSIOBSERVER
NS_DECL_NSIMEMORYREPORTER

View File

@ -51,7 +51,6 @@ const mozilla::Module::ContractIDEntry kPlacesContracts[] = {
{ NS_FAVICONSERVICE_CONTRACTID, &kNS_FAVICONSERVICE_CID },
{ "@mozilla.org/embeddor.implemented/bookmark-charset-resolver;1", &kNS_NAVHISTORYSERVICE_CID },
{ NS_IHISTORY_CONTRACTID, &kNS_HISTORYSERVICE_CID },
{ NS_DOWNLOADHISTORY_CONTRACTID, &kNS_HISTORYSERVICE_CID },
{ nullptr }
};

View File

@ -1,308 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* This file tests the nsIDownloadHistory Places implementation.
*/
XPCOMUtils.defineLazyServiceGetter(this, "gDownloadHistory",
"@mozilla.org/browser/download-history;1",
"nsIDownloadHistory");
const DOWNLOAD_URI = NetUtil.newURI("http://www.example.com/");
const REFERRER_URI = NetUtil.newURI("http://www.example.org/");
const PRIVATE_URI = NetUtil.newURI("http://www.example.net/");
/**
* Waits for the first visit notification to be received.
*
* @param aCallback
* Callback function to be called with the same arguments of onVisit.
*/
async function waitForOnVisit(aCallback) {
await PlacesTestUtils.waitForNotification("page-visited", aEvents => {
Assert.equal(aEvents.length, 1, "Right number of visits notified");
Assert.equal(aEvents[0].type, "page-visited");
let {
url,
visitId,
visitTime,
referringVisitId,
transitionType,
pageGuid,
hidden,
visitCount,
typedCount,
lastKnownTitle,
} = aEvents[0];
let uriArg = NetUtil.newURI(url);
aCallback(uriArg, visitId, visitTime, 0, referringVisitId,
transitionType, pageGuid, hidden, visitCount,
typedCount, lastKnownTitle);
return true;
}, "places");
}
/**
* Waits for the first onDeleteURI notification to be received.
*
* @param aCallback
* Callback function to be called with the same arguments of onDeleteURI.
*/
function waitForOnDeleteURI(aCallback) {
let historyObserver = {
__proto__: NavHistoryObserver.prototype,
onDeleteURI: function HO_onDeleteURI() {
PlacesUtils.history.removeObserver(this);
aCallback.apply(null, arguments);
}
};
PlacesUtils.history.addObserver(historyObserver);
}
/**
* Waits for the first onDeleteVisits notification to be received.
*
* @param aCallback
* Callback function to be called with the same arguments of onDeleteVisits.
*/
function waitForOnDeleteVisits(aCallback) {
let historyObserver = {
__proto__: NavHistoryObserver.prototype,
onDeleteVisits: function HO_onDeleteVisits() {
PlacesUtils.history.removeObserver(this);
aCallback.apply(null, arguments);
}
};
PlacesUtils.history.addObserver(historyObserver);
}
add_task(async function test_dh_is_from_places() {
// Test that this nsIDownloadHistory is the one places implements.
Assert.ok(gDownloadHistory instanceof Ci.mozIAsyncHistory);
});
async function checkAddAndRemove(expected) {
let visitedPromise = PlacesTestUtils.waitForNotification("page-visited",
visits => visits[0].url == DOWNLOAD_URI.spec,
"places");
let pageInfo = await PlacesUtils.history.insert({
url: DOWNLOAD_URI.spec,
visits: [{
date: new Date(),
transition: PlacesUtils.history.TRANSITIONS.DOWNLOAD,
}]
});
await visitedPromise;
Assert.ok(!!page_in_database(DOWNLOAD_URI),
"Should have added the page to the database");
let notificationArgs;
let removedPromise = PlacesTestUtils.waitForNotification(
expected.deleteVisitOnly ? "onDeleteVisits" : "onDeleteURI",
(...args) => {
notificationArgs = args;
return true;
},
"history");
await PlacesUtils.history.removeVisitsByFilter({
transition: PlacesUtils.history.TRANSITIONS.DOWNLOAD
});
await removedPromise;
Assert.equal(notificationArgs[0].spec, DOWNLOAD_URI.spec,
"Should have received the correct URI in the notification");
if (expected.deleteVisitOnly) {
Assert.equal(notificationArgs[1], expected.partialRemoval,
"Should have received the expected partialRemoval in the notification");
Assert.equal(notificationArgs[2], pageInfo.guid,
"Should have received the correct GUID in the notification");
Assert.equal(notificationArgs[3], Ci.nsINavHistoryObserver.REASON_DELETED,
"Should have received the correct reason in the notification");
Assert.equal(notificationArgs[4], PlacesUtils.history.TRANSITIONS.DOWNLOAD,
"Should have received the correct transition type in the notification");
Assert.ok(!!page_in_database(DOWNLOAD_URI),
"Should have kept the page in the database.");
} else {
Assert.equal(notificationArgs[1], pageInfo.guid,
"Should have received the correct GUID in the notification");
Assert.equal(notificationArgs[2], Ci.nsINavHistoryObserver.REASON_DELETED,
"Should have received the correct reason in the notification");
Assert.ok(!page_in_database(DOWNLOAD_URI),
"Should have removed the page from the database.");
}
}
add_task(async function test_dh_addRemoveDownload() {
await checkAddAndRemove({
deleteVisitOnly: false,
partialRemoval: false,
});
});
add_task(async function test_dh_addMultiRemoveDownload() {
await PlacesTestUtils.addVisits({
uri: DOWNLOAD_URI,
transition: TRANSITION_TYPED
});
await checkAddAndRemove({
deleteVisitOnly: true,
partialRemoval: true,
});
await PlacesUtils.history.clear();
});
add_task(async function test_dh_addBookmarkRemoveDownload() {
await PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
url: DOWNLOAD_URI,
title: "A bookmark"
});
await checkAddAndRemove({
deleteVisitOnly: true,
partialRemoval: false,
});
});
add_task(async function test_dh_addDownload_referrer() {
// Wait for visits notification and get the visit id.
let visitId;
let referrerPromise = PlacesTestUtils.waitForNotification("page-visited", visits => {
visitId = visits[0].visitId;
let {url} = visits[0];
return url == REFERRER_URI.spec;
}, "places");
await PlacesTestUtils.addVisits([{
uri: REFERRER_URI,
transition: Ci.nsINavHistoryService.TRANSITION_TYPED
}]);
await referrerPromise;
// Verify results for referrer uri.
Assert.ok(!!PlacesTestUtils.isPageInDB(REFERRER_URI));
Assert.equal(visitId, 1);
// Wait for visits notification and get the referrer Id.
let referrerId;
let downloadPromise = PlacesTestUtils.waitForNotification("page-visited", visits => {
referrerId = visits[0].referringVisitId;
let {url} = visits[0];
return url == DOWNLOAD_URI.spec;
}, "places");
gDownloadHistory.addDownload(DOWNLOAD_URI, REFERRER_URI, Date.now() * 1000);
await downloadPromise;
// Verify results for download uri.
// ensure that we receive the 'page-visited' notification before we call addDownload.
Assert.ok(!!PlacesTestUtils.isPageInDB(DOWNLOAD_URI));
Assert.equal(visitId, referrerId);
await PlacesUtils.history.clear();
});
add_test(function test_dh_addDownload_disabledHistory() {
waitForOnVisit(function DHAD_onVisit(aURI) {
// We should only receive the notification for the non-private URI. This
// test is based on the assumption that visit notifications are received in
// the same order of the addDownload calls, which is currently true because
// database access is serialized on the same worker thread.
Assert.ok(aURI.equals(DOWNLOAD_URI));
Assert.ok(!!page_in_database(DOWNLOAD_URI));
Assert.ok(!page_in_database(PRIVATE_URI));
PlacesUtils.history.clear().then(run_next_test);
});
Services.prefs.setBoolPref("places.history.enabled", false);
gDownloadHistory.addDownload(PRIVATE_URI, REFERRER_URI, Date.now() * 1000);
// The addDownload functions calls CanAddURI synchronously, thus we can set
// the preference back to true immediately (not all apps enable places by
// default).
Services.prefs.setBoolPref("places.history.enabled", true);
gDownloadHistory.addDownload(DOWNLOAD_URI, REFERRER_URI, Date.now() * 1000);
});
/**
* Tests that nsIDownloadHistory::AddDownload saves the additional download
* details if the optional destination URL is specified.
*/
add_test(function test_dh_details() {
const REMOTE_URI = NetUtil.newURI("http://localhost/");
const SOURCE_URI = NetUtil.newURI("http://example.com/test_dh_details");
const DEST_FILE_NAME = "dest.txt";
// We must build a real, valid file URI for the destination.
let destFileUri = NetUtil.newURI(FileUtils.getFile("TmpD", [DEST_FILE_NAME]));
let titleSet = false;
let destinationFileUriSet = false;
function checkFinished() {
if (titleSet && destinationFileUriSet) {
PlacesUtils.annotations.removeObserver(annoObserver);
PlacesUtils.history.removeObserver(historyObserver);
PlacesUtils.history.clear().then(run_next_test);
}
}
let annoObserver = {
onPageAnnotationSet: function AO_onPageAnnotationSet(aPage, aName) {
if (aPage.equals(SOURCE_URI)) {
let value = PlacesUtils.annotations.getPageAnnotation(aPage, aName);
switch (aName) {
case "downloads/destinationFileURI":
destinationFileUriSet = true;
Assert.equal(value, destFileUri.spec);
break;
}
checkFinished();
}
},
onItemAnnotationSet() {},
onPageAnnotationRemoved() {},
onItemAnnotationRemoved() {}
};
let historyObserver = {
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onTitleChanged: function HO_onTitleChanged(aURI, aPageTitle) {
if (aURI.equals(SOURCE_URI)) {
titleSet = true;
Assert.equal(aPageTitle, DEST_FILE_NAME);
checkFinished();
}
},
onDeleteURI() {},
onClearHistory() {},
onPageChanged() {},
onDeleteVisits() {}
};
PlacesUtils.annotations.addObserver(annoObserver);
PlacesUtils.history.addObserver(historyObserver);
// Both null values and remote URIs should not cause errors.
gDownloadHistory.addDownload(SOURCE_URI, null, Date.now() * 1000);
gDownloadHistory.addDownload(SOURCE_URI, null, Date.now() * 1000, null);
gDownloadHistory.addDownload(SOURCE_URI, null, Date.now() * 1000, REMOTE_URI);
// Valid local file URIs should cause the download details to be saved.
gDownloadHistory.addDownload(SOURCE_URI, null, Date.now() * 1000,
destFileUri);
});

View File

@ -2,7 +2,6 @@
head = head_history.js
[test_async_history_api.js]
[test_download_history.js]
[test_fetch.js]
[test_hasVisits.js]
[test_insert.js]

View File

@ -10,10 +10,14 @@ add_task(async function test_InsertVisitedURIs_UpdateFrecency_and_History_Insert
// two birds with one stone and expect two notifications. Trigger the path by
// adding a download.
let url = Services.io.newURI("http://example.com/a");
Cc["@mozilla.org/browser/download-history;1"].
getService(Ci.nsIDownloadHistory).
addDownload(url);
await Promise.all([onFrecencyChanged(url), onFrecencyChanged(url)]);
let promises = [onFrecencyChanged(url), onFrecencyChanged(url)];
await PlacesUtils.history.insert({
url,
visits: [{
transition: PlacesUtils.history.TRANSITIONS.DOWNLOAD,
}],
});
await Promise.all(promises);
});
// nsNavHistory::UpdateFrecency