mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-26 12:20:56 +00:00
Bug 1496380 - stop recursion via the external protocol handler if Firefox is either the default OS handler or a configured external handler, r=mossop
This is an initial implementation of this idea that works on mac. I've added a Windows implementation in another commit in this stack. I'll look at a Linux one in a follow-up bug. I do not think we need them in the child process implementation or on Android. Effectively, this makes nsIHandlerInfo::LaunchWithURI() fall back to asking if the handler info points to the OS default and that's us, or if it points to a helper app and that's us. The latter is fairly easy to check, but the former, more common case, is actually annoying - there don't seem to be APIs on the external helper app service or the handler service that provide any information about the app that's currently the default. So despite my belief that these interfaces have too many methods that all do very similar things, and what we need is fewer interfaces with fewer methods, I added another one... For this mac implementation, I'm comparing bundle URLs and added newer API usage for 10.10 and later to avoid deprecation warnings. I've not changed the mac shell service as it uses bundle identifiers to check if we're the default. Another way of fixing these issues would be to complain about things when we receive these URIs from external parties and our own config says that we will just hand them to someone else. I decided not to do so because we end up with at least one of the following problems: - if we implement in BrowserContentHandler, that won't help for PWAs/Thunderbird - if we try to implement in the external protocol handler, we'd need to start passing load flag information through to lots of checks. - it wouldn't stop the recursion until we've already done one round of it for links that are in webpages, which seems suboptimal (ie, if you clicked a mailto: link on a webpage it'd go to the OS with that mailto link and only realize something's awry when we've gone back through the OS to us, rather than straightaway). If we wanted to, we could add a fix like that in belt-and-suspenders fashion. Differential Revision: https://phabricator.services.mozilla.com/D48742 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
eb71df2dc9
commit
c84bf2a64d
@ -39,6 +39,18 @@ nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char* aScheme,
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme,
|
||||
nsAString& _retval) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(
|
||||
const nsACString& aScheme, bool* _retval) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsresult nsOSHelperAppService::GetProtocolHandlerInfoFromOS(
|
||||
const nsACString& aScheme, bool* found, nsIHandlerInfo** info) {
|
||||
// We don't want to get protocol handlers from the OS in GV; the app
|
||||
|
@ -24,6 +24,10 @@ class nsOSHelperAppService : public nsExternalHelperAppService {
|
||||
NS_IMETHOD GetProtocolHandlerInfoFromOS(const nsACString& aScheme,
|
||||
bool* found,
|
||||
nsIHandlerInfo** _retval) override;
|
||||
NS_IMETHOD GetApplicationDescription(const nsACString& aScheme,
|
||||
nsAString& _retval) override;
|
||||
NS_IMETHOD IsCurrentAppOSDefaultForProtocol(const nsACString& aScheme,
|
||||
bool* _retval) override;
|
||||
|
||||
static nsIHandlerApp* CreateAndroidHandlerApp(
|
||||
const nsAString& aName, const nsAString& aDescription,
|
||||
|
@ -26,6 +26,9 @@ class nsOSHelperAppService : public nsExternalHelperAppService {
|
||||
NS_IMETHOD GetApplicationDescription(const nsACString& aScheme,
|
||||
nsAString& _retval) override;
|
||||
|
||||
NS_IMETHOD IsCurrentAppOSDefaultForProtocol(const nsACString& aScheme,
|
||||
bool* _retval) override;
|
||||
|
||||
nsresult GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||
const nsACString& aFileExt, bool* aFound,
|
||||
nsIMIMEInfo** aMIMEInfo) override;
|
||||
|
@ -31,6 +31,49 @@
|
||||
#define HELPERAPPLAUNCHER_BUNDLE_URL "chrome://global/locale/helperAppLauncher.properties"
|
||||
#define BRAND_BUNDLE_URL "chrome://branding/locale/brand.properties"
|
||||
|
||||
nsresult GetDefaultBundleURL(const nsACString& aScheme, CFURLRef* aBundleURL) {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
CFStringRef schemeCFString = ::CFStringCreateWithBytes(
|
||||
kCFAllocatorDefault, (const UInt8*)PromiseFlatCString(aScheme).get(), aScheme.Length(),
|
||||
kCFStringEncodingUTF8, false);
|
||||
|
||||
if (schemeCFString) {
|
||||
CFStringRef lookupCFString =
|
||||
::CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:"), schemeCFString);
|
||||
|
||||
if (lookupCFString) {
|
||||
CFURLRef lookupCFURL = ::CFURLCreateWithString(NULL, lookupCFString, NULL);
|
||||
|
||||
if (lookupCFURL) {
|
||||
if (@available(macOS 10.10, *)) {
|
||||
*aBundleURL = ::LSCopyDefaultApplicationURLForURL(lookupCFURL, kLSRolesAll, NULL);
|
||||
if (*aBundleURL) {
|
||||
rv = NS_OK;
|
||||
}
|
||||
} else {
|
||||
OSStatus theErr = ::LSGetApplicationForURL(lookupCFURL, kLSRolesAll, NULL, aBundleURL);
|
||||
if (theErr == noErr && *aBundleURL) {
|
||||
rv = NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
::CFRelease(lookupCFURL);
|
||||
}
|
||||
|
||||
::CFRelease(lookupCFString);
|
||||
}
|
||||
|
||||
::CFRelease(schemeCFString);
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
using mozilla::LogLevel;
|
||||
|
||||
/* This is an undocumented interface (in the Foundation framework) that has
|
||||
@ -91,52 +134,57 @@ NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString&
|
||||
|
||||
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
CFStringRef schemeCFString = ::CFStringCreateWithBytes(
|
||||
kCFAllocatorDefault, (const UInt8*)PromiseFlatCString(aScheme).get(), aScheme.Length(),
|
||||
kCFStringEncodingUTF8, false);
|
||||
CFURLRef handlerBundleURL;
|
||||
rv = GetDefaultBundleURL(aScheme, &handlerBundleURL);
|
||||
|
||||
if (schemeCFString) {
|
||||
CFStringRef lookupCFString =
|
||||
::CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:"), schemeCFString);
|
||||
|
||||
if (lookupCFString) {
|
||||
CFURLRef lookupCFURL = ::CFURLCreateWithString(NULL, lookupCFString, NULL);
|
||||
|
||||
if (lookupCFURL) {
|
||||
CFURLRef appCFURL = NULL;
|
||||
OSStatus theErr = ::LSGetApplicationForURL(lookupCFURL, kLSRolesAll, NULL, &appCFURL);
|
||||
|
||||
if (theErr == noErr) {
|
||||
CFBundleRef handlerBundle = ::CFBundleCreate(NULL, appCFURL);
|
||||
|
||||
if (handlerBundle) {
|
||||
// Get the human-readable name of the default handler bundle
|
||||
CFStringRef bundleName = (CFStringRef)::CFBundleGetValueForInfoDictionaryKey(
|
||||
handlerBundle, kCFBundleNameKey);
|
||||
|
||||
if (bundleName) {
|
||||
AutoTArray<UniChar, 255> buffer;
|
||||
CFIndex bundleNameLength = ::CFStringGetLength(bundleName);
|
||||
buffer.SetLength(bundleNameLength);
|
||||
::CFStringGetCharacters(bundleName, CFRangeMake(0, bundleNameLength),
|
||||
buffer.Elements());
|
||||
_retval.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), bundleNameLength);
|
||||
rv = NS_OK;
|
||||
}
|
||||
|
||||
::CFRelease(handlerBundle);
|
||||
}
|
||||
|
||||
::CFRelease(appCFURL);
|
||||
}
|
||||
|
||||
::CFRelease(lookupCFURL);
|
||||
}
|
||||
|
||||
::CFRelease(lookupCFString);
|
||||
if (NS_SUCCEEDED(rv) && handlerBundleURL) {
|
||||
CFBundleRef handlerBundle = CFBundleCreate(NULL, handlerBundleURL);
|
||||
if (!handlerBundle) {
|
||||
::CFRelease(handlerBundleURL);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
::CFRelease(schemeCFString);
|
||||
// Get the human-readable name of the bundle
|
||||
CFStringRef bundleName =
|
||||
(CFStringRef)::CFBundleGetValueForInfoDictionaryKey(handlerBundle, kCFBundleNameKey);
|
||||
|
||||
if (bundleName) {
|
||||
AutoTArray<UniChar, 255> buffer;
|
||||
CFIndex bundleNameLength = ::CFStringGetLength(bundleName);
|
||||
buffer.SetLength(bundleNameLength);
|
||||
::CFStringGetCharacters(bundleName, CFRangeMake(0, bundleNameLength), buffer.Elements());
|
||||
_retval.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), bundleNameLength);
|
||||
rv = NS_OK;
|
||||
}
|
||||
::CFRelease(handlerBundle);
|
||||
::CFRelease(handlerBundleURL);
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(const nsACString& aScheme,
|
||||
bool* _retval) {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
CFURLRef handlerBundleURL;
|
||||
rv = GetDefaultBundleURL(aScheme, &handlerBundleURL);
|
||||
if (NS_SUCCEEDED(rv) && handlerBundleURL) {
|
||||
// Ensure we don't accidentally return success if we can't get an app bundle.
|
||||
rv = NS_ERROR_NOT_AVAILABLE;
|
||||
CFBundleRef appBundle = ::CFBundleGetMainBundle();
|
||||
if (appBundle) {
|
||||
CFURLRef selfURL = ::CFBundleCopyBundleURL(appBundle);
|
||||
*_retval = ::CFEqual(selfURL, handlerBundleURL);
|
||||
rv = NS_OK;
|
||||
::CFRelease(appBundle);
|
||||
::CFRelease(selfURL);
|
||||
}
|
||||
::CFRelease(handlerBundleURL);
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -1008,13 +1008,6 @@ nsExternalHelperAppService::LoadURI(nsIURI* aURI,
|
||||
nsIContentDispatchChooser::REASON_CANNOT_HANDLE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExternalHelperAppService::GetApplicationDescription(
|
||||
const nsACString& aScheme, nsAString& _retval) {
|
||||
// this method should only be implemented by each OS specific implementation
|
||||
// of this service.
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Methods related to deleting temporary files on exit
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1101,13 +1094,6 @@ nsExternalHelperAppService::GetProtocolHandlerInfo(
|
||||
return SetProtocolHandlerDefaults(*aHandlerInfo, exists);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsExternalHelperAppService::GetProtocolHandlerInfoFromOS(
|
||||
const nsACString& aScheme, bool* found, nsIHandlerInfo** aHandlerInfo) {
|
||||
// intended to be implemented by the subclass
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsExternalHelperAppService::SetProtocolHandlerDefaults(
|
||||
nsIHandlerInfo* aHandlerInfo, bool aOSHandlerExists) {
|
||||
|
@ -44,6 +44,8 @@ class MaybeCloseWindowHelper;
|
||||
/**
|
||||
* The helper app service. Responsible for handling content that Mozilla
|
||||
* itself can not handle
|
||||
* Note that this is an abstract class - we depend on appropriate subclassing
|
||||
* on a per-OS basis to implement some methods.
|
||||
*/
|
||||
class nsExternalHelperAppService : public nsIExternalHelperAppService,
|
||||
public nsPIExternalAppLauncher,
|
||||
@ -55,7 +57,6 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService,
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIEXTERNALHELPERAPPSERVICE
|
||||
NS_DECL_NSPIEXTERNALAPPLAUNCHER
|
||||
NS_DECL_NSIEXTERNALPROTOCOLSERVICE
|
||||
NS_DECL_NSIMIMESERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
@ -67,6 +68,21 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService,
|
||||
*/
|
||||
MOZ_MUST_USE nsresult Init();
|
||||
|
||||
/**
|
||||
* nsIExternalProtocolService methods that we provide in this class. Other
|
||||
* methods should be implemented by per-OS subclasses.
|
||||
*/
|
||||
NS_IMETHOD ExternalProtocolHandlerExists(const char* aProtocolScheme,
|
||||
bool* aHandlerExists) override;
|
||||
NS_IMETHOD IsExposedProtocol(const char* aProtocolScheme,
|
||||
bool* aResult) override;
|
||||
NS_IMETHOD GetProtocolHandlerInfo(const nsACString& aScheme,
|
||||
nsIHandlerInfo** aHandlerInfo) override;
|
||||
NS_IMETHOD LoadURI(nsIURI* aURI,
|
||||
nsIInterfaceRequestor* aWindowContext) override;
|
||||
NS_IMETHOD SetProtocolHandlerDefaults(nsIHandlerInfo* aHandlerInfo,
|
||||
bool aOSHandlerExists) override;
|
||||
|
||||
/**
|
||||
* Given a string identifying an application, create an nsIFile representing
|
||||
* it. This function should look in $PATH for the application.
|
||||
|
@ -123,4 +123,11 @@ interface nsIExternalProtocolService : nsISupports
|
||||
* possible to get a description for it.
|
||||
*/
|
||||
AString getApplicationDescription(in AUTF8String aScheme);
|
||||
|
||||
/**
|
||||
* Check if this app is registered as the OS default for a given scheme.
|
||||
*
|
||||
* @param aScheme The scheme to look up. For example, "mms".
|
||||
*/
|
||||
bool isCurrentAppOSDefaultForProtocol(in AUTF8String aScheme);
|
||||
};
|
||||
|
@ -13,6 +13,42 @@
|
||||
#include "nsEscape.h"
|
||||
#include "nsIURILoader.h"
|
||||
#include "nsCURILoader.h"
|
||||
#include "nsCExternalHandlerService.h"
|
||||
#include "nsIExternalProtocolService.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
static bool sInitializedOurData = false;
|
||||
StaticRefPtr<nsIFile> sOurAppFile;
|
||||
|
||||
static already_AddRefed<nsIFile> GetCanonicalExecutable(nsIFile* aFile) {
|
||||
nsCOMPtr<nsIFile> binary = aFile;
|
||||
#ifdef XP_MACOSX
|
||||
nsAutoString leafName;
|
||||
if (binary) {
|
||||
binary->GetLeafName(leafName);
|
||||
}
|
||||
while (binary && !StringEndsWith(leafName, NS_LITERAL_STRING(".app"))) {
|
||||
nsCOMPtr<nsIFile> parent;
|
||||
binary->GetParent(getter_AddRefs(parent));
|
||||
binary = parent;
|
||||
if (binary) {
|
||||
binary->GetLeafName(leafName);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return binary.forget();
|
||||
}
|
||||
|
||||
static void EnsureAppDetailsAvailable() {
|
||||
if (sInitializedOurData) {
|
||||
return;
|
||||
}
|
||||
sInitializedOurData = true;
|
||||
nsCOMPtr<nsIFile> binary;
|
||||
XRE_GetBinaryPath(getter_AddRefs(binary));
|
||||
sOurAppFile = GetCanonicalExecutable(binary);
|
||||
ClearOnShutdown(&sOurAppFile);
|
||||
}
|
||||
|
||||
// nsISupports methods
|
||||
NS_IMPL_ADDREF(nsMIMEInfoBase)
|
||||
@ -287,12 +323,45 @@ nsMIMEInfoBase::LaunchWithURI(nsIURI* aURI,
|
||||
"nsMIMEInfoBase should be a protocol handler");
|
||||
|
||||
if (mPreferredAction == useSystemDefault) {
|
||||
// First, ensure we're not accidentally going to call ourselves.
|
||||
// That'd lead to an infinite loop (see bug 215554).
|
||||
nsCOMPtr<nsIExternalProtocolService> extProtService =
|
||||
do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
|
||||
if (!extProtService) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsAutoCString scheme;
|
||||
aURI->GetScheme(scheme);
|
||||
bool isDefault = false;
|
||||
nsresult rv =
|
||||
extProtService->IsCurrentAppOSDefaultForProtocol(scheme, &isDefault);
|
||||
if (NS_SUCCEEDED(rv) && isDefault) {
|
||||
// Lie. This will trip the handler service into showing a dialog asking
|
||||
// what the user wants.
|
||||
return NS_ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
return LoadUriInternal(aURI);
|
||||
}
|
||||
|
||||
if (mPreferredAction == useHelperApp) {
|
||||
if (!mPreferredApplication) return NS_ERROR_FILE_NOT_FOUND;
|
||||
|
||||
EnsureAppDetailsAvailable();
|
||||
nsCOMPtr<nsILocalHandlerApp> localPreferredHandler =
|
||||
do_QueryInterface(mPreferredApplication);
|
||||
if (localPreferredHandler) {
|
||||
nsCOMPtr<nsIFile> executable;
|
||||
localPreferredHandler->GetExecutable(getter_AddRefs(executable));
|
||||
executable = GetCanonicalExecutable(executable);
|
||||
bool isOurExecutable = false;
|
||||
if (!executable ||
|
||||
NS_FAILED(executable->Equals(sOurAppFile, &isOurExecutable)) ||
|
||||
isOurExecutable) {
|
||||
// Lie. This will trip the handler service into showing a dialog asking
|
||||
// what the user wants.
|
||||
return NS_ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
return mPreferredApplication->LaunchWithURI(aURI, aWindowContext);
|
||||
}
|
||||
|
||||
|
@ -120,6 +120,12 @@ nsOSHelperAppServiceChild::GetProtocolHandlerInfoFromOS(
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOSHelperAppServiceChild::IsCurrentAppOSDefaultForProtocol(
|
||||
const nsACString& aScheme, bool* aRetVal) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult nsOSHelperAppServiceChild::GetFileTokenForPath(
|
||||
const char16_t* platformAppPath, nsIFile** aFile) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
@ -37,6 +37,8 @@ class nsOSHelperAppServiceChild : public nsExternalHelperAppService {
|
||||
|
||||
NS_IMETHOD GetApplicationDescription(const nsACString& aScheme,
|
||||
nsAString& aRetVal) override;
|
||||
NS_IMETHOD IsCurrentAppOSDefaultForProtocol(const nsACString& aScheme,
|
||||
bool* _retval) override;
|
||||
|
||||
NS_IMETHOD GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||
const nsACString& aFileExt, bool* aFound,
|
||||
|
@ -11,5 +11,7 @@ support-files =
|
||||
download.sjs
|
||||
[browser_download_always_ask_preferred_app.js]
|
||||
[browser_download_privatebrowsing.js]
|
||||
[browser_protocolhandler_loop.js]
|
||||
skip-if = fission # Bug 1597154
|
||||
[browser_remember_download_option.js]
|
||||
[browser_web_protocol_handlers.js]
|
||||
|
@ -0,0 +1,82 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(async function test_helperapp() {
|
||||
// Set up the test infrastructure:
|
||||
const kProt = "foopydoopydoo";
|
||||
const extProtocolSvc = Cc[
|
||||
"@mozilla.org/uriloader/external-protocol-service;1"
|
||||
].getService(Ci.nsIExternalProtocolService);
|
||||
const handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].getService(
|
||||
Ci.nsIHandlerService
|
||||
);
|
||||
let handlerInfo = extProtocolSvc.getProtocolHandlerInfo(kProt);
|
||||
if (handlerSvc.exists(handlerInfo)) {
|
||||
handlerSvc.fillHandlerInfo(handlerInfo, "");
|
||||
}
|
||||
// Say we want to use a specific app:
|
||||
handlerInfo.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
|
||||
handlerInfo.alwaysAskBeforeHandling = false;
|
||||
|
||||
// Say it's us:
|
||||
let selfFile = Services.dirsvc.get("XREExeF", Ci.nsIFile);
|
||||
// Make sure it's the .app
|
||||
if (AppConstants.platform == "macosx") {
|
||||
while (
|
||||
!selfFile.leafName.endsWith(".app") &&
|
||||
!selfFile.leafName.endsWith(".app/")
|
||||
) {
|
||||
selfFile = selfFile.parent;
|
||||
}
|
||||
}
|
||||
let selfHandlerApp = Cc[
|
||||
"@mozilla.org/uriloader/local-handler-app;1"
|
||||
].createInstance(Ci.nsILocalHandlerApp);
|
||||
selfHandlerApp.executable = selfFile;
|
||||
handlerInfo.possibleApplicationHandlers.appendElement(selfHandlerApp);
|
||||
handlerInfo.preferredApplicationHandler = selfHandlerApp;
|
||||
handlerSvc.store(handlerInfo);
|
||||
|
||||
await BrowserTestUtils.withNewTab("about:blank", async browser => {
|
||||
// Now, do some safety stubbing. If we do end up recursing we spawn
|
||||
// infinite tabs. We definitely don't want that. Avoid it by stubbing
|
||||
// our external URL handling bits:
|
||||
let oldAddTab = gBrowser.addTab;
|
||||
registerCleanupFunction(
|
||||
() => (gBrowser.addTab = gBrowser.loadOneTab = oldAddTab)
|
||||
);
|
||||
let wrongThingHappenedPromise = new Promise(resolve => {
|
||||
gBrowser.addTab = gBrowser.loadOneTab = function(aURI) {
|
||||
ok(false, "Tried to open unexpected URL in a tab: " + aURI);
|
||||
resolve(null);
|
||||
// Pass a dummy object to avoid upsetting BrowserContentHandler -
|
||||
// if it thinks opening the tab failed, it tries to open a window instead,
|
||||
// which we can't prevent as easily, and at which point we still end up
|
||||
// with runaway tabs.
|
||||
return {};
|
||||
};
|
||||
});
|
||||
// We can't use TestUtils.topicObserved because it leaks.
|
||||
let askedUserPromise = new Promise(r => {
|
||||
let obs = () => {
|
||||
r("yes");
|
||||
Services.obs.removeObserver(obs, "domwindowopened");
|
||||
};
|
||||
Services.obs.addObserver(obs, "domwindowopened");
|
||||
});
|
||||
BrowserTestUtils.loadURI(browser, kProt + ":test");
|
||||
let win = await Promise.race([wrongThingHappenedPromise, askedUserPromise]);
|
||||
ok(win, "Should have gotten a window");
|
||||
// This is really annoying. Hanging on to the window from the observer
|
||||
// leaks for some reason. Just close it now. It has no window type, so use
|
||||
// the lack of one to distinguish it from the browser and the harness.
|
||||
for (let openWin of Services.wm.getEnumerator("")) {
|
||||
if (!openWin.document.documentElement.getAttribute("windowtype")) {
|
||||
openWin.close();
|
||||
}
|
||||
}
|
||||
askedUserPromise = null;
|
||||
});
|
||||
});
|
@ -24,6 +24,8 @@ class nsOSHelperAppService final : public nsExternalHelperAppService {
|
||||
// override nsIExternalProtocolService methods
|
||||
NS_IMETHOD GetApplicationDescription(const nsACString& aScheme,
|
||||
nsAString& _retval);
|
||||
NS_IMETHOD IsCurrentAppOSDefaultForProtocol(const nsACString& aScheme,
|
||||
bool* _retval);
|
||||
|
||||
// method overrides --> used to hook the mime service into internet config....
|
||||
NS_IMETHOD GetFromTypeAndExtension(const nsACString& aType,
|
||||
|
@ -21,6 +21,11 @@ nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme, nsASt
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(const nsACString& aScheme, bool* _retval) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t* aPlatformAppPath,
|
||||
nsIFile** aFile) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
@ -1057,6 +1057,12 @@ NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(
|
||||
const nsACString& aScheme, bool* _retval) {
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsOSHelperAppService::GetFileTokenForPath(
|
||||
const char16_t* platformAppPath, nsIFile** aFile) {
|
||||
LOG(("-- nsOSHelperAppService::GetFileTokenForPath: '%s'\n",
|
||||
|
@ -36,6 +36,8 @@ class nsOSHelperAppService : public nsExternalHelperAppService {
|
||||
bool* aHandlerExists) override;
|
||||
NS_IMETHOD GetApplicationDescription(const nsACString& aScheme,
|
||||
nsAString& _retval) override;
|
||||
NS_IMETHOD IsCurrentAppOSDefaultForProtocol(const nsACString& aScheme,
|
||||
bool* _retval) override;
|
||||
|
||||
// GetFileTokenForPath must be implemented by each platform.
|
||||
// platformAppPath --> a platform specific path to an application that we got
|
||||
|
@ -152,6 +152,12 @@ NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(
|
||||
const nsACString& aScheme, bool* _retval) {
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// GetMIMEInfoFromRegistry: This function obtains the values of some of the
|
||||
// nsIMIMEInfo attributes for the mimeType/extension associated with the input
|
||||
// registry key. The default entry for that key is the name of a registry key
|
||||
|
@ -37,6 +37,9 @@ class nsOSHelperAppService : public nsExternalHelperAppService {
|
||||
NS_IMETHOD GetApplicationDescription(const nsACString& aScheme,
|
||||
nsAString& _retval) override;
|
||||
|
||||
NS_IMETHOD IsCurrentAppOSDefaultForProtocol(const nsACString& aScheme,
|
||||
bool* _retval) override;
|
||||
|
||||
// method overrides for windows registry look up steps....
|
||||
NS_IMETHOD GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||
const nsACString& aFileExt, bool* aFound,
|
||||
|
Loading…
x
Reference in New Issue
Block a user