--- a/uriloader/exthandler/beos/nsOSHelperAppService.cpp
+++ b/uriloader/exthandler/beos/nsOSHelperAppService.cpp
@@ -57,19 +57,19 @@
nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService()
{
}
nsOSHelperAppService::~nsOSHelperAppService()
{}
-NS_IMETHODIMP nsOSHelperAppService::ExternalProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists)
+nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists)
{
- LOG(("-- nsOSHelperAppService::ExternalProtocolHandlerExists for '%s'\n",
+ LOG(("-- nsOSHelperAppService::OSProtocolHandlerExists for '%s'\n",
aProtocolScheme));
// look up the protocol scheme in the MIME database
*aHandlerExists = PR_FALSE;
if (aProtocolScheme && *aProtocolScheme)
{
BString protoStr(aProtocolScheme);
protoStr.Prepend("application/x-vnd.Be.URL.");
BMimeType protocol;
--- a/uriloader/exthandler/beos/nsOSHelperAppService.h
+++ b/uriloader/exthandler/beos/nsOSHelperAppService.h
@@ -51,17 +51,17 @@ class nsOSHelperAppService : public nsEx
{
public:
nsOSHelperAppService();
virtual ~nsOSHelperAppService();
already_AddRefed<nsIMIMEInfo> GetMIMEInfoFromOS(const nsACString& aMIMEType, const nsACString& aFileExt, PRBool *aFound);
// override nsIExternalProtocolService methods
- NS_IMETHOD ExternalProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists);
+ nsresult OSProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists);
nsresult LoadUriInternal(nsIURI * aURL);
protected:
nsresult SetMIMEInfoForType(const char *aMIMEType, nsMIMEInfoBeOS **_retval);
nsresult GetMimeInfoFromExtension(const char *aFileExt, nsMIMEInfoBeOS **_retval);
nsresult GetMimeInfoFromMIMEType(const char *aMIMEType, nsMIMEInfoBeOS **_retval);
};
--- a/uriloader/exthandler/mac/nsOSHelperAppService.cpp
+++ b/uriloader/exthandler/mac/nsOSHelperAppService.cpp
@@ -69,17 +69,17 @@ extern "C" {
nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService()
{
}
nsOSHelperAppService::~nsOSHelperAppService()
{}
-NS_IMETHODIMP nsOSHelperAppService::ExternalProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists)
+nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists)
{
// look up the protocol scheme in Internet Config....if we find a match then we have a handler for it...
*aHandlerExists = PR_FALSE;
// ask the internet config service to look it up for us...
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr<nsIInternetConfigService> icService (do_GetService(NS_INTERNETCONFIGSERVICE_CONTRACTID));
if (icService)
{
--- a/uriloader/exthandler/mac/nsOSHelperAppService.h
+++ b/uriloader/exthandler/mac/nsOSHelperAppService.h
@@ -51,29 +51,30 @@
class nsOSHelperAppService : public nsExternalHelperAppService
{
public:
nsOSHelperAppService();
virtual ~nsOSHelperAppService();
// override nsIExternalProtocolService methods
- NS_IMETHOD ExternalProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists);
NS_IMETHOD GetApplicationDescription(const nsACString& aScheme, nsAString& _retval);
nsresult LoadUriInternal(nsIURI * aURL);
// method overrides --> used to hook the mime service into internet config....
NS_IMETHOD GetFromTypeAndExtension(const nsACString& aType, const nsACString& aFileExt, nsIMIMEInfo ** aMIMEInfo);
already_AddRefed<nsIMIMEInfo> GetMIMEInfoFromOS(const nsACString& aMIMEType, const nsACString& aFileExt, PRBool * aFound);
// GetFileTokenForPath must be implemented by each platform.
// platformAppPath --> a platform specific path to an application that we got out of the
// rdf data source. This can be a mac file spec, a unix path or a windows path depending on the platform
// aFile --> an nsIFile representation of that platform application path.
virtual nsresult GetFileTokenForPath(const PRUnichar * platformAppPath, nsIFile ** aFile);
-
+
+ nsresult OSProtocolHandlerExists(const char * aScheme,
+ PRBool * aHandlerExists);
+
protected:
// add any mac specific service state here
void UpdateCreatorInfo(nsIMIMEInfo * aMIMEInfo);
-
};
#endif // nsOSHelperAppService_h__
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -19,16 +19,17 @@
* Netscape Communications, Inc.
* Portions created by the Initial Developer are Copyright (C) 1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Scott MacGregor <mscott@netscape.com>
* Bill Law <law@netscape.com>
* Christian Biesinger <cbiesinger@web.de>
+ * Dan Mosedale <dmose@mozilla.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either of 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
@@ -137,17 +138,17 @@ static const char NEVER_ASK_FOR_OPEN_FIL
#ifdef MOZ_RDF
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
#endif
static NS_DEFINE_CID(kPluginManagerCID, NS_PLUGINMANAGER_CID);
/**
* Contains a pointer to the helper app service, set in its constructor
*/
-static nsExternalHelperAppService* sSrv;
+nsExternalHelperAppService* gExtProtSvc;
// Helper functions for Content-Disposition headers
/**
* Given a URI fragment, unescape it
* @param aFragment The string to unescape
* @param aURI The URI from which this fragment is taken. Only its character set
* will be used.
@@ -487,17 +488,17 @@ NS_IMPL_ISUPPORTS6(
nsIExternalProtocolService,
nsIMIMEService,
nsIObserver,
nsISupportsWeakReference)
nsExternalHelperAppService::nsExternalHelperAppService()
: mDataSourceInitialized(PR_FALSE)
{
- sSrv = this;
+ gExtProtSvc = this;
}
nsresult nsExternalHelperAppService::Init()
{
// Add an observer for profile change
nsresult rv = NS_OK;
nsCOMPtr<nsIObserverService> obs = do_GetService("@mozilla.org/observer-service;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
@@ -509,17 +510,17 @@ nsresult nsExternalHelperAppService::Ini
}
#endif
return obs->AddObserver(this, "profile-before-change", PR_TRUE);
}
nsExternalHelperAppService::~nsExternalHelperAppService()
{
- sSrv = nsnull;
+ gExtProtSvc = nsnull;
}
nsresult nsExternalHelperAppService::InitDataSource()
{
#ifdef MOZ_RDF
nsresult rv = NS_OK;
// don't re-initialize the data source if we've already done so...
@@ -1046,19 +1047,27 @@ nsresult nsExternalHelperAppService::Get
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
// begin external protocol service default implementation...
//////////////////////////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsExternalHelperAppService::ExternalProtocolHandlerExists(const char * aProtocolScheme,
PRBool * aHandlerExists)
{
- // this method should only be implemented by each OS specific implementation of this service.
- *aHandlerExists = PR_FALSE;
- return NS_ERROR_NOT_IMPLEMENTED;
+ // check for web-based handler
+ nsCAutoString uriTemplate;
+ nsresult rv = GetWebProtocolHandlerURITemplate(
+ nsDependentCString(aProtocolScheme), uriTemplate);
+ if (NS_SUCCEEDED(rv)) {
+ *aHandlerExists = PR_TRUE;
+ return NS_OK;
+ }
+
+ // fall back on an os-based handler
+ return OSProtocolHandlerExists(aProtocolScheme, aHandlerExists);
}
NS_IMETHODIMP nsExternalHelperAppService::IsExposedProtocol(const char * aProtocolScheme, PRBool * aResult)
{
// by default, no protocol is exposed. i.e., by default all link clicks must
// go through the external protocol service. most applications override this
// default behavior.
*aResult = PR_FALSE;
@@ -1101,18 +1110,18 @@ NS_IMETHODIMP nsExternalHelperAppService
// callback to make sure we don't hang someone up.
class nsExternalLoadRequest : public nsRunnable {
public:
nsExternalLoadRequest(nsIURI *uri, nsIPrompt *prompt)
: mURI(uri), mPrompt(prompt) {}
NS_IMETHOD Run() {
- if (sSrv && sSrv->isExternalLoadOK(mURI, mPrompt))
- sSrv->LoadUriInternal(mURI);
+ if (gExtProtSvc && gExtProtSvc->isExternalLoadOK(mURI, mPrompt))
+ gExtProtSvc->LoadUriInternal(mURI);
return NS_OK;
}
private:
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIPrompt> mPrompt;
};
@@ -1361,16 +1370,52 @@ nsresult nsExternalHelperAppService::Exp
localFile->Remove(PR_FALSE);
}
mTemporaryFilesList.Clear();
return NS_OK;
}
+nsresult
+nsExternalHelperAppService::GetWebProtocolHandlerURITemplate(const nsACString &aScheme,
+ nsACString &aUriTemplate)
+{
+ nsresult rv;
+ nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID,
+ &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // before we expose this to the UI, we need sort out our strategy re
+ // the "warning" and "exposed" prefs
+
+ // XXX enterprise customers should be able to turn this support off with a
+ // single master pref (maybe use one of the "exposed" prefs here?)
+
+ // do we have an automatic handler for this protocol?
+ nsCAutoString autoTemplatePref("network.protocol-handler.web.auto.");
+ autoTemplatePref += aScheme;
+
+ nsCAutoString autoTemplate;
+ rv = prefBranch->GetCharPref(autoTemplatePref.get(),
+ getter_Copies(autoTemplate));
+ // if so, return it.
+ if (NS_SUCCEEDED(rv)) {
+ aUriTemplate.Assign(autoTemplate);
+ return NS_OK;
+ }
+
+ // XXX since there's no automatic handler, if we have any choices, offer them
+ // up as well as including the option to make one of the choices automatic.
+ // do so by returning "about:protoHandlerChooser?uri=%s" as the template or
+ // perhaps by opening a dialog
+
+ return NS_ERROR_FAILURE;
+}
+
// XPCOM profile change observer
NS_IMETHODIMP
nsExternalHelperAppService::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData )
{
if (!strcmp(aTopic, "profile-before-change")) {
ExpungeTemporaryFiles();
#ifdef MOZ_RDF
nsCOMPtr <nsIRDFRemoteDataSource> flushableDataSource = do_QueryInterface(mOverRideDataSource);
@@ -1426,23 +1471,23 @@ nsExternalAppHandler::nsExternalAppHandl
// replace platform specific path separator and illegal characters to avoid any confusion
mSuggestedFileName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '-');
mTempFileExtension.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '-');
// Make sure extension is correct.
EnsureSuggestedFileName();
- sSrv->AddRef();
+ gExtProtSvc->AddRef();
}
nsExternalAppHandler::~nsExternalAppHandler()
{
- // Not using NS_RELEASE, since we don't want to set sSrv to NULL
- sSrv->Release();
+ // Not using NS_RELEASE, since we don't want to set gExtProtSvc to NULL
+ gExtProtSvc->Release();
}
NS_IMETHODIMP nsExternalAppHandler::SetWebProgressListener(nsIWebProgressListener2 * aWebProgressListener)
{
// this call back means we've successfully brought up the
// progress window so set the appropriate flag, even though
// aWebProgressListener might be null
@@ -1750,20 +1795,19 @@ NS_IMETHODIMP nsExternalAppHandler::OnSt
PRBool hasMore;
rv = encEnum->HasMore(&hasMore);
if (NS_SUCCEEDED(rv) && hasMore)
{
nsCAutoString encType;
rv = encEnum->GetNext(encType);
if (NS_SUCCEEDED(rv) && !encType.IsEmpty())
{
- NS_ASSERTION(sSrv, "Where did the service go?");
- sSrv->ApplyDecodingForExtension(extension,
- encType,
- &applyConversion);
+ NS_ASSERTION(gExtProtSvc, "Where did the service go?");
+ gExtProtSvc->ApplyDecodingForExtension(extension, encType,
+ &applyConversion);
}
}
}
}
}
encChannel->SetApplyConversion( applyConversion );
}
@@ -1786,18 +1830,18 @@ NS_IMETHODIMP nsExternalAppHandler::OnSt
mMimeInfo->GetAlwaysAskBeforeHandling(&alwaysAsk);
if (alwaysAsk)
{
// But we *don't* ask if this mimeInfo didn't come from
// our mimeTypes.rdf data source and the user has said
// at some point in the distant past that they don't
// want to be asked. The latter fact would have been
// stored in pref strings back in the old days.
- NS_ASSERTION(sSrv, "Service gone away!?");
- if (!sSrv->MIMETypeIsInDataSource(MIMEType.get()))
+ NS_ASSERTION(gExtProtSvc, "Service gone away!?");
+ if (!gExtProtSvc->MIMETypeIsInDataSource(MIMEType.get()))
{
if (!GetNeverAskFlagFromPref(NEVER_ASK_FOR_SAVE_TO_DISK_PREF, MIMEType.get()))
{
// Don't need to ask after all.
alwaysAsk = PR_FALSE;
// Make sure action matches pref (save to disk).
mMimeInfo->SetPreferredAction(nsIMIMEInfo::saveToDisk);
}
@@ -2143,17 +2187,17 @@ nsresult nsExternalAppHandler::ExecuteDe
else // Various unknown actions go here too
{
// XXX Put progress dialog in barber-pole mode
// and change text to say "Copying from:".
rv = MoveFile(mFinalFileDestination);
if (NS_SUCCEEDED(rv) && action == nsIMIMEInfo::saveToDisk)
{
nsCOMPtr<nsILocalFile> destfile(do_QueryInterface(mFinalFileDestination));
- sSrv->FixFilePermissions(destfile);
+ gExtProtSvc->FixFilePermissions(destfile);
}
}
// Notify dialog that download is complete.
// By waiting till this point, it ensures that the progress dialog doesn't indicate
// success until we're really done.
if(mWebProgressListener)
{
@@ -2449,18 +2493,18 @@ nsresult nsExternalAppHandler::OpenWithA
// app exit - they don't like it - but we'll continue to do this on
// other platforms for now.
deleteTempFileOnExit = PR_TRUE;
#else
deleteTempFileOnExit = PR_FALSE;
#endif
}
if (deleteTempFileOnExit) {
- NS_ASSERTION(sSrv, "Service gone away!?");
- sSrv->DeleteTemporaryFileOnExit(mFinalFileDestination);
+ NS_ASSERTION(gExtProtSvc, "Service gone away!?");
+ gExtProtSvc->DeleteTemporaryFileOnExit(mFinalFileDestination);
}
}
}
return rv;
}
// LaunchWithApplication should only be called by the helper app dialog which allows
--- a/uriloader/exthandler/nsExternalHelperAppService.h
+++ b/uriloader/exthandler/nsExternalHelperAppService.h
@@ -17,16 +17,17 @@
* The Initial Developer of the Original Code is
* Netscape Communications, Inc.
* Portions created by the Initial Developer are Copyright (C) 1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Scott MacGregor <mscott@netscape.com>
* Christian Biesinger <cbiesinger@web.de>
+ * Dan Mosedale <dmose@mozilla.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either of 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
@@ -186,16 +187,26 @@ public:
nsIFile ** aFile);
/**
* Helper routine used to test whether a given mime type is in our
* mimeTypes.rdf data source
*/
NS_HIDDEN_(PRBool) MIMETypeIsInDataSource(const char * aContentType);
+ /**
+ * Return the URI template for any configured web handler. This will
+ * probably be replaced by something on nsIWebContentConverterService soon.
+ */
+ static NS_HIDDEN_(nsresult) GetWebProtocolHandlerURITemplate(const nsACString &aScheme,
+ nsACString &aUriTemplate);
+
+ virtual NS_HIDDEN_(nsresult) OSProtocolHandlerExists(const char *aScheme,
+ PRBool *aExists) = 0;
+
protected:
/**
* Pointer to the datasource that contains the user override information.
* @see InitDataSource
*/
#ifdef MOZ_RDF
nsCOMPtr<nsIRDFDataSource> mOverRideDataSource;
@@ -507,9 +518,11 @@ protected:
/**
* The request that's being loaded. Not used after OnStopRequest, so a weak
* reference suffices. Initialized in OnStartRequest.
*/
nsIRequest* mRequest;
};
+extern NS_HIDDEN_(nsExternalHelperAppService*) gExtProtSvc;
+
#endif // nsExternalHelperAppService_h__
--- a/uriloader/exthandler/nsExternalProtocolHandler.cpp
+++ b/uriloader/exthandler/nsExternalProtocolHandler.cpp
@@ -18,16 +18,17 @@
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Scott MacGregor <mscott@netscape.com>
+ * Dan Mosedale <dmose@mozilla.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either of 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
@@ -47,45 +48,51 @@
#include "nsIServiceManager.h"
#include "nsServiceManagerUtils.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIStringBundle.h"
#include "nsIPrefService.h"
#include "nsIPrompt.h"
#include "nsNetUtil.h"
+#include "nsIChannelEventSink.h"
+#include "nsThreadUtils.h"
+#include "nsEscape.h"
+#include "nsExternalHelperAppService.h"
// used to dispatch urls to default protocol handlers
#include "nsCExternalHandlerService.h"
#include "nsIExternalProtocolService.h"
////////////////////////////////////////////////////////////////////////
// a stub channel implemenation which will map calls to AsyncRead and OpenInputStream
// to calls in the OS for loading the url.
////////////////////////////////////////////////////////////////////////
class nsExtProtocolChannel : public nsIChannel
{
+ friend class nsWebProtocolRedirect;
+
public:
-
NS_DECL_ISUPPORTS
NS_DECL_NSICHANNEL
NS_DECL_NSIREQUEST
nsExtProtocolChannel();
virtual ~nsExtProtocolChannel();
nsresult SetURI(nsIURI*);
private:
nsresult OpenURL();
nsCOMPtr<nsIURI> mUrl;
nsCOMPtr<nsIURI> mOriginalURI;
nsresult mStatus;
+ nsLoadFlags mLoadFlags;
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
nsCOMPtr<nsILoadGroup> mLoadGroup;
};
NS_IMPL_THREADSAFE_ADDREF(nsExtProtocolChannel)
NS_IMPL_THREADSAFE_RELEASE(nsExtProtocolChannel)
@@ -153,17 +160,17 @@ NS_IMETHODIMP nsExtProtocolChannel::GetU
return NS_OK;
}
nsresult nsExtProtocolChannel::SetURI(nsIURI* aURI)
{
mUrl = aURI;
return NS_OK;
}
-
+
nsresult nsExtProtocolChannel::OpenURL()
{
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr<nsIExternalProtocolService> extProtService (do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
if (extProtService)
{
#ifdef DEBUG
@@ -187,30 +194,162 @@ nsresult nsExtProtocolChannel::OpenURL()
}
NS_IMETHODIMP nsExtProtocolChannel::Open(nsIInputStream **_retval)
{
OpenURL();
return NS_ERROR_NO_CONTENT; // force caller to abort.
}
+class nsWebProtocolRedirect : public nsRunnable {
+ public:
+ nsWebProtocolRedirect(nsIURI *aURI, const nsACString & aUriTemplate,
+ nsIStreamListener *aListener, nsISupports *aContext,
+ nsExtProtocolChannel *aOriginalChannel)
+ : mURI(aURI), mUriTemplate(aUriTemplate), mListener(aListener),
+ mContext(aContext), mOriginalChannel(aOriginalChannel) {}
+
+ NS_IMETHOD Run()
+ {
+ // get the URI spec so we can escape it for insertion into the template
+ nsCAutoString uriSpecToHandle;
+ nsresult rv = mURI->GetSpec(uriSpecToHandle);
+ if (NS_FAILED(rv)) {
+ AbandonOriginalChannel(rv);
+ return NS_OK;
+ }
+
+ // XXX need to strip passwd & username from URI to handle, as per the
+ // WhatWG HTML5 draft. nsSimpleURL, which is what we're going to get,
+ // can't do this directly. Ideally, we'd fix nsStandardURL to make it
+ // possible to turn off all of its quirks handling, and use that...
+
+ // XXX this doesn't exactly match how the HTML5 draft is requesting us to
+ // escape; at the very least, it should be escaping @ signs, and there
+ // may well be more issues. However, this code will probably be thrown
+ // out when we do the front-end work, as we'll be using a refactored
+ // nsIWebContentConverterInfo to do this work for us
+ nsCAutoString escapedUriSpecToHandle;
+ NS_EscapeURL(uriSpecToHandle, esc_Minimal | esc_Forced | esc_Colon,
+ escapedUriSpecToHandle);
+
+ // Note that this replace all occurrences of %s with the URL to be
+ // handled. The HTML5 draft doesn't prohibit %s from occurring more than
+ // once, and if it does, I can't think of any problems that could
+ // cause, (though I don't know why anyone would need or want to do it).
+ mUriTemplate.ReplaceSubstring(NS_LITERAL_CSTRING("%s"),
+ escapedUriSpecToHandle);
+
+ // convert spec to URI; no original charset needed since there's no way
+ // to communicate that information to any handler
+ nsCOMPtr<nsIURI> uriToSend;
+ rv = NS_NewURI(getter_AddRefs(uriToSend), mUriTemplate);
+ if (NS_FAILED(rv)) {
+ AbandonOriginalChannel(rv);
+ return NS_OK;
+ }
+
+ // create a channel
+ nsCOMPtr<nsIChannel> newChannel;
+ rv = NS_NewChannel(getter_AddRefs(newChannel), uriToSend, nsnull,
+ mOriginalChannel->mLoadGroup,
+ mOriginalChannel->mCallbacks,
+ mOriginalChannel->mLoadFlags);
+ if (NS_FAILED(rv)) {
+ AbandonOriginalChannel(rv);
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsIChannelEventSink> eventSink;
+ NS_QueryNotificationCallbacks(mOriginalChannel->mCallbacks,
+ mOriginalChannel->mLoadGroup, eventSink);
+
+ if (eventSink) {
+ // XXX decide on and audit for correct session & global hist behavior
+ rv = eventSink->OnChannelRedirect(mOriginalChannel, newChannel,
+ nsIChannelEventSink::REDIRECT_TEMPORARY |
+ nsIChannelEventSink::REDIRECT_INTERNAL);
+ if (NS_FAILED(rv)) {
+ AbandonOriginalChannel(rv);
+ return NS_OK;
+ }
+ }
+
+ rv = newChannel->AsyncOpen(mListener, mContext);
+ if (NS_FAILED(rv)) {
+ AbandonOriginalChannel(rv);
+ return NS_OK;
+ }
+
+ mOriginalChannel->mStatus = NS_BINDING_REDIRECTED;
+ return NS_OK;
+ }
+
+ private:
+ nsCOMPtr<nsIURI> mURI;
+ nsCString mUriTemplate;
+ nsCOMPtr<nsIStreamListener> mListener;
+ nsCOMPtr<nsISupports> mContext;
+ nsCOMPtr<nsExtProtocolChannel> mOriginalChannel;
+
+ // necko guarantees that after an AsyncOpen has succeeded, OnStartRequest
+ // and OnStopRequest will get called
+ void AbandonOriginalChannel(const nsresult aStatus)
+ {
+ mOriginalChannel->mStatus = aStatus;
+ (void)mListener->OnStartRequest(mOriginalChannel, mContext);
+ (void)mListener->OnStopRequest(mOriginalChannel, mContext, aStatus);
+
+ return;
+ }
+
+};
+
NS_IMETHODIMP nsExtProtocolChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
{
+ // check whether the scheme is one that we have a web handler for
+ nsCAutoString urlScheme;
+ nsresult rv = mUrl->GetScheme(urlScheme);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIExternalProtocolService> extProtService =
+ do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCAutoString uriTemplate;
+ rv = nsExternalHelperAppService::GetWebProtocolHandlerURITemplate(urlScheme,
+ uriTemplate);
+ if (NS_SUCCEEDED(rv)) {
+
+ // redirecting to the web handler involvegs calling OnChannelRedirect,
+ // which is supposed to happen after AsyncOpen completes, so we do it in an
+ // event
+ nsCOMPtr<nsIRunnable> event = new nsWebProtocolRedirect(mUrl, uriTemplate,
+ listener, ctxt,
+ this);
+ rv = NS_DispatchToCurrentThread(event);
+ if (NS_SUCCEEDED(rv)) {
+ return rv;
+ }
+ }
+
+ // try for an OS-provided handler
OpenURL();
return NS_ERROR_NO_CONTENT; // force caller to abort.
}
NS_IMETHODIMP nsExtProtocolChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
{
- *aLoadFlags = 0;
+ *aLoadFlags = mLoadFlags;
return NS_OK;
}
NS_IMETHODIMP nsExtProtocolChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
{
+ mLoadFlags = aLoadFlags;
return NS_OK;
}
NS_IMETHODIMP nsExtProtocolChannel::GetContentType(nsACString &aContentType)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
@@ -255,18 +394,17 @@ NS_IMETHODIMP nsExtProtocolChannel::SetO
}
////////////////////////////////////////////////////////////////////////////////
// From nsIRequest
////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsExtProtocolChannel::GetName(nsACString &result)
{
- NS_NOTREACHED("nsExtProtocolChannel::GetName");
- return NS_ERROR_NOT_IMPLEMENTED;
+ return mUrl->GetSpec(result);
}
NS_IMETHODIMP nsExtProtocolChannel::IsPending(PRBool *result)
{
*result = PR_TRUE;
return NS_OK;
}
@@ -296,17 +434,16 @@ NS_IMETHODIMP nsExtProtocolChannel::Resu
///////////////////////////////////////////////////////////////////////
// the default protocol handler implementation
//////////////////////////////////////////////////////////////////////
nsExternalProtocolHandler::nsExternalProtocolHandler()
{
m_schemeName = "default";
- m_extProtService = do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
}
nsExternalProtocolHandler::~nsExternalProtocolHandler()
{}
NS_IMPL_THREADSAFE_ADDREF(nsExternalProtocolHandler)
NS_IMPL_THREADSAFE_RELEASE(nsExternalProtocolHandler)
@@ -333,25 +470,25 @@ NS_IMETHODIMP nsExternalProtocolHandler:
NS_IMETHODIMP
nsExternalProtocolHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval)
{
// don't override anything.
*_retval = PR_FALSE;
return NS_OK;
}
// returns TRUE if the OS can handle this protocol scheme and false otherwise.
-PRBool nsExternalProtocolHandler::HaveProtocolHandler(nsIURI * aURI)
+PRBool nsExternalProtocolHandler::HaveOSProtocolHandler(nsIURI * aURI)
{
PRBool haveHandler = PR_FALSE;
if (aURI)
{
nsCAutoString scheme;
aURI->GetScheme(scheme);
- if (m_extProtService)
- m_extProtService->ExternalProtocolHandlerExists(scheme.get(), &haveHandler);
+ if (gExtProtSvc)
+ gExtProtSvc->OSProtocolHandlerExists(scheme.get(), &haveHandler);
}
return haveHandler;
}
NS_IMETHODIMP nsExternalProtocolHandler::GetProtocolFlags(PRUint32 *aUritype)
{
// Make it norelative since it is a simple uri
@@ -375,18 +512,18 @@ NS_IMETHODIMP nsExternalProtocolHandler:
NS_ADDREF(*_retval = uri);
return NS_OK;
}
NS_IMETHODIMP nsExternalProtocolHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval)
{
// only try to return a channel if we have a protocol handler for the url
- PRBool haveHandler = HaveProtocolHandler(aURI);
- if (haveHandler)
+ PRBool haveOSHandler = HaveOSProtocolHandler(aURI);
+ if (haveOSHandler)
{
nsCOMPtr<nsIChannel> channel;
NS_NEWXPCOM(channel, nsExtProtocolChannel);
if (!channel) return NS_ERROR_OUT_OF_MEMORY;
((nsExtProtocolChannel*) channel.get())->SetURI(aURI);
channel->SetOriginalURI(aURI);
@@ -401,18 +538,19 @@ NS_IMETHODIMP nsExternalProtocolHandler:
return NS_ERROR_UNKNOWN_PROTOCOL;
}
///////////////////////////////////////////////////////////////////////
// External protocol handler interface implementation
//////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsExternalProtocolHandler::ExternalAppExistsForScheme(const nsACString& aScheme, PRBool *_retval)
{
- if (m_extProtService)
- return m_extProtService->ExternalProtocolHandlerExists(PromiseFlatCString(aScheme).get(), _retval);
+ if (gExtProtSvc)
+ return gExtProtSvc->ExternalProtocolHandlerExists(
+ PromiseFlatCString(aScheme).get(), _retval);
// In case we don't have external protocol service.
*_retval = PR_FALSE;
return NS_OK;
}
nsBlockedExternalProtocolHandler::nsBlockedExternalProtocolHandler()
{
--- a/uriloader/exthandler/nsExternalProtocolHandler.h
+++ b/uriloader/exthandler/nsExternalProtocolHandler.h
@@ -17,16 +17,17 @@
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Scott MacGregor <mscott@netscape.com>
+ * Dan Mosedale <dmose@mozilla.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either of 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
@@ -56,17 +57,17 @@ public:
NS_DECL_NSIPROTOCOLHANDLER
NS_DECL_NSIEXTERNALPROTOCOLHANDLER
nsExternalProtocolHandler();
~nsExternalProtocolHandler();
protected:
// helper function
- PRBool HaveProtocolHandler(nsIURI * aURI);
+ PRBool HaveOSProtocolHandler(nsIURI * aURI);
nsCString m_schemeName;
nsCOMPtr<nsIExternalProtocolService> m_extProtService;
};
class nsBlockedExternalProtocolHandler: public nsExternalProtocolHandler
{
public:
nsBlockedExternalProtocolHandler();
--- a/uriloader/exthandler/nsIExternalProtocolService.idl
+++ b/uriloader/exthandler/nsIExternalProtocolService.idl
@@ -40,17 +40,18 @@
#include "nsISupports.idl"
interface nsIURI;
interface nsIFile;
interface nsIPrompt;
/**
* The external protocol service is used for finding and launching
- * platform specific applications for particular protocols.
+ * web handlers (a la registerProtocolHandler in the HTML5 draft) or
+ * platform-specific applications for handling particular protocols.
*
* You can ask the external protocol service if it has an external
* handler for a given protocol scheme. And you can ask it to load
* the url using the default handler.
*/
[scriptable, uuid(a49813a4-98b7-4bdb-998c-8bd9704af0c0)]
interface nsIExternalProtocolService : nsISupports
{
--- a/uriloader/exthandler/os2/nsOSHelperAppService.cpp
+++ b/uriloader/exthandler/os2/nsOSHelperAppService.cpp
@@ -1235,19 +1235,19 @@ nsOSHelperAppService::GetApplicationAndP
/* application string in INI was empty */
if (app[0] == '\0')
return NS_ERROR_FAILURE;
return NS_OK;
}
-NS_IMETHODIMP nsOSHelperAppService::ExternalProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists)
+nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists)
{
- LOG(("-- nsOSHelperAppService::ExternalProtocolHandlerExists for '%s'\n",
+ LOG(("-- nsOSHelperAppService::OSProtocolHandlerExists for '%s'\n",
aProtocolScheme));
*aHandlerExists = PR_FALSE;
/* if applications.protocol is in prefs, then we have an external protocol handler */
nsresult rv;
nsCAutoString prefName;
prefName = NS_LITERAL_CSTRING("applications.") + nsDependentCString(aProtocolScheme);
--- a/uriloader/exthandler/os2/nsOSHelperAppService.h
+++ b/uriloader/exthandler/os2/nsOSHelperAppService.h
@@ -59,20 +59,20 @@ public:
virtual ~nsOSHelperAppService();
// method overrides for mime.types and mime.info look up steps
already_AddRefed<nsIMIMEInfo> GetMIMEInfoFromOS(const nsACString& aMimeType,
const nsACString& aFileExt,
PRBool *aFound);
// override nsIExternalProtocolService methods
- NS_IMETHOD ExternalProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists);
nsresult LoadUriInternal(nsIURI * aURL);
NS_IMETHODIMP GetApplicationDescription(const nsACString& aScheme, nsAString& _retval);
+ nsresult OSProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists);
protected:
already_AddRefed<nsMIMEInfoOS2> GetFromType(const nsCString& aMimeType);
already_AddRefed<nsMIMEInfoOS2> GetFromExtension(const nsCString& aFileExt);
private:
nsresult GetApplicationAndParametersFromINI(const nsACString& aProtocol,
char * app, unsigned long appLength,
char * param, unsigned long paramLength);
--- a/uriloader/exthandler/unix/nsOSHelperAppService.cpp
+++ b/uriloader/exthandler/unix/nsOSHelperAppService.cpp
@@ -1228,19 +1228,19 @@ nsOSHelperAppService::GetHandlerAppFromP
}
NS_RELEASE(*aApp);
}
// Thirdly, search the path
return GetFileTokenForPath(utf16AppPath.get(), aApp);
}
-NS_IMETHODIMP nsOSHelperAppService::ExternalProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists)
+nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists)
{
- LOG(("-- nsOSHelperAppService::ExternalProtocolHandlerExists for '%s'\n",
+ LOG(("-- nsOSHelperAppService::OSProtocolHandlerExists for '%s'\n",
aProtocolScheme));
*aHandlerExists = PR_FALSE;
nsCOMPtr<nsIFile> app;
nsresult rv = GetHandlerAppFromPrefs(aProtocolScheme, getter_AddRefs(app));
if (NS_SUCCEEDED(rv)) {
PRBool isExecutable = PR_FALSE, exists = PR_FALSE;
nsresult rv1 = app->Exists(&exists);
--- a/uriloader/exthandler/unix/nsOSHelperAppService.h
+++ b/uriloader/exthandler/unix/nsOSHelperAppService.h
@@ -58,17 +58,17 @@ public:
virtual ~nsOSHelperAppService();
// method overrides for mime.types and mime.info look up steps
already_AddRefed<nsIMIMEInfo> GetMIMEInfoFromOS(const nsACString& aMimeType,
const nsACString& aFileExt,
PRBool *aFound);
// override nsIExternalProtocolService methods
- NS_IMETHOD ExternalProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists);
+ nsresult OSProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists);
nsresult LoadUriInternal(nsIURI * aURL);
NS_IMETHOD GetApplicationDescription(const nsACString& aScheme, nsAString& _retval);
// GetFileTokenForPath must be implemented by each platform.
// platformAppPath --> a platform specific path to an application that we got out of the
// rdf data source. This can be a mac file spec, a unix path or a windows path depending on the platform
// aFile --> an nsIFile representation of that platform application path.
virtual nsresult GetFileTokenForPath(const PRUnichar * platformAppPath, nsIFile ** aFile);
--- a/uriloader/exthandler/win/nsOSHelperAppService.cpp
+++ b/uriloader/exthandler/win/nsOSHelperAppService.cpp
@@ -132,17 +132,17 @@ static nsresult GetExtensionFrom4xRegist
// we have a comma separated list of types...
// truncate everything after the first comma (including the comma)
aFileExtension.Truncate(pos);
}
return NS_OK;
}
-NS_IMETHODIMP nsOSHelperAppService::ExternalProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists)
+nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists)
{
// look up the protocol scheme in the windows registry....if we find a match then we have a handler for it...
*aHandlerExists = PR_FALSE;
if (aProtocolScheme && *aProtocolScheme)
{
HKEY hKey;
LONG err = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, aProtocolScheme, 0,
KEY_QUERY_VALUE, &hKey);
--- a/uriloader/exthandler/win/nsOSHelperAppService.h
+++ b/uriloader/exthandler/win/nsOSHelperAppService.h
@@ -52,17 +52,17 @@ class nsMIMEInfoWin;
class nsOSHelperAppService : public nsExternalHelperAppService
{
public:
nsOSHelperAppService();
virtual ~nsOSHelperAppService();
// override nsIExternalProtocolService methods
- NS_IMETHOD ExternalProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists);
+ nsresult OSProtocolHandlerExists(const char * aProtocolScheme, PRBool * aHandlerExists);
nsresult LoadUriInternal(nsIURI * aURL);
NS_IMETHOD GetApplicationDescription(const nsACString& aScheme, nsAString& _retval);
// method overrides for windows registry look up steps....
already_AddRefed<nsIMIMEInfo> GetMIMEInfoFromOS(const nsACString& aMIMEType, const nsACString& aFileExt, PRBool *aFound);
/** Get the string value of a registry value and store it in result.
* @return PR_TRUE on success, PR_FALSE on failure