Bug 401174 - Allow how exthandler adds downloads to history to be overridden. r=biesi, sr=bz, a=mconnor

This commit is contained in:
sdwilsh@shawnwilsher.com 2007-11-23 12:20:41 -08:00
Родитель ed89c4c8ff
Коммит 851f816bc5
12 изменённых файлов: 462 добавлений и 32 удалений

Просмотреть файл

@ -114,6 +114,7 @@ XPIDLSRCS = \
nsIEditorDocShell.idl \
nsIWebPageDescriptor.idl \
nsIURIClassifier.idl \
nsIDownloadHistory.idl \
$(NULL)
EXPORTS = nsDocShellLoadTypes.h
@ -131,6 +132,7 @@ CPPSRCS = \
nsGlobalHistory2Adapter.cpp \
nsWebNavigationInfo.cpp \
nsAboutRedirector.cpp \
nsDownloadHistory.cpp \
$(NULL)
# we don't want the shared lib, but we want to force the creation of a

Просмотреть файл

@ -8509,16 +8509,9 @@ nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
if (NS_FAILED(rv))
return rv;
// Get referrer from the channel. We have to check for a property on a
// property bag because the referrer may be empty for security reasons (for
// example, when loading a http page with a https referrer).
nsCOMPtr<nsIURI> referrer;
nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel));
if (props) {
props->GetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
NS_GET_IID(nsIURI),
getter_AddRefs(referrer));
}
if (aChannel)
NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
rv = mGlobalHistory->AddURI(aURI, aRedirect, !IsFrame(), referrer);
if (NS_FAILED(rv))

Просмотреть файл

@ -0,0 +1,83 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 sts=2
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDownloadHistory.h"
#include "nsCOMPtr.h"
#include "nsServiceManagerUtils.h"
#include "nsIGlobalHistory.h"
#include "nsIGlobalHistory2.h"
#include "nsIObserverService.h"
#include "nsIURI.h"
////////////////////////////////////////////////////////////////////////////////
//// nsDownloadHistory
NS_IMPL_ISUPPORTS1(nsDownloadHistory, nsIDownloadHistory)
////////////////////////////////////////////////////////////////////////////////
//// nsIDownloadHistory
NS_IMETHODIMP
nsDownloadHistory::AddDownload(nsIURI *aSource,
nsIURI *aReferrer,
PRTime aStartTime)
{
NS_ENSURE_ARG_POINTER(aSource);
nsCOMPtr<nsIGlobalHistory2> history =
do_GetService("@mozilla.org/browser/global-history;2");
if (!history)
return NS_ERROR_NOT_AVAILABLE;
PRBool visited;
nsresult rv = history->IsVisited(aSource, &visited);
NS_ENSURE_SUCCESS(rv, rv);
rv = history->AddURI(aSource, PR_FALSE, PR_TRUE, aReferrer);
NS_ENSURE_SUCCESS(rv, rv);
if (!visited) {
nsCOMPtr<nsIObserverService> os =
do_GetService("@mozilla.org/observer-service;1");
if (os)
os->NotifyObservers(aSource, NS_LINK_VISITED_EVENT_TOPIC, nsnull);
}
return NS_OK;
}

Просмотреть файл

@ -0,0 +1,55 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 sts=2
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __nsDownloadHistory_h__
#define __nsDownloadHistory_h__
#include "nsIDownloadHistory.h"
#define NS_DOWNLOADHISTORY_CID \
{0x2ee83680, 0x2af0, 0x4bcb, {0xbf, 0xa0, 0xc9, 0x70, 0x5f, 0x65, 0x54, 0xf1}}
class nsDownloadHistory : public nsIDownloadHistory
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOWNLOADHISTORY
};
#endif // __nsDownloadHistory_h__

Просмотреть файл

@ -0,0 +1,72 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 sts=2
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#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(202533cd-a8f1-4ee4-8d20-3a6a0d2c6c51)]
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.
* @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.
*/
void addDownload(in nsIURI aSource, [optional] in nsIURI aReferrer,
[optional] in PRTime aStartTime);
};

Просмотреть файл

@ -1,5 +1,6 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=4 sts=4
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
@ -41,6 +42,16 @@
#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.

Просмотреть файл

@ -66,6 +66,9 @@
#include "nsGlobalHistoryAdapter.h"
#include "nsGlobalHistory2Adapter.h"
// download history
#include "nsDownloadHistory.h"
static PRBool gInitialized = PR_FALSE;
// The one time initialization for this module
@ -119,6 +122,9 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsSHEntry)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSHTransaction)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSHistory)
// download history
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDownloadHistory)
// Currently no-one is instantiating docshell's directly because
// nsWebShell is still our main "shell" class. nsWebShell is a subclass
// of nsDocShell. Once migration is complete, docshells will be the main
@ -240,7 +246,11 @@ static const nsModuleComponentInfo gDocShellModuleInfo[] = {
nsGlobalHistoryAdapter::RegisterSelf },
{ "nsGlobalHistory2Adapter", NS_GLOBALHISTORY2ADAPTER_CID,
nsnull, nsGlobalHistory2Adapter::Create,
nsGlobalHistory2Adapter::RegisterSelf }
nsGlobalHistory2Adapter::RegisterSelf },
// download history
{ "nsDownloadHistory", NS_DOWNLOADHISTORY_CID,
NS_DOWNLOADHISTORY_CONTRACTID, nsDownloadHistoryConstructor }
};
// "docshell provider" to illustrate that this thing really *should*

Просмотреть файл

@ -41,10 +41,14 @@ srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = docshell/test
MODULE = test_docshell
DIRS += chrome \
browser \
$(NULL)
XPCSHELL_TESTS = unit
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,90 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
var profileDir = dirSvc.get("CurProcD", Ci.nsILocalFile);
profileDir.append("test_docshell_profile");
// Register our own provider for the profile directory.
// It will return our special docshell profile directory.
var provider = {
getFile: function(prop, persistent) {
persistent.value = true;
if (prop == "ProfD") {
var retVal = dirSvc.get("CurProcD", Ci.nsILocalFile);
retVal.append("test_docshell_profile");
if (!retVal.exists())
retVal.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
return retVal;
}
throw Cr.NS_ERROR_FAILURE;
},
QueryInterface: function(iid) {
if (iid.equals(Ci.nsIDirectoryProvider) ||
iid.equals(Ci.nsISupports)) {
return this;
}
throw Cr.NS_ERROR_NO_INTERFACE;
}
};
dirSvc.QueryInterface(Ci.nsIDirectoryService).registerProvider(provider);
function cleanup()
{
// we need to remove the folder that we created for the profile
try {
if (profileDir.exists())
profileDir.remove(true);
} catch (e) {
// windows has a slight problem with sqlite databases and trying to remove
// them to quickly after you might expect to be done with them. Eat any
// errors we'll get. This should be OK because we cleanup before and after
// each test run.
}
}
// cleanup from any failed test runs in the past
cleanup();
// make sure we have our profile directory available to us
profileDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);

Просмотреть файл

@ -0,0 +1,81 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
const NS_DOWNLOADHISTORY_CID = "{2ee83680-2af0-4bcb-bfa0-c9705f6554f1}";
function testLinkVistedObserver()
{
const NS_LINK_VISITED_EVENT_TOPIC = "link-visited";
var ios = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
var testURI = ios.newURI("http://google.com/", null, null);
var gh = Cc["@mozilla.org/browser/global-history;2"].
getService(Ci.nsIGlobalHistory2);
do_check_false(gh.isVisited(testURI));
var topicReceived = false;
var obs = {
observe: function tlvo_observe(aSubject, aTopic, aData)
{
if (NS_LINK_VISITED_EVENT_TOPIC == aTopic) {
do_check_eq(testURI, aSubject);
topicReceived = true;
}
}
};
var os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
os.addObserver(obs, NS_LINK_VISITED_EVENT_TOPIC, false);
var dh = Components.classesByID[NS_DOWNLOADHISTORY_CID].
getService(Ci.nsIDownloadHistory);
dh.addDownload(testURI);
do_check_true(topicReceived);
do_check_true(gh.isVisited(testURI));
}
var tests = [testLinkVistedObserver];
function run_test()
{
for (var i = 0; i < tests.length; i++)
tests[i]();
cleanup();
}

Просмотреть файл

@ -92,6 +92,7 @@
#include "nsServiceManagerUtils.h"
#include "nsINestedURI.h"
#include "nsIMutable.h"
#include "nsIPropertyBag2.h"
// Helper, to simplify getting the I/O service.
inline const nsGetServiceByContractIDWithError
@ -699,6 +700,45 @@ NS_GetURLSpecFromFile(nsIFile *file,
return rv;
}
/**
* Obtains the referrer for a given channel. This first tries to obtain the
* referrer from the property docshell.internalReferrer, and if that doesn't
* work and the channel is an nsIHTTPChannel, we check it's referrer property.
*
* @returns NS_ERROR_NOT_AVAILABLE if no referrer is available.
*/
inline nsresult
NS_GetReferrerFromChannel(nsIChannel *channel,
nsIURI **referrer)
{
nsresult rv = NS_ERROR_NOT_AVAILABLE;
*referrer = nsnull;
nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(channel));
if (props) {
// We have to check for a property on a property bag because the
// referrer may be empty for security reasons (for example, when loading
// an http page with an https referrer).
rv = props->GetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
NS_GET_IID(nsIURI),
reinterpret_cast<void **>(referrer));
if (NS_FAILED(rv))
*referrer = nsnull;
}
// if that didn't work, we can still try to get the referrer from the
// nsIHttpChannel (if we can QI to it)
if (!(*referrer)) {
nsCOMPtr<nsIHttpChannel> chan(do_QueryInterface(channel));
if (chan) {
rv = chan->GetReferrer(referrer);
if (NS_FAILED(rv))
*referrer = nsnull;
}
}
return rv;
}
#ifdef MOZILLA_INTERNAL_API
inline nsresult
NS_ExamineForProxy(const char *scheme,

Просмотреть файл

@ -109,8 +109,8 @@
#include "nsIPrefService.h"
#include "nsIWindowWatcher.h"
#include "nsIGlobalHistory.h" // to mark downloads as visited
#include "nsIGlobalHistory2.h" // to mark downloads as visited
#include "nsIDownloadHistory.h" // to mark downloads as visited
#include "nsDocShellCID.h"
#include "nsIDOMWindow.h"
#include "nsIDOMWindowInternal.h"
@ -1497,24 +1497,13 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest *request, nsISuppo
}
}
// Now let's mark the downloaded URL as visited
nsCOMPtr<nsIGlobalHistory> history(do_GetService(NS_GLOBALHISTORY_CONTRACTID));
nsCAutoString spec;
mSourceUrl->GetSpec(spec);
if (history && !spec.IsEmpty())
{
PRBool visited;
rv = history->IsVisited(spec.get(), &visited);
if (NS_FAILED(rv))
return rv;
history->AddPage(spec.get());
if (!visited) {
nsCOMPtr<nsIObserverService> obsService =
do_GetService("@mozilla.org/observer-service;1");
if (obsService) {
obsService->NotifyObservers(mSourceUrl, NS_LINK_VISITED_EVENT_TOPIC, nsnull);
}
}
// Now let's add the download to history
nsCOMPtr<nsIDownloadHistory> dh(do_GetService(NS_DOWNLOADHISTORY_CONTRACTID));
if (dh) {
nsCOMPtr<nsIURI> referrer;
if (aChannel)
NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
dh->AddDownload(mSourceUrl, referrer, mTimeDownloadStarted);
}
return NS_OK;