зеркало из https://github.com/mozilla/gecko-dev.git
Fix for protocol handling dialog throwing exception when a web handler is selected (bug 392957), r=biesi, sr=mconnor, a=bz
This commit is contained in:
Родитель
a79dcd72fc
Коммит
4ad19860ce
|
@ -818,7 +818,7 @@ nsWebShell::OnLinkClickSync(nsIContent *aContent,
|
|||
PRBool isExposed;
|
||||
nsresult rv = extProtService->IsExposedProtocol(scheme.get(), &isExposed);
|
||||
if (NS_SUCCEEDED(rv) && !isExposed) {
|
||||
return extProtService->LoadUrl(aURI);
|
||||
return extProtService->LoadURI(aURI, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ interface nsIFile;
|
|||
interface nsIUTF8StringEnumerator;
|
||||
interface nsIHandlerApp;
|
||||
interface nsIMutableArray;
|
||||
interface nsIInterfaceRequestor;
|
||||
|
||||
typedef long nsHandlerInfoAction;
|
||||
|
||||
|
@ -50,7 +51,7 @@ typedef long nsHandlerInfoAction;
|
|||
* nsIHandlerInfo gives access to the information about how a given protocol
|
||||
* scheme or MIME-type is handled.
|
||||
*/
|
||||
[scriptable, uuid(4c7f5603-cfa9-4576-a769-c3343cb0135b)]
|
||||
[scriptable, uuid(325e56a7-3762-4312-aec7-f1fcf84b4145)]
|
||||
interface nsIHandlerInfo : nsISupports {
|
||||
/**
|
||||
* The type of this handler info. For MIME handlers, this is the MIME type.
|
||||
|
@ -106,12 +107,22 @@ interface nsIHandlerInfo : nsISupports {
|
|||
* and our code will not make any decision based on the content-type or
|
||||
* extension, though the invoked file: handler is free to do so.
|
||||
*
|
||||
* @param aURI The URI to launch this application with
|
||||
* @param aURI
|
||||
* The URI to launch this application with
|
||||
*
|
||||
* @throw NS_ERROR_INVALID_ARG if action is not valid for this function.
|
||||
* Other exceptions may be thrown.
|
||||
* @param aWindowContext
|
||||
* The window to parent the dialog against, and, if a web handler
|
||||
* is chosen, it is loaded in this window as well. This parameter
|
||||
* may be ultimately passed nsIURILoader.openURI in the case of a
|
||||
* web handler, and aWindowContext is null or not present, web
|
||||
* handlers will fail. We need to do better than that; bug 394483
|
||||
* filed in order to track.
|
||||
*
|
||||
* @throw NS_ERROR_INVALID_ARG if preferredAction is not valid for this
|
||||
* call. Other exceptions may be thrown.
|
||||
*/
|
||||
void launchWithURI(in nsIURI aURI);
|
||||
void launchWithURI(in nsIURI aURI,
|
||||
[optional] in nsIInterfaceRequestor aWindowContext);
|
||||
|
||||
/**
|
||||
* preferredAction is how the user specified they would like to handle
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Shawn Wilsher <me@shawnwilsher.com> (original author)
|
||||
* Dan Mosedale <dmose@mozilla.org>
|
||||
*
|
||||
* 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
|
||||
|
@ -55,6 +56,8 @@
|
|||
* This is the nsIHandlerInfo that gives us all our precious information.
|
||||
* window.arguments[7]:
|
||||
* This is the nsIURI that we are being brought up for in the first place.
|
||||
* window.arguments[8]:
|
||||
* The nsIInterfaceRequestor of the parent window; may be null
|
||||
*/
|
||||
|
||||
const Cc = Components.classes;
|
||||
|
@ -69,7 +72,8 @@ var dialog = {
|
|||
_URI: null,
|
||||
_itemChoose: null,
|
||||
_okButton: null,
|
||||
|
||||
_windowCtxt: null,
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// Methods
|
||||
|
||||
|
@ -80,6 +84,9 @@ var dialog = {
|
|||
{
|
||||
this._handlerInfo = window.arguments[6].QueryInterface(Ci.nsIHandlerInfo);
|
||||
this._URI = window.arguments[7].QueryInterface(Ci.nsIURI);
|
||||
this._windowCtxt = window.arguments[8];
|
||||
if (this._windowCtxt)
|
||||
this._windowCtxt.QueryInterface(Ci.nsIInterfaceRequestor);
|
||||
this._itemChoose = document.getElementById("item-choose");
|
||||
this._okButton = document.documentElement.getButton("accept");
|
||||
|
||||
|
@ -202,7 +209,7 @@ var dialog = {
|
|||
getService(Ci.nsIHandlerService);
|
||||
hs.store(this._handlerInfo);
|
||||
|
||||
this._handlerInfo.launchWithURI(this._URI);
|
||||
this._handlerInfo.launchWithURI(this._URI, this._windowCtxt);
|
||||
|
||||
return true;
|
||||
},
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
|
||||
* Dan Mosedale <dmose@mozilla.org>
|
||||
*
|
||||
* 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
|
||||
|
@ -99,7 +100,8 @@ nsContentDispatchChooser.prototype =
|
|||
}
|
||||
params.appendElement(aHandler, false);
|
||||
params.appendElement(aURI, false);
|
||||
|
||||
params.appendElement(aWindowContext, false);
|
||||
|
||||
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
|
||||
getService(Ci.nsIWindowWatcher);
|
||||
ww.openWindow(window,
|
||||
|
|
|
@ -100,7 +100,8 @@ nsMIMEInfoMac::LaunchWithFile(nsIFile *aFile)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoMac::LaunchWithURI(nsIURI* aURI)
|
||||
nsMIMEInfoMac::LaunchWithURI(nsIURI* aURI,
|
||||
nsIInterfaceRequestor* aWindowContext)
|
||||
{
|
||||
nsCOMPtr<nsIFile> application;
|
||||
nsresult rv;
|
||||
|
@ -117,7 +118,7 @@ nsMIMEInfoMac::LaunchWithURI(nsIURI* aURI)
|
|||
nsCOMPtr<nsIWebHandlerApp> webHandlerApp =
|
||||
do_QueryInterface(mPreferredApplication, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return LaunchWithWebHandler(webHandlerApp, aURI);
|
||||
return LaunchWithWebHandler(webHandlerApp, aURI, aWindowContext);
|
||||
}
|
||||
|
||||
// otherwise, get the application executable from the handler
|
||||
|
|
|
@ -46,7 +46,8 @@ class nsMIMEInfoMac : public nsMIMEInfoImpl {
|
|||
nsMIMEInfoMac(const nsACString& aType, HandlerClass aClass) :
|
||||
nsMIMEInfoImpl(aType, aClass) {}
|
||||
|
||||
NS_IMETHOD LaunchWithURI(nsIURI* aURI);
|
||||
NS_IMETHOD LaunchWithURI(nsIURI* aURI,
|
||||
nsIInterfaceRequestor* aWindowContext);
|
||||
NS_IMETHOD LaunchWithFile(nsIFile* aFile);
|
||||
NS_IMETHOD GetHasDefaultHandler(PRBool *_retval);
|
||||
protected:
|
||||
|
|
|
@ -124,7 +124,6 @@
|
|||
|
||||
#include "nsCRT.h"
|
||||
|
||||
#include "nsMIMEInfoImpl.h"
|
||||
#include "nsLocalHandlerApp.h"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -1339,7 +1338,7 @@ nsExternalHelperAppService::LoadURI(nsIURI *aURI,
|
|||
if (!warn &&
|
||||
!alwaysAsk && (preferredAction == nsIHandlerInfo::useHelperApp ||
|
||||
preferredAction == nsIHandlerInfo::useSystemDefault))
|
||||
return handler->LaunchWithURI(uri);
|
||||
return handler->LaunchWithURI(uri, aWindowContext);
|
||||
|
||||
nsCOMPtr<nsIContentDispatchChooser> chooser =
|
||||
do_CreateInstance("@mozilla.org/content-dispatch-chooser;1", &rv);
|
||||
|
@ -1407,10 +1406,6 @@ nsExternalHelperAppService::GetProtocolHandlerInfo(const nsACString &aScheme,
|
|||
// XXX enterprise customers should be able to turn this support off with a
|
||||
// single master pref (maybe use one of the "exposed" prefs here?)
|
||||
|
||||
// nsIMIMEInfo is a superset of nsIHandlerInfo. Furthermore, nsMimeInfoImpl
|
||||
// and subclasses have lots of good platform specific-knowledge of local
|
||||
// applications which we might need later. For now, just use nsMIMEInfoImpl
|
||||
// instead of implementating a separate nsIHandlerInfo object.
|
||||
PRBool exists;
|
||||
*aHandlerInfo = GetProtocolInfoFromOS(aScheme, &exists).get();
|
||||
if (!(*aHandlerInfo)) {
|
||||
|
|
|
@ -53,9 +53,6 @@
|
|||
#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
|
||||
|
@ -69,8 +66,6 @@
|
|||
|
||||
class nsExtProtocolChannel : public nsIChannel
|
||||
{
|
||||
friend class nsProtocolRedirect;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICHANNEL
|
||||
|
@ -89,13 +84,10 @@ private:
|
|||
nsCOMPtr<nsIURI> mOriginalURI;
|
||||
nsresult mStatus;
|
||||
nsLoadFlags mLoadFlags;
|
||||
PRBool mIsPending;
|
||||
PRBool mWasOpened;
|
||||
|
||||
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
nsCOMPtr<nsIStreamListener> mListener;
|
||||
nsCOMPtr<nsISupports> mContext;
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ADDREF(nsExtProtocolChannel)
|
||||
|
@ -108,7 +100,6 @@ NS_INTERFACE_MAP_BEGIN(nsExtProtocolChannel)
|
|||
NS_INTERFACE_MAP_END_THREADSAFE
|
||||
|
||||
nsExtProtocolChannel::nsExtProtocolChannel() : mStatus(NS_OK),
|
||||
mIsPending(PR_FALSE),
|
||||
mWasOpened(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
@ -188,233 +179,40 @@ nsresult nsExtProtocolChannel::OpenURL()
|
|||
NS_ASSERTION(haveHandler, "Why do we have a channel for this url if we don't support the protocol?");
|
||||
#endif
|
||||
|
||||
rv = extProtService->LoadURI(mUrl, mCallbacks);
|
||||
nsCOMPtr<nsIInterfaceRequestor> aggCallbacks;
|
||||
rv = NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
|
||||
getter_AddRefs(aggCallbacks));
|
||||
if (NS_FAILED(rv)) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
rv = extProtService->LoadURI(mUrl, aggCallbacks);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// despite success, we need to abort this channel, at the very least
|
||||
// to make it clear to the caller that no on{Start,Stop}Request
|
||||
// should be expected.
|
||||
rv = NS_ERROR_NO_CONTENT;
|
||||
}
|
||||
}
|
||||
|
||||
// Drop notification callbacks to prevent cycles.
|
||||
finish:
|
||||
mCallbacks = 0;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::Open(nsIInputStream **_retval)
|
||||
{
|
||||
OpenURL();
|
||||
return NS_ERROR_NO_CONTENT; // force caller to abort.
|
||||
return OpenURL();
|
||||
}
|
||||
|
||||
class nsProtocolRedirect : public nsRunnable {
|
||||
public:
|
||||
nsProtocolRedirect(nsIURI *aURI, nsIHandlerInfo *aHandlerInfo,
|
||||
nsIStreamListener *aListener, nsISupports *aContext,
|
||||
nsExtProtocolChannel *aOriginalChannel)
|
||||
: mURI(aURI), mHandlerInfo(aHandlerInfo), mListener(aListener),
|
||||
mContext(aContext), mOriginalChannel(aOriginalChannel) {}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
// for now, this code path is only take for a web-based protocol handler
|
||||
nsCOMPtr<nsIHandlerApp> handlerApp;
|
||||
nsresult rv =
|
||||
mHandlerInfo->GetPreferredApplicationHandler(getter_AddRefs(handlerApp));
|
||||
if (NS_FAILED(rv)) {
|
||||
mOriginalChannel->Finish(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWebHandlerApp> webHandlerApp = do_QueryInterface(handlerApp,
|
||||
&rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
mOriginalChannel->Finish(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCAutoString uriTemplate;
|
||||
rv = webHandlerApp->GetUriTemplate(uriTemplate);
|
||||
if (NS_FAILED(rv)) {
|
||||
mOriginalChannel->Finish(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// get the URI spec so we can escape it for insertion into the template
|
||||
nsCAutoString uriSpecToHandle;
|
||||
rv = mURI->GetSpec(uriSpecToHandle);
|
||||
if (NS_FAILED(rv)) {
|
||||
mOriginalChannel->Finish(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).
|
||||
uriTemplate.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), uriTemplate);
|
||||
if (NS_FAILED(rv)) {
|
||||
mOriginalChannel->Finish(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// create a channel
|
||||
nsCOMPtr<nsIChannel> newChannel;
|
||||
rv = NS_NewChannel(getter_AddRefs(newChannel), uriToSend, nsnull,
|
||||
mOriginalChannel->mLoadGroup,
|
||||
mOriginalChannel->mCallbacks,
|
||||
mOriginalChannel->mLoadFlags
|
||||
| nsIChannel::LOAD_REPLACE);
|
||||
if (NS_FAILED(rv)) {
|
||||
mOriginalChannel->Finish(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)) {
|
||||
mOriginalChannel->Finish(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
rv = newChannel->AsyncOpen(mListener, mContext);
|
||||
if (NS_FAILED(rv)) {
|
||||
mOriginalChannel->Finish(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mOriginalChannel->Finish(NS_BINDING_REDIRECTED);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsIHandlerInfo> mHandlerInfo;
|
||||
nsCOMPtr<nsIStreamListener> mListener;
|
||||
nsCOMPtr<nsISupports> mContext;
|
||||
nsCOMPtr<nsExtProtocolChannel> mOriginalChannel;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(listener);
|
||||
NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
|
||||
NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
|
||||
|
||||
mWasOpened = PR_TRUE;
|
||||
mListener = listener;
|
||||
mContext = ctxt;
|
||||
|
||||
if (!gExtProtSvc) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCAutoString urlScheme;
|
||||
nsresult rv = mUrl->GetScheme(urlScheme);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// check whether the scheme is one that we have a web handler for
|
||||
nsCOMPtr<nsIHandlerInfo> handlerInfo;
|
||||
rv = gExtProtSvc->GetProtocolHandlerInfo(urlScheme,
|
||||
getter_AddRefs(handlerInfo));
|
||||
// TODO all this code should be moved to nsIHandlerInfo::LaunchWithURI
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PRInt32 preferredAction;
|
||||
rv = handlerInfo->GetPreferredAction(&preferredAction);
|
||||
|
||||
if (preferredAction == nsIHandlerInfo::useHelperApp) {
|
||||
|
||||
nsCOMPtr<nsIHandlerApp> handler;
|
||||
rv = handlerInfo->GetPreferredApplicationHandler(getter_AddRefs(handler));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Now we check to see if this is a local handler or not
|
||||
nsCOMPtr<nsILocalHandlerApp> localHandler =
|
||||
do_QueryInterface(handler, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
OpenURL();
|
||||
return NS_ERROR_NO_CONTENT; // force caller to abort
|
||||
}
|
||||
|
||||
// We must have a web handler
|
||||
// redirecting to the web handler involves calling OnChannelRedirect
|
||||
// (which is supposed to happen after AsyncOpen completes) or possibly
|
||||
// opening a dialog, so we do it in an event
|
||||
nsCOMPtr<nsIRunnable> event = new nsProtocolRedirect(mUrl, handlerInfo,
|
||||
listener, ctxt,
|
||||
this);
|
||||
|
||||
// We don't check if |event| was successfully created because
|
||||
// |NS_DispatchToCurrentThread| will do that for us.
|
||||
rv = NS_DispatchToCurrentThread(event);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mIsPending = PR_TRUE;
|
||||
|
||||
// add ourselves to the load group, since this isn't going to finish
|
||||
// immediately
|
||||
if (mLoadGroup)
|
||||
(void)mLoadGroup->AddRequest(this, nsnull);
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no protocol info found, just fall back on whatever the OS has to offer
|
||||
OpenURL();
|
||||
return NS_ERROR_NO_CONTENT; // force caller to abort.
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish out what was started in AsyncOpen. This can be called in either the
|
||||
* success or the failure case.
|
||||
*
|
||||
* @param aStatus used to set the channel's status, and, if this set to
|
||||
* anything other than NS_BINDING_REDIRECTED, OnStartRequest
|
||||
* and OnStopRequest will be called, since Necko guarantees
|
||||
* this will happen unless the redirect took place.
|
||||
*/
|
||||
void nsExtProtocolChannel::Finish(nsresult aStatus)
|
||||
{
|
||||
mStatus = aStatus;
|
||||
|
||||
if (aStatus != NS_BINDING_REDIRECTED && mListener) {
|
||||
(void)mListener->OnStartRequest(this, mContext);
|
||||
(void)mListener->OnStopRequest(this, mContext, aStatus);
|
||||
}
|
||||
|
||||
mIsPending = PR_FALSE;
|
||||
|
||||
if (mLoadGroup) {
|
||||
(void)mLoadGroup->RemoveRequest(this, nsnull, aStatus);
|
||||
}
|
||||
return;
|
||||
return OpenURL();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
|
||||
|
@ -485,7 +283,7 @@ NS_IMETHODIMP nsExtProtocolChannel::GetName(nsACString &result)
|
|||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::IsPending(PRBool *result)
|
||||
{
|
||||
*result = mIsPending;
|
||||
*result = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
* Contributor(s):
|
||||
* Scott MacGregor <mscott@netscape.com>
|
||||
* Myk Melez <myk@mozilla.org>
|
||||
* 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"),
|
||||
|
@ -105,8 +106,20 @@ interface nsIExternalProtocolService : nsISupports
|
|||
* Used to load a URI via an external application. Might prompt the user for
|
||||
* permission to load the external application.
|
||||
*
|
||||
* @param aURI The URI to load
|
||||
* @param aWindowContext The parent window to open the dialog with.
|
||||
* @param aURI
|
||||
* The URI to load
|
||||
*
|
||||
* @param aWindowContext
|
||||
* The window to parent the dialog against, and, if a web handler
|
||||
* is chosen, it is loaded in this window as well. This parameter
|
||||
* may be ultimately passed nsIURILoader.openURI in the case of a
|
||||
* web handler, and aWindowContext is null or not present, web
|
||||
* handlers will fail. We need to do better than that; bug 394483
|
||||
* filed in order to track.
|
||||
*
|
||||
* @note Embedders that do not expose the http protocol should not currently
|
||||
* use web-based protocol handlers, as handoff won't work correctly
|
||||
* (bug 394479).
|
||||
*/
|
||||
void loadURI(in nsIURI aURI,
|
||||
[optional] in nsIInterfaceRequestor aWindowContext);
|
||||
|
|
|
@ -43,6 +43,10 @@
|
|||
#include "nsIProcess.h"
|
||||
#include "nsILocalFile.h"
|
||||
#include "nsIFileURL.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIURILoader.h"
|
||||
#include "nsCURILoader.h"
|
||||
|
||||
// nsISupports methods
|
||||
NS_IMPL_THREADSAFE_ADDREF(nsMIMEInfoBase)
|
||||
|
@ -380,7 +384,8 @@ nsMIMEInfoBase::LaunchWithFile(nsIFile* aFile)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoBase::LaunchWithURI(nsIURI* aURI)
|
||||
nsMIMEInfoBase::LaunchWithURI(nsIURI* aURI,
|
||||
nsIInterfaceRequestor* aWindowContext)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
|
@ -402,7 +407,7 @@ nsMIMEInfoBase::LaunchWithURI(nsIURI* aURI)
|
|||
nsCOMPtr<nsIWebHandlerApp> webHandler =
|
||||
do_QueryInterface(mPreferredApplication, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return LaunchWithWebHandler(webHandler, aURI);
|
||||
return LaunchWithWebHandler(webHandler, aURI, aWindowContext);
|
||||
}
|
||||
|
||||
// ok, we must have a local handler app
|
||||
|
@ -456,10 +461,66 @@ nsMIMEInfoBase::LaunchWithIProcess(nsIFile* aApp, const nsCString& aArg)
|
|||
|
||||
/* static */
|
||||
nsresult
|
||||
nsMIMEInfoBase::LaunchWithWebHandler(nsIWebHandlerApp *aApp, nsIURI *aURI)
|
||||
nsMIMEInfoBase::LaunchWithWebHandler(nsIWebHandlerApp *aApp, nsIURI *aURI,
|
||||
nsIInterfaceRequestor *aWindowContext)
|
||||
{
|
||||
// we'll be implementing this Real Soon Now!
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
nsCAutoString uriTemplate;
|
||||
nsresult rv = aApp->GetUriTemplate(uriTemplate);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// get the URI spec so we can escape it for insertion into the template
|
||||
nsCAutoString uriSpecToHandle;
|
||||
rv = aURI->GetSpec(uriSpecToHandle);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// 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 (bug 382019).
|
||||
nsCAutoString escapedUriSpecToHandle;
|
||||
NS_EscapeURL(uriSpecToHandle, esc_Minimal | esc_Forced | esc_Colon,
|
||||
escapedUriSpecToHandle);
|
||||
|
||||
// XXX note that this replace all occurrences of %s with the URL to be
|
||||
// handled, instead of just the first, as specified by the current draft
|
||||
// of the spec. Bug 394476 filed to track this.
|
||||
uriTemplate.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), uriTemplate);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// create a channel
|
||||
nsCOMPtr<nsIChannel> newChannel;
|
||||
rv = NS_NewChannel(getter_AddRefs(newChannel), uriToSend, nsnull, nsnull,
|
||||
nsnull, nsIChannel::LOAD_DOCUMENT_URI);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// load the URI
|
||||
nsCOMPtr<nsIURILoader> uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID,
|
||||
&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// XXX ideally, aIsContentPreferred (the second param) should really be
|
||||
// passed in from above. Practically, PR_TRUE is probably a reasonable
|
||||
// default since browsers don't care much, and link click is likely to be
|
||||
// the more interesting case for non-browser apps. See
|
||||
// <https://bugzilla.mozilla.org/show_bug.cgi?id=392957#c9> for details.
|
||||
return uriLoader->OpenURI(newChannel, PR_TRUE, aWindowContext);
|
||||
}
|
||||
|
||||
// nsMIMEInfoImpl implementation
|
||||
|
|
|
@ -89,7 +89,8 @@ class nsMIMEInfoBase : public nsIMIMEInfo {
|
|||
NS_IMETHOD GetPossibleApplicationHandlers(nsIMutableArray * *aPossibleAppHandlers);
|
||||
NS_IMETHOD GetDefaultDescription(nsAString & aDefaultDescription);
|
||||
NS_IMETHOD LaunchWithFile(nsIFile *aFile);
|
||||
NS_IMETHOD LaunchWithURI(nsIURI *aURI);
|
||||
NS_IMETHOD LaunchWithURI(nsIURI *aURI,
|
||||
nsIInterfaceRequestor *aWindowContext);
|
||||
NS_IMETHOD GetPreferredAction(nsHandlerInfoAction *aPreferredAction);
|
||||
NS_IMETHOD SetPreferredAction(nsHandlerInfoAction aPreferredAction);
|
||||
NS_IMETHOD GetAlwaysAskBeforeHandling(PRBool *aAlwaysAskBeforeHandling);
|
||||
|
@ -158,9 +159,19 @@ class nsMIMEInfoBase : public nsIMIMEInfo {
|
|||
* Used to launch a web-based handler with this URI.
|
||||
*
|
||||
* @param aURI The URI to launch with.
|
||||
*
|
||||
* @param aWindowContext
|
||||
* The window to parent the dialog against, and, if a web handler
|
||||
* is chosen, it is loaded in this window as well. This parameter
|
||||
* may be ultimately passed nsIURILoader.openURI in the case of a
|
||||
* web handler, and aWindowContext is null or not present, web
|
||||
* handlers will fail. We need to do better than that; bug 394483
|
||||
* filed in order to track.
|
||||
*
|
||||
*/
|
||||
static NS_HIDDEN_(nsresult) LaunchWithWebHandler(nsIWebHandlerApp *aApp,
|
||||
nsIURI *aURI);
|
||||
static NS_HIDDEN_(nsresult)
|
||||
LaunchWithWebHandler(nsIWebHandlerApp *aApp, nsIURI *aURI,
|
||||
nsIInterfaceRequestor *aWindowContext);
|
||||
|
||||
/**
|
||||
* Given a file: nsIURI, return the associated nsILocalFile
|
||||
|
|
|
@ -59,7 +59,8 @@ nsMIMEInfoOS2::~nsMIMEInfoOS2()
|
|||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMIMEInfoOS2::LaunchWithURI(nsIURI* aURI)
|
||||
NS_IMETHODIMP nsMIMEInfoOS2::LaunchWithURI(nsIURI* aURI,
|
||||
nsIInterfaceRequestor* aWindowContext)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
|
|
|
@ -64,7 +64,8 @@ class nsMIMEInfoOS2 : public nsMIMEInfoImpl
|
|||
nsMIMEInfoImpl(aType, aClass) {}
|
||||
virtual ~nsMIMEInfoOS2();
|
||||
|
||||
NS_IMETHOD LaunchWithURI(nsIURI* aURI);
|
||||
NS_IMETHOD LaunchWithURI(nsIURI* aURI,
|
||||
nsIInterfaceRequestor* aWindowContext);
|
||||
protected:
|
||||
virtual NS_HIDDEN_(nsresult) LoadUriInternal(nsIURI *aURI);
|
||||
#ifdef DEBUG
|
||||
|
|
Загрузка…
Ссылка в новой задаче