From 210b7f773c2a277f6f94fa0c5a75a6bb8c3bc7cf Mon Sep 17 00:00:00 2001 From: "dmose%mozilla.org" Date: Mon, 3 Sep 2007 04:44:26 +0000 Subject: [PATCH] Fix for protocol handling dialog throwing exception when a web handler is selected (bug 392957), r=biesi, sr=mconnor, a=bz git-svn-id: svn://10.0.0.236/trunk@233779 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/docshell/base/nsWebShell.cpp | 2 +- mozilla/netwerk/mime/public/nsIMIMEInfo.idl | 21 +- .../mozapps/handling/content/dialog.js | 11 +- .../handling/src/nsContentDispatchChooser.js | 4 +- .../exthandler/mac/nsMIMEInfoMac.cpp | 5 +- .../uriloader/exthandler/mac/nsMIMEInfoMac.h | 3 +- .../exthandler/nsExternalHelperAppService.cpp | 7 +- .../exthandler/nsExternalProtocolHandler.cpp | 238 ++---------------- .../exthandler/nsIExternalProtocolService.idl | 17 +- .../uriloader/exthandler/nsMIMEInfoImpl.cpp | 71 +++++- mozilla/uriloader/exthandler/nsMIMEInfoImpl.h | 17 +- .../exthandler/os2/nsMIMEInfoOS2.cpp | 3 +- .../uriloader/exthandler/os2/nsMIMEInfoOS2.h | 3 +- 13 files changed, 152 insertions(+), 250 deletions(-) diff --git a/mozilla/docshell/base/nsWebShell.cpp b/mozilla/docshell/base/nsWebShell.cpp index 35c2eca14f3..d561c75893a 100644 --- a/mozilla/docshell/base/nsWebShell.cpp +++ b/mozilla/docshell/base/nsWebShell.cpp @@ -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); } } } diff --git a/mozilla/netwerk/mime/public/nsIMIMEInfo.idl b/mozilla/netwerk/mime/public/nsIMIMEInfo.idl index 1534c9494af..57286e662d5 100644 --- a/mozilla/netwerk/mime/public/nsIMIMEInfo.idl +++ b/mozilla/netwerk/mime/public/nsIMIMEInfo.idl @@ -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 diff --git a/mozilla/toolkit/mozapps/handling/content/dialog.js b/mozilla/toolkit/mozapps/handling/content/dialog.js index 90b5b32ec88..2bb1b2d7c1f 100644 --- a/mozilla/toolkit/mozapps/handling/content/dialog.js +++ b/mozilla/toolkit/mozapps/handling/content/dialog.js @@ -20,6 +20,7 @@ * * Contributor(s): * Shawn Wilsher (original author) + * Dan Mosedale * * 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; }, diff --git a/mozilla/toolkit/mozapps/handling/src/nsContentDispatchChooser.js b/mozilla/toolkit/mozapps/handling/src/nsContentDispatchChooser.js index 156fb315750..02a8d0c5fea 100644 --- a/mozilla/toolkit/mozapps/handling/src/nsContentDispatchChooser.js +++ b/mozilla/toolkit/mozapps/handling/src/nsContentDispatchChooser.js @@ -20,6 +20,7 @@ * * Contributor(s): * Shawn Wilsher (Original Author) + * Dan Mosedale * * 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, diff --git a/mozilla/uriloader/exthandler/mac/nsMIMEInfoMac.cpp b/mozilla/uriloader/exthandler/mac/nsMIMEInfoMac.cpp index 685e2c6e29b..b6e5ad03317 100755 --- a/mozilla/uriloader/exthandler/mac/nsMIMEInfoMac.cpp +++ b/mozilla/uriloader/exthandler/mac/nsMIMEInfoMac.cpp @@ -100,7 +100,8 @@ nsMIMEInfoMac::LaunchWithFile(nsIFile *aFile) } NS_IMETHODIMP -nsMIMEInfoMac::LaunchWithURI(nsIURI* aURI) +nsMIMEInfoMac::LaunchWithURI(nsIURI* aURI, + nsIInterfaceRequestor* aWindowContext) { nsCOMPtr application; nsresult rv; @@ -117,7 +118,7 @@ nsMIMEInfoMac::LaunchWithURI(nsIURI* aURI) nsCOMPtr 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 diff --git a/mozilla/uriloader/exthandler/mac/nsMIMEInfoMac.h b/mozilla/uriloader/exthandler/mac/nsMIMEInfoMac.h index 6ac99b13efb..bc302ef1468 100755 --- a/mozilla/uriloader/exthandler/mac/nsMIMEInfoMac.h +++ b/mozilla/uriloader/exthandler/mac/nsMIMEInfoMac.h @@ -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: diff --git a/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp b/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp index a032ba52f7c..1513b3bdc2c 100644 --- a/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -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 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)) { diff --git a/mozilla/uriloader/exthandler/nsExternalProtocolHandler.cpp b/mozilla/uriloader/exthandler/nsExternalProtocolHandler.cpp index d16465417e7..81331366a58 100644 --- a/mozilla/uriloader/exthandler/nsExternalProtocolHandler.cpp +++ b/mozilla/uriloader/exthandler/nsExternalProtocolHandler.cpp @@ -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 mOriginalURI; nsresult mStatus; nsLoadFlags mLoadFlags; - PRBool mIsPending; PRBool mWasOpened; nsCOMPtr mCallbacks; nsCOMPtr mLoadGroup; - nsCOMPtr mListener; - nsCOMPtr 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 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 handlerApp; - nsresult rv = - mHandlerInfo->GetPreferredApplicationHandler(getter_AddRefs(handlerApp)); - if (NS_FAILED(rv)) { - mOriginalChannel->Finish(rv); - return NS_OK; - } - - nsCOMPtr 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 uriToSend; - rv = NS_NewURI(getter_AddRefs(uriToSend), uriTemplate); - if (NS_FAILED(rv)) { - mOriginalChannel->Finish(rv); - return NS_OK; - } - - // create a channel - nsCOMPtr 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 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 mURI; - nsCOMPtr mHandlerInfo; - nsCOMPtr mListener; - nsCOMPtr mContext; - nsCOMPtr 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 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 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 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 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; } diff --git a/mozilla/uriloader/exthandler/nsIExternalProtocolService.idl b/mozilla/uriloader/exthandler/nsIExternalProtocolService.idl index f7e3f5d801a..2d207088958 100644 --- a/mozilla/uriloader/exthandler/nsIExternalProtocolService.idl +++ b/mozilla/uriloader/exthandler/nsIExternalProtocolService.idl @@ -23,6 +23,7 @@ * Contributor(s): * Scott MacGregor * Myk Melez + * Dan Mosedale * * 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); diff --git a/mozilla/uriloader/exthandler/nsMIMEInfoImpl.cpp b/mozilla/uriloader/exthandler/nsMIMEInfoImpl.cpp index 9e61bfa87e9..63f650edfbc 100644 --- a/mozilla/uriloader/exthandler/nsMIMEInfoImpl.cpp +++ b/mozilla/uriloader/exthandler/nsMIMEInfoImpl.cpp @@ -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 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 uriToSend; + rv = NS_NewURI(getter_AddRefs(uriToSend), uriTemplate); + if (NS_FAILED(rv)) + return rv; + + // create a channel + nsCOMPtr 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 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 + // for details. + return uriLoader->OpenURI(newChannel, PR_TRUE, aWindowContext); } // nsMIMEInfoImpl implementation diff --git a/mozilla/uriloader/exthandler/nsMIMEInfoImpl.h b/mozilla/uriloader/exthandler/nsMIMEInfoImpl.h index a7f257d9522..ba322497fa8 100644 --- a/mozilla/uriloader/exthandler/nsMIMEInfoImpl.h +++ b/mozilla/uriloader/exthandler/nsMIMEInfoImpl.h @@ -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 diff --git a/mozilla/uriloader/exthandler/os2/nsMIMEInfoOS2.cpp b/mozilla/uriloader/exthandler/os2/nsMIMEInfoOS2.cpp index 1440eb077d9..e5e9521bb64 100755 --- a/mozilla/uriloader/exthandler/os2/nsMIMEInfoOS2.cpp +++ b/mozilla/uriloader/exthandler/os2/nsMIMEInfoOS2.cpp @@ -59,7 +59,8 @@ nsMIMEInfoOS2::~nsMIMEInfoOS2() { } -NS_IMETHODIMP nsMIMEInfoOS2::LaunchWithURI(nsIURI* aURI) +NS_IMETHODIMP nsMIMEInfoOS2::LaunchWithURI(nsIURI* aURI, + nsIInterfaceRequestor* aWindowContext) { nsresult rv = NS_OK; diff --git a/mozilla/uriloader/exthandler/os2/nsMIMEInfoOS2.h b/mozilla/uriloader/exthandler/os2/nsMIMEInfoOS2.h index 15b76c34ab1..c7f500e69da 100755 --- a/mozilla/uriloader/exthandler/os2/nsMIMEInfoOS2.h +++ b/mozilla/uriloader/exthandler/os2/nsMIMEInfoOS2.h @@ -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