mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
bug 173010 prompt before launching external protocol handler,r=mscott,sr=darin/jst
This commit is contained in:
parent
216e446106
commit
3ea4400949
@ -51,3 +51,7 @@ isprinting=The document cannot change while Printing or in Print Preview.
|
|||||||
deniedPortAccess=Access to the port number given has been disabled for security reasons.
|
deniedPortAccess=Access to the port number given has been disabled for security reasons.
|
||||||
proxyResolveFailure=The proxy server you have configured could not be found. Please check your proxy settings and try again.
|
proxyResolveFailure=The proxy server you have configured could not be found. Please check your proxy settings and try again.
|
||||||
proxyConnectFailure=The connection was refused when attempting to contact the proxy server you have configured. Please check your proxy settings and try again.
|
proxyConnectFailure=The connection was refused when attempting to contact the proxy server you have configured. Please check your proxy settings and try again.
|
||||||
|
externalProtocolTitle=External Protocol Request
|
||||||
|
externalProtocolPrompt=An external application must be launched to handle %1$S: links. Requested link:\n\n\n%2$S\n\n\nIf you were not expecting this request it may be an attempt to exploit a weakness in that other program. Cancel this request unless you are sure it is not malicious.\n
|
||||||
|
externalProtocolChkMsg=Remember my choice for all links of this type.
|
||||||
|
externalProtocolLaunchBtn=Launch application
|
||||||
|
@ -109,6 +109,10 @@ pref("network.protocol-handler.external.vnd.ms.radio", false);
|
|||||||
pref("network.protocol-handler.external.help", false);
|
pref("network.protocol-handler.external.help", false);
|
||||||
pref("network.protocol-handler.external.disk", false);
|
pref("network.protocol-handler.external.disk", false);
|
||||||
|
|
||||||
|
// Default action for unlisted external protocol handlers
|
||||||
|
// 0 == never load, 1 == always load, 2 == ask the user
|
||||||
|
pref("network.protocol-handler.external-default", 2);
|
||||||
|
|
||||||
// An exposed protocol handler is one that can be used in all contexts. A
|
// An exposed protocol handler is one that can be used in all contexts. A
|
||||||
// non-exposed protocol handler is one that can only be used internally by the
|
// non-exposed protocol handler is one that can only be used internally by the
|
||||||
// application. For example, a non-exposed protocol would not be loaded by the
|
// application. For example, a non-exposed protocol would not be loaded by the
|
||||||
|
@ -448,6 +448,10 @@ pref("network.protocol-handler.external.disk", false);
|
|||||||
pref("network.protocol-handler.external.disks", false);
|
pref("network.protocol-handler.external.disks", false);
|
||||||
pref("network.protocol-handler.external.afp", false);
|
pref("network.protocol-handler.external.afp", false);
|
||||||
|
|
||||||
|
// Default action for unlisted external protocol handlers
|
||||||
|
// 0 == never load, 1 == always load, 2 == ask the user
|
||||||
|
pref("network.protocol-handler.external-default", 2);
|
||||||
|
|
||||||
// An exposed protocol handler is one that can be used in all contexts. A
|
// An exposed protocol handler is one that can be used in all contexts. A
|
||||||
// non-exposed protocol handler is one that can only be used internally by the
|
// non-exposed protocol handler is one that can only be used internally by the
|
||||||
// application. For example, a non-exposed protocol would not be loaded by the
|
// application. For example, a non-exposed protocol would not be loaded by the
|
||||||
|
@ -44,6 +44,12 @@
|
|||||||
#include "nsReadableUtils.h"
|
#include "nsReadableUtils.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsIServiceManager.h"
|
#include "nsIServiceManager.h"
|
||||||
|
#include "nsIServiceManagerUtils.h"
|
||||||
|
#include "nsIInterfaceRequestor.h"
|
||||||
|
#include "nsIStringBundle.h"
|
||||||
|
#include "nsIPrefService.h"
|
||||||
|
#include "nsIPrompt.h"
|
||||||
|
#include "nsEventQueueUtils.h"
|
||||||
#include "nsIChannel.h"
|
#include "nsIChannel.h"
|
||||||
#include "nsNetCID.h"
|
#include "nsNetCID.h"
|
||||||
#include "netCore.h"
|
#include "netCore.h"
|
||||||
@ -53,6 +59,8 @@
|
|||||||
#include "nsIExternalProtocolService.h"
|
#include "nsIExternalProtocolService.h"
|
||||||
|
|
||||||
static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
|
static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
|
||||||
|
static const char kExternalProtocolPrefPrefix[] = "network.protocol-handler.external.";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
@ -67,18 +75,21 @@ public:
|
|||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
NS_DECL_NSICHANNEL
|
NS_DECL_NSICHANNEL
|
||||||
NS_DECL_NSIREQUEST
|
NS_DECL_NSIREQUEST
|
||||||
|
|
||||||
nsExtProtocolChannel();
|
nsExtProtocolChannel();
|
||||||
virtual ~nsExtProtocolChannel();
|
virtual ~nsExtProtocolChannel();
|
||||||
|
|
||||||
nsresult SetURI(nsIURI*);
|
nsresult SetURI(nsIURI*);
|
||||||
|
|
||||||
protected:
|
nsresult OpenURL();
|
||||||
nsCOMPtr<nsIURI> mUrl;
|
|
||||||
nsCOMPtr<nsIURI> mOriginalURI;
|
|
||||||
nsresult mStatus;
|
|
||||||
|
|
||||||
nsresult OpenURL();
|
private:
|
||||||
|
nsCOMPtr<nsIURI> mUrl;
|
||||||
|
nsCOMPtr<nsIURI> mOriginalURI;
|
||||||
|
nsresult mStatus;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
|
||||||
|
PRBool PromptForScheme(nsIURI *aURI, nsACString& aScheme);
|
||||||
};
|
};
|
||||||
|
|
||||||
NS_IMPL_THREADSAFE_ADDREF(nsExtProtocolChannel)
|
NS_IMPL_THREADSAFE_ADDREF(nsExtProtocolChannel)
|
||||||
@ -105,18 +116,21 @@ NS_IMETHODIMP nsExtProtocolChannel::GetLoadGroup(nsILoadGroup * *aLoadGroup)
|
|||||||
|
|
||||||
NS_IMETHODIMP nsExtProtocolChannel::SetLoadGroup(nsILoadGroup * aLoadGroup)
|
NS_IMETHODIMP nsExtProtocolChannel::SetLoadGroup(nsILoadGroup * aLoadGroup)
|
||||||
{
|
{
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsExtProtocolChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
|
NS_IMETHODIMP nsExtProtocolChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
|
||||||
{
|
{
|
||||||
*aNotificationCallbacks = nsnull;
|
NS_ENSURE_ARG_POINTER(aNotificationCallbacks);
|
||||||
|
*aNotificationCallbacks = mCallbacks;
|
||||||
|
NS_IF_ADDREF(*aNotificationCallbacks);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsExtProtocolChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
|
NS_IMETHODIMP nsExtProtocolChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
|
||||||
{
|
{
|
||||||
return NS_OK; // don't fail when trying to set this
|
mCallbacks = aNotificationCallbacks;
|
||||||
|
return NS_OK; // don't fail when trying to set this
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
@ -152,6 +166,94 @@ nsresult nsExtProtocolChannel::SetURI(nsIURI* aURI)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRBool nsExtProtocolChannel::PromptForScheme(nsIURI* aURI,
|
||||||
|
nsACString& aScheme)
|
||||||
|
{
|
||||||
|
// deny the load if we aren't able to ask but prefs say we should
|
||||||
|
nsresult rv;
|
||||||
|
if (!mCallbacks) {
|
||||||
|
NS_ERROR("Notification Callbacks not set!");
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPrompt> prompt;
|
||||||
|
mCallbacks->GetInterface(NS_GET_IID(nsIPrompt), getter_AddRefs(prompt));
|
||||||
|
if (!prompt) {
|
||||||
|
NS_ERROR("No prompt interface on channel");
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIStringBundleService> sbSvc(do_GetService(NS_STRINGBUNDLE_CONTRACTID));
|
||||||
|
if (!sbSvc) {
|
||||||
|
NS_ERROR("Couldn't load StringBundleService");
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIStringBundle> appstrings;
|
||||||
|
rv = sbSvc->CreateBundle("chrome://global/locale/appstrings.properties",
|
||||||
|
getter_AddRefs(appstrings));
|
||||||
|
if (NS_FAILED(rv) || !appstrings) {
|
||||||
|
NS_ERROR("Failed to create appstrings.properties bundle");
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCAutoString spec;
|
||||||
|
aURI->GetSpec(spec);
|
||||||
|
NS_ConvertUTF8toUTF16 uri(spec);
|
||||||
|
NS_ConvertUTF8toUTF16 scheme(aScheme);
|
||||||
|
|
||||||
|
nsXPIDLString title;
|
||||||
|
appstrings->GetStringFromName(NS_LITERAL_STRING("externalProtocolTitle").get(),
|
||||||
|
getter_Copies(title));
|
||||||
|
nsXPIDLString checkMsg;
|
||||||
|
appstrings->GetStringFromName(NS_LITERAL_STRING("externalProtocolChkMsg").get(),
|
||||||
|
getter_Copies(checkMsg));
|
||||||
|
nsXPIDLString launchBtn;
|
||||||
|
appstrings->GetStringFromName(NS_LITERAL_STRING("externalProtocolLaunchBtn").get(),
|
||||||
|
getter_Copies(launchBtn));
|
||||||
|
|
||||||
|
nsXPIDLString message;
|
||||||
|
const PRUnichar* msgArgs[] = { scheme.get(), uri.get() };
|
||||||
|
appstrings->FormatStringFromName(NS_LITERAL_STRING("externalProtocolPrompt").get(),
|
||||||
|
msgArgs,
|
||||||
|
NS_ARRAY_LENGTH(msgArgs),
|
||||||
|
getter_Copies(message));
|
||||||
|
|
||||||
|
if (scheme.IsEmpty() || uri.IsEmpty() || title.IsEmpty() ||
|
||||||
|
checkMsg.IsEmpty() || launchBtn.IsEmpty() || message.IsEmpty())
|
||||||
|
return PR_FALSE;
|
||||||
|
|
||||||
|
// all pieces assembled, now we can pose the dialog
|
||||||
|
PRBool allowLoad = PR_FALSE;
|
||||||
|
PRBool remember = PR_FALSE;
|
||||||
|
PRInt32 choice = 1; // assume "cancel" in case of failure
|
||||||
|
rv = prompt->ConfirmEx(title.get(), message.get(),
|
||||||
|
nsIPrompt::BUTTON_DELAY_ENABLE +
|
||||||
|
nsIPrompt::BUTTON_POS_1_DEFAULT +
|
||||||
|
(nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_0) +
|
||||||
|
(nsIPrompt::BUTTON_TITLE_CANCEL * nsIPrompt::BUTTON_POS_1),
|
||||||
|
launchBtn.get(), 0, 0, checkMsg.get(),
|
||||||
|
&remember, &choice);
|
||||||
|
if (NS_SUCCEEDED(rv))
|
||||||
|
{
|
||||||
|
if (choice == 0)
|
||||||
|
allowLoad = PR_TRUE;
|
||||||
|
|
||||||
|
if (remember)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
|
||||||
|
if (prefs)
|
||||||
|
{
|
||||||
|
nsCAutoString prefname(kExternalProtocolPrefPrefix);
|
||||||
|
prefname += aScheme;
|
||||||
|
prefs->SetBoolPref(prefname.get(), allowLoad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allowLoad;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult nsExtProtocolChannel::OpenURL()
|
nsresult nsExtProtocolChannel::OpenURL()
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIExternalProtocolService> extProtService (do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
|
nsCOMPtr<nsIExternalProtocolService> extProtService (do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
|
||||||
@ -165,9 +267,47 @@ nsresult nsExtProtocolChannel::OpenURL()
|
|||||||
extProtService->ExternalProtocolHandlerExists(urlScheme.get(), &haveHandler);
|
extProtService->ExternalProtocolHandlerExists(urlScheme.get(), &haveHandler);
|
||||||
NS_ASSERTION(haveHandler, "Why do we have a channel for this url if we don't support the protocol?");
|
NS_ASSERTION(haveHandler, "Why do we have a channel for this url if we don't support the protocol?");
|
||||||
#endif
|
#endif
|
||||||
return extProtService->LoadUrl(mUrl);
|
|
||||||
|
// Check that it's OK to hand this scheme off to the OS
|
||||||
|
|
||||||
|
PRBool allowLoad = PR_FALSE;
|
||||||
|
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
|
||||||
|
|
||||||
|
if (prefs)
|
||||||
|
{
|
||||||
|
// check whether it's explicitly approved or denied in prefs
|
||||||
|
nsCAutoString schemePref(kExternalProtocolPrefPrefix);
|
||||||
|
schemePref += urlScheme;
|
||||||
|
|
||||||
|
nsresult rv = prefs->GetBoolPref(schemePref.get(), &allowLoad);
|
||||||
|
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
{
|
||||||
|
// scheme not explicitly listed, what is the default action?
|
||||||
|
const PRInt32 kExternalProtocolNever = 0;
|
||||||
|
const PRInt32 kExternalProtocolAlways = 1;
|
||||||
|
const PRInt32 kExternalProtocolAsk = 2;
|
||||||
|
|
||||||
|
PRInt32 externalDefault = kExternalProtocolAsk;
|
||||||
|
prefs->GetIntPref("network.protocol-handler.external-default",
|
||||||
|
&externalDefault);
|
||||||
|
|
||||||
|
if (externalDefault == kExternalProtocolAlways)
|
||||||
|
{
|
||||||
|
// original behavior -- just do it
|
||||||
|
allowLoad = PR_TRUE;
|
||||||
|
}
|
||||||
|
else if (externalDefault == kExternalProtocolAsk)
|
||||||
|
{
|
||||||
|
allowLoad = PromptForScheme(mUrl, urlScheme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowLoad)
|
||||||
|
return extProtService->LoadUrl(mUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,26 +317,60 @@ NS_IMETHODIMP nsExtProtocolChannel::Open(nsIInputStream **_retval)
|
|||||||
return NS_ERROR_NO_CONTENT; // force caller to abort.
|
return NS_ERROR_NO_CONTENT; // force caller to abort.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *PR_CALLBACK handleExtProtoEvent(PLEvent *event)
|
||||||
|
{
|
||||||
|
nsExtProtocolChannel *channel =
|
||||||
|
NS_STATIC_CAST(nsExtProtocolChannel*, PL_GetEventOwner(event));
|
||||||
|
|
||||||
|
if (channel)
|
||||||
|
channel->OpenURL();
|
||||||
|
|
||||||
|
return nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PR_CALLBACK destroyExtProtoEvent(PLEvent *event)
|
||||||
|
{
|
||||||
|
nsExtProtocolChannel *channel =
|
||||||
|
NS_STATIC_CAST(nsExtProtocolChannel*, PL_GetEventOwner(event));
|
||||||
|
NS_IF_RELEASE(channel);
|
||||||
|
delete event;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsExtProtocolChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
|
NS_IMETHODIMP nsExtProtocolChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
|
||||||
{
|
{
|
||||||
OpenURL();
|
nsCOMPtr<nsIEventQueue> eventQ;
|
||||||
|
nsresult rv = NS_GetCurrentEventQ(getter_AddRefs(eventQ));
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
PLEvent *event = new PLEvent;
|
||||||
|
if (event)
|
||||||
|
{
|
||||||
|
NS_ADDREF_THIS();
|
||||||
|
PL_InitEvent(event, this, handleExtProtoEvent, destroyExtProtoEvent);
|
||||||
|
|
||||||
|
rv = eventQ->PostEvent(event);
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
PL_DestroyEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
return NS_ERROR_NO_CONTENT; // force caller to abort.
|
return NS_ERROR_NO_CONTENT; // force caller to abort.
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsExtProtocolChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
|
NS_IMETHODIMP nsExtProtocolChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
|
||||||
{
|
{
|
||||||
*aLoadFlags = 0;
|
*aLoadFlags = 0;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsExtProtocolChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
|
NS_IMETHODIMP nsExtProtocolChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
|
||||||
{
|
{
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsExtProtocolChannel::GetContentType(nsACString &aContentType)
|
NS_IMETHODIMP nsExtProtocolChannel::GetContentType(nsACString &aContentType)
|
||||||
{
|
{
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsExtProtocolChannel::SetContentType(const nsACString &aContentType)
|
NS_IMETHODIMP nsExtProtocolChannel::SetContentType(const nsACString &aContentType)
|
||||||
@ -285,8 +459,8 @@ NS_IMETHODIMP nsExtProtocolChannel::Resume()
|
|||||||
|
|
||||||
nsExternalProtocolHandler::nsExternalProtocolHandler()
|
nsExternalProtocolHandler::nsExternalProtocolHandler()
|
||||||
{
|
{
|
||||||
m_schemeName = "default";
|
m_schemeName = "default";
|
||||||
m_extProtService = do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
|
m_extProtService = do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -305,13 +479,13 @@ NS_INTERFACE_MAP_END_THREADSAFE
|
|||||||
|
|
||||||
NS_IMETHODIMP nsExternalProtocolHandler::GetScheme(nsACString &aScheme)
|
NS_IMETHODIMP nsExternalProtocolHandler::GetScheme(nsACString &aScheme)
|
||||||
{
|
{
|
||||||
aScheme = m_schemeName;
|
aScheme = m_schemeName;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsExternalProtocolHandler::GetDefaultPort(PRInt32 *aDefaultPort)
|
NS_IMETHODIMP nsExternalProtocolHandler::GetDefaultPort(PRInt32 *aDefaultPort)
|
||||||
{
|
{
|
||||||
*aDefaultPort = 0;
|
*aDefaultPort = 0;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user