mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +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.
|
||||
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.
|
||||
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.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
|
||||
// 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
|
||||
|
@ -448,6 +448,10 @@ pref("network.protocol-handler.external.disk", false);
|
||||
pref("network.protocol-handler.external.disks", 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
|
||||
// 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
|
||||
|
@ -44,6 +44,12 @@
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsCOMPtr.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 "nsNetCID.h"
|
||||
#include "netCore.h"
|
||||
@ -53,6 +59,8 @@
|
||||
#include "nsIExternalProtocolService.h"
|
||||
|
||||
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_NSICHANNEL
|
||||
NS_DECL_NSIREQUEST
|
||||
|
||||
|
||||
nsExtProtocolChannel();
|
||||
virtual ~nsExtProtocolChannel();
|
||||
|
||||
nsresult SetURI(nsIURI*);
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIURI> mUrl;
|
||||
nsCOMPtr<nsIURI> mOriginalURI;
|
||||
nsresult mStatus;
|
||||
nsresult OpenURL();
|
||||
|
||||
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)
|
||||
@ -105,18 +116,21 @@ NS_IMETHODIMP nsExtProtocolChannel::GetLoadGroup(nsILoadGroup * *aLoadGroup)
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::SetLoadGroup(nsILoadGroup * aLoadGroup)
|
||||
{
|
||||
return NS_OK;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
|
||||
{
|
||||
*aNotificationCallbacks = nsnull;
|
||||
NS_ENSURE_ARG_POINTER(aNotificationCallbacks);
|
||||
*aNotificationCallbacks = mCallbacks;
|
||||
NS_IF_ADDREF(*aNotificationCallbacks);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
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
|
||||
@ -152,6 +166,94 @@ nsresult nsExtProtocolChannel::SetURI(nsIURI* aURI)
|
||||
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()
|
||||
{
|
||||
nsCOMPtr<nsIExternalProtocolService> extProtService (do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
|
||||
@ -165,9 +267,47 @@ nsresult nsExtProtocolChannel::OpenURL()
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
@ -177,26 +317,60 @@ NS_IMETHODIMP nsExtProtocolChannel::Open(nsIInputStream **_retval)
|
||||
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)
|
||||
{
|
||||
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.
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
|
||||
{
|
||||
*aLoadFlags = 0;
|
||||
return NS_OK;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
|
||||
{
|
||||
return NS_OK;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::GetContentType(nsACString &aContentType)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExtProtocolChannel::SetContentType(const nsACString &aContentType)
|
||||
@ -285,8 +459,8 @@ NS_IMETHODIMP nsExtProtocolChannel::Resume()
|
||||
|
||||
nsExternalProtocolHandler::nsExternalProtocolHandler()
|
||||
{
|
||||
m_schemeName = "default";
|
||||
m_extProtService = do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
|
||||
m_schemeName = "default";
|
||||
m_extProtService = do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
|
||||
}
|
||||
|
||||
|
||||
@ -305,13 +479,13 @@ NS_INTERFACE_MAP_END_THREADSAFE
|
||||
|
||||
NS_IMETHODIMP nsExternalProtocolHandler::GetScheme(nsACString &aScheme)
|
||||
{
|
||||
aScheme = m_schemeName;
|
||||
return NS_OK;
|
||||
aScheme = m_schemeName;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExternalProtocolHandler::GetDefaultPort(PRInt32 *aDefaultPort)
|
||||
{
|
||||
*aDefaultPort = 0;
|
||||
*aDefaultPort = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user