--- a/docshell/base/nsWebShell.cpp
+++ b/docshell/base/nsWebShell.cpp
@@ -813,17 +813,17 @@ nsWebShell::OnLinkClickSync(nsIContent *
nsCAutoString scheme;
aURI->GetScheme(scheme);
if (!scheme.IsEmpty()) {
// if the URL scheme does not correspond to an exposed protocol, then we
// need to hand this link click over to the external protocol handler.
PRBool isExposed;
nsresult rv = extProtService->IsExposedProtocol(scheme.get(), &isExposed);
if (NS_SUCCEEDED(rv) && !isExposed) {
- return extProtService->LoadUrl(aURI);
+ return extProtService->LoadURI(aURI, this);
}
}
}
}
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aContent));
NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
--- a/netwerk/mime/public/nsIMIMEInfo.idl
+++ b/netwerk/mime/public/nsIMIMEInfo.idl
@@ -38,24 +38,25 @@
#include "nsISupports.idl"
interface nsIURI;
interface nsIFile;
interface nsIUTF8StringEnumerator;
interface nsIHandlerApp;
interface nsIMutableArray;
+interface nsIInterfaceRequestor;
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.
* For protocol handlers, it's the scheme.
*
* @return String representing the type.
*/
readonly attribute ACString type;
@@ -101,22 +102,32 @@ interface nsIHandlerInfo : nsISupports {
* useHelperApp or useSystemDefault.
*
* @note Only the URI scheme is used to determine how to launch. This is
* essentially a pass-by-value operation. This means that in the case of
* a file: URI, the handler that is registered for file: will be launched
* 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
* this content type: save to disk, use specified helper app, use OS
* default handler or handle using navigator; possible value constants
* listed below
*/
attribute nsHandlerInfoAction preferredAction;
--- a/toolkit/mozapps/handling/content/dialog.js
+++ b/toolkit/mozapps/handling/content/dialog.js
@@ -15,16 +15,17 @@
*
* 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)
+ * 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
* 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
@@ -50,41 +51,47 @@
* This is the text to be placed in the label for the checkbox. If no text is
* passed (ie, it's an empty string), the checkbox will be hidden.
* window.arguments[5]:
* This is the text that is displayed below the checkbox when it is checked.
* window.arguments[6]:
* 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;
const Ci = Components.interfaces;
const Cr = Components.results;
var dialog = {
//////////////////////////////////////////////////////////////////////////////
//// Member Variables
_handlerInfo: null,
_URI: null,
_itemChoose: null,
_okButton: null,
-
+ _windowCtxt: null,
+
//////////////////////////////////////////////////////////////////////////////
//// Methods
/**
* This function initializes the content of the dialog.
*/
initialize: function initialize()
{
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");
this.updateOKButton();
var description = {
image: document.getElementById("description-image"),
text: document.getElementById("description-text")
@@ -197,17 +204,17 @@ var dialog = {
this._handlerInfo.preferredAction = Ci.nsIHandlerInfo.useSystemDefault;
}
this._handlerInfo.alwaysAskBeforeHandling = !checkbox.checked;
var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
getService(Ci.nsIHandlerService);
hs.store(this._handlerInfo);
- this._handlerInfo.launchWithURI(this._URI);
+ this._handlerInfo.launchWithURI(this._URI, this._windowCtxt);
return true;
},
/**
* Determines if the OK button should be disabled or not
*/
updateOKButton: function updateOKButton()
--- a/toolkit/mozapps/handling/src/nsContentDispatchChooser.js
+++ b/toolkit/mozapps/handling/src/nsContentDispatchChooser.js
@@ -15,16 +15,17 @@
*
* 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)
+ * 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
* 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
@@ -94,17 +95,18 @@ nsContentDispatchChooser.prototype =
for each (let text in arr) {
let string = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
string.data = text;
params.appendElement(string, false);
}
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,
CONTENT_HANDLING_URL,
null,
"chrome,dialog=yes,resizable,centerscreen",
params);
},
--- a/uriloader/exthandler/mac/nsMIMEInfoMac.cpp
+++ b/uriloader/exthandler/mac/nsMIMEInfoMac.cpp
@@ -95,34 +95,35 @@ nsMIMEInfoMac::LaunchWithFile(nsIFile *a
return NS_ERROR_FAILURE;
}
}
nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(aFile);
return app->LaunchWithDoc(localFile, PR_FALSE);
}
NS_IMETHODIMP
-nsMIMEInfoMac::LaunchWithURI(nsIURI* aURI)
+nsMIMEInfoMac::LaunchWithURI(nsIURI* aURI,
+ nsIInterfaceRequestor* aWindowContext)
{
nsCOMPtr<nsIFile> application;
nsresult rv;
// for now, this is only being called with protocol handlers; that
// will change once we get to more general registerContentHandler
// support
NS_ASSERTION(mClass == eProtocolInfo,
"nsMIMEInfoBase should be a protocol handler");
if (mPreferredAction == useHelperApp) {
// check for and launch with web handler app
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
nsCOMPtr<nsILocalHandlerApp> localHandlerApp =
do_QueryInterface(mPreferredApplication, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = localHandlerApp->GetExecutable(getter_AddRefs(application));
--- a/uriloader/exthandler/mac/nsMIMEInfoMac.h
+++ b/uriloader/exthandler/mac/nsMIMEInfoMac.h
@@ -41,17 +41,18 @@
class nsMIMEInfoMac : public nsMIMEInfoImpl {
public:
nsMIMEInfoMac(const char* aMIMEType = "") : nsMIMEInfoImpl(aMIMEType) {}
nsMIMEInfoMac(const nsACString& aMIMEType) : nsMIMEInfoImpl(aMIMEType) {}
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:
virtual NS_HIDDEN_(nsresult) LoadUriInternal(nsIURI *aURI);
#ifdef DEBUG
virtual NS_HIDDEN_(nsresult) LaunchDefaultWithFile(nsIFile* aFile) {
NS_NOTREACHED("do not call this method, use LaunchWithFile");
return NS_ERROR_UNEXPECTED;
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -119,17 +119,16 @@
#include "nsIGlobalHistory2.h" // to mark downloads as visited
#include "nsIDOMWindow.h"
#include "nsIDOMWindowInternal.h"
#include "nsIDocShell.h"
#include "nsCRT.h"
-#include "nsMIMEInfoImpl.h"
#include "nsLocalHandlerApp.h"
#ifdef PR_LOGGING
PRLogModuleInfo* nsExternalHelperAppService::mLog = nsnull;
#endif
// Using level 3 here because the OSHelperAppServices use a log level
// of PR_LOG_DEBUG (4), and we want less detailed output here
@@ -1334,17 +1333,17 @@ nsExternalHelperAppService::LoadURI(nsIU
handler->GetAlwaysAskBeforeHandling(&alwaysAsk);
// if we are not supposed to warn, we are not supposed to always ask, and
// the preferred action is to use a helper app or the system default, we just
// launch the URI.
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);
NS_ENSURE_SUCCESS(rv, rv);
return chooser->Ask(handler, aWindowContext, uri,
nsIContentDispatchChooser::REASON_CANNOT_HANDLE);
}
@@ -1402,20 +1401,16 @@ nsExternalHelperAppService::GetProtocolH
nsIHandlerInfo **aHandlerInfo)
{
// XXX Now that we've exposed this to the UI (bug 391150), is there anything
// we need to do to make it compatible with 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?)
- // 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)) {
// Either it knows nothing, or we ran out of memory
return NS_ERROR_FAILURE;
}
nsresult rv = FillProtoInfoForSchemeFromDS(aScheme, *aHandlerInfo);
--- a/uriloader/exthandler/nsExternalProtocolHandler.cpp
+++ b/uriloader/exthandler/nsExternalProtocolHandler.cpp
@@ -48,34 +48,29 @@
#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 nsProtocolRedirect;
-
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICHANNEL
NS_DECL_NSIREQUEST
nsExtProtocolChannel();
virtual ~nsExtProtocolChannel();
@@ -84,36 +79,32 @@ public:
private:
nsresult OpenURL();
void Finish(nsresult aResult);
nsCOMPtr<nsIURI> mUrl;
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)
NS_IMPL_THREADSAFE_RELEASE(nsExtProtocolChannel)
NS_INTERFACE_MAP_BEGIN(nsExtProtocolChannel)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIChannel)
NS_INTERFACE_MAP_ENTRY(nsIChannel)
NS_INTERFACE_MAP_ENTRY(nsIRequest)
NS_INTERFACE_MAP_END_THREADSAFE
nsExtProtocolChannel::nsExtProtocolChannel() : mStatus(NS_OK),
- mIsPending(PR_FALSE),
mWasOpened(PR_FALSE)
{
}
nsExtProtocolChannel::~nsExtProtocolChannel()
{}
NS_IMETHODIMP nsExtProtocolChannel::GetLoadGroup(nsILoadGroup * *aLoadGroup)
@@ -183,243 +174,50 @@ nsresult nsExtProtocolChannel::OpenURL()
#ifdef DEBUG
nsCAutoString urlScheme;
mUrl->GetScheme(urlScheme);
PRBool haveHandler = PR_FALSE;
extProtService->ExternalProtocolHandlerExists(urlScheme.get(), &haveHandler);
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)
{
*aLoadFlags = mLoadFlags;
return NS_OK;
}
@@ -480,17 +278,17 @@ NS_IMETHODIMP nsExtProtocolChannel::SetO
NS_IMETHODIMP nsExtProtocolChannel::GetName(nsACString &result)
{
return mUrl->GetSpec(result);
}
NS_IMETHODIMP nsExtProtocolChannel::IsPending(PRBool *result)
{
- *result = mIsPending;
+ *result = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP nsExtProtocolChannel::GetStatus(nsresult *status)
{
*status = mStatus;
return NS_OK;
}
--- a/uriloader/exthandler/nsIExternalProtocolService.idl
+++ b/uriloader/exthandler/nsIExternalProtocolService.idl
@@ -18,16 +18,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>
* 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"),
* 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
@@ -100,18 +101,30 @@ interface nsIExternalProtocolService : n
* @deprecated Use LoadURI instead (See Bug 389565 for removal)
*/
void loadUrl (in nsIURI aURL);
/**
* 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);
/**
* Gets a human-readable description for the application responsible for
* handling a specific protocol.
*
--- a/uriloader/exthandler/nsMIMEInfoImpl.cpp
+++ b/uriloader/exthandler/nsMIMEInfoImpl.cpp
@@ -38,16 +38,20 @@
#include "nsMIMEInfoImpl.h"
#include "nsXPIDLString.h"
#include "nsReadableUtils.h"
#include "nsStringEnumerator.h"
#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)
NS_IMPL_THREADSAFE_RELEASE(nsMIMEInfoBase)
NS_INTERFACE_MAP_BEGIN(nsMIMEInfoBase)
NS_INTERFACE_MAP_ENTRY(nsIHandlerInfo)
// This is only an nsIMIMEInfo if it's a MIME handler.
@@ -375,17 +379,18 @@ nsMIMEInfoBase::LaunchWithFile(nsIFile*
aFile->GetNativePath(path);
return LaunchWithIProcess(executable, path);
}
return NS_ERROR_INVALID_ARG;
}
NS_IMETHODIMP
-nsMIMEInfoBase::LaunchWithURI(nsIURI* aURI)
+nsMIMEInfoBase::LaunchWithURI(nsIURI* aURI,
+ nsIInterfaceRequestor* aWindowContext)
{
nsresult rv;
// for now, this is only being called with protocol handlers; that
// will change once we get to more general registerContentHandler
// support
NS_ASSERTION(mClass == eProtocolInfo,
"nsMIMEInfoBase should be a protocol handler");
@@ -397,17 +402,17 @@ nsMIMEInfoBase::LaunchWithURI(nsIURI* aU
if (mPreferredAction == useHelperApp) {
if (!mPreferredApplication)
return NS_ERROR_FILE_NOT_FOUND;
// check for and possibly launch with web application
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
nsCOMPtr<nsILocalHandlerApp> localHandler =
do_QueryInterface(mPreferredApplication, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIFile> executable;
@@ -451,20 +456,76 @@ nsMIMEInfoBase::LaunchWithIProcess(nsIFi
const char *string = aArg.get();
PRUint32 pid;
return process->Run(PR_FALSE, &string, 1, &pid);
}
/* 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
NS_IMETHODIMP
nsMIMEInfoImpl::GetDefaultDescription(nsAString& aDefaultDescription)
{
if (mDefaultAppDescription.IsEmpty() && mDefaultApplication) {
// Don't want to cache this, just in case someone resets the app
--- a/uriloader/exthandler/nsMIMEInfoImpl.h
+++ b/uriloader/exthandler/nsMIMEInfoImpl.h
@@ -84,17 +84,18 @@ class nsMIMEInfoBase : public nsIMIMEInf
NS_IMETHOD GetMacCreator(PRUint32 *aMacCreator);
NS_IMETHOD SetMacCreator(PRUint32 aMacCreator);
NS_IMETHOD Equals(nsIMIMEInfo *aMIMEInfo, PRBool *_retval);
NS_IMETHOD GetPreferredApplicationHandler(nsIHandlerApp * *aPreferredAppHandler);
NS_IMETHOD SetPreferredApplicationHandler(nsIHandlerApp * aPreferredAppHandler);
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);
NS_IMETHOD SetAlwaysAskBeforeHandling(PRBool aAlwaysAskBeforeHandling);
enum HandlerClass {
eMIMEInfo,
eProtocolInfo
@@ -153,19 +154,29 @@ class nsMIMEInfoBase : public nsIMIMEInf
*/
static NS_HIDDEN_(nsresult) LaunchWithIProcess(nsIFile* aApp,
const nsCString &aArg);
/**
* 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
*
* @param aURI the file: URI in question
* @param aFile the associated nsILocalFile (out param)
*/
static NS_HIDDEN_(nsresult) GetLocalFileFromURI(nsIURI *aURI,
--- a/uriloader/exthandler/os2/nsMIMEInfoOS2.cpp
+++ b/uriloader/exthandler/os2/nsMIMEInfoOS2.cpp
@@ -54,17 +54,18 @@ static const PRUnichar table[] =
'u','v','w','x','y','z','0','1','2','3',
'4','5','6','7','8','9'};
nsMIMEInfoOS2::~nsMIMEInfoOS2()
{
}
-NS_IMETHODIMP nsMIMEInfoOS2::LaunchWithURI(nsIURI* aURI)
+NS_IMETHODIMP nsMIMEInfoOS2::LaunchWithURI(nsIURI* aURI,
+ nsIInterfaceRequestor* aWindowContext)
{
nsresult rv = NS_OK;
nsCOMPtr<nsILocalFile> docToLoad;
rv = GetLocalFileFromURI(aURI, getter_AddRefs(docToLoad));
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString path;
--- a/uriloader/exthandler/os2/nsMIMEInfoOS2.h
+++ b/uriloader/exthandler/os2/nsMIMEInfoOS2.h
@@ -59,17 +59,18 @@ class nsMIMEInfoOS2 : public nsMIMEInfoI
{
public:
nsMIMEInfoOS2(const char* aType = "") : nsMIMEInfoImpl(aType) {}
nsMIMEInfoOS2(const nsACString& aMIMEType) : nsMIMEInfoImpl(aMIMEType) {}
nsMIMEInfoOS2(const nsACString& aType, HandlerClass aClass) :
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
virtual NS_HIDDEN_(nsresult) LaunchDefaultWithFile(nsIFile* aFile) {
NS_NOTREACHED("Do not call this, use LaunchWithFile");
return NS_ERROR_UNEXPECTED;
}
#endif