summaryrefslogtreecommitdiffstats
path: root/uriloader
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--uriloader/base/nsURILoader.cpp22
-rw-r--r--uriloader/exthandler/HandlerServiceParent.cpp4
-rw-r--r--uriloader/exthandler/android/nsMIMEInfoAndroid.cpp5
-rw-r--r--uriloader/exthandler/moz.build1
-rw-r--r--uriloader/exthandler/nsIContentDispatchChooser.idl2
-rw-r--r--uriloader/exthandler/nsIExternalProtocolService.idl6
-rw-r--r--uriloader/exthandler/nsLocalHandlerApp.cpp98
-rw-r--r--uriloader/exthandler/nsLocalHandlerApp.h10
-rw-r--r--uriloader/exthandler/nsMIMEInfoImpl.cpp15
-rw-r--r--uriloader/exthandler/nsMIMEInfoImpl.h2
-rw-r--r--uriloader/exthandler/tests/unit/test_getFromTypeAndExtension.js122
-rw-r--r--uriloader/exthandler/tests/unit/xpcshell.toml1
-rw-r--r--uriloader/exthandler/unix/nsMIMEInfoUnix.cpp13
-rw-r--r--uriloader/exthandler/unix/nsMIMEInfoUnix.h1
-rw-r--r--uriloader/exthandler/win/nsLocalHandlerAppWin.cpp119
-rw-r--r--uriloader/exthandler/win/nsLocalHandlerAppWin.h34
-rw-r--r--uriloader/exthandler/win/nsMIMEInfoWin.cpp31
-rw-r--r--uriloader/exthandler/win/nsMIMEInfoWin.h3
18 files changed, 465 insertions, 24 deletions
diff --git a/uriloader/base/nsURILoader.cpp b/uriloader/base/nsURILoader.cpp
index 792f3ea893..ef138f05d2 100644
--- a/uriloader/base/nsURILoader.cpp
+++ b/uriloader/base/nsURILoader.cpp
@@ -435,28 +435,28 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest* request) {
NS_ASSERTION(!m_targetStreamListener,
"If we found a listener, why are we not using it?");
- if (mFlags & nsIURILoader::DONT_RETARGET) {
- LOG(
- (" External handling forced or (listener not interested and no "
- "stream converter exists), and retargeting disallowed -> aborting"));
- return NS_ERROR_WONT_HANDLE_CONTENT;
- }
-
// Before dispatching to the external helper app service, check for an HTTP
// error page. If we got one, we don't want to handle it with a helper app,
// really.
- // The WPT a-download-click-404.html requires us to silently handle this
- // without displaying an error page, so we just return early here.
- // See bug 1604308 for discussion around what the ideal behaviour is.
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
if (httpChannel) {
bool requestSucceeded;
rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
if (NS_FAILED(rv) || !requestSucceeded) {
- return NS_OK;
+ LOG(
+ (" Returning NS_ERROR_FILE_NOT_FOUND from "
+ "nsDocumentOpenInfo::DispatchContent due to failed HTTP response"));
+ return NS_ERROR_FILE_NOT_FOUND;
}
}
+ if (mFlags & nsIURILoader::DONT_RETARGET) {
+ LOG(
+ (" External handling forced or (listener not interested and no "
+ "stream converter exists), and retargeting disallowed -> aborting"));
+ return NS_ERROR_WONT_HANDLE_CONTENT;
+ }
+
// Fifth step:
//
// All attempts to dispatch this content have failed. Just pass it off to
diff --git a/uriloader/exthandler/HandlerServiceParent.cpp b/uriloader/exthandler/HandlerServiceParent.cpp
index ab77657dd5..1c83d9628f 100644
--- a/uriloader/exthandler/HandlerServiceParent.cpp
+++ b/uriloader/exthandler/HandlerServiceParent.cpp
@@ -110,6 +110,10 @@ NS_IMETHODIMP ProxyHandlerInfo::GetDefaultDescription(
return NS_ERROR_NOT_IMPLEMENTED;
}
+NS_IMETHODIMP ProxyHandlerInfo::GetDefaultExecutable(nsIFile** aExecutable) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
/* void launchWithURI (in nsIURI aURI,
[optional] in BrowsingContext aBrowsingContext); */
NS_IMETHODIMP ProxyHandlerInfo::LaunchWithURI(
diff --git a/uriloader/exthandler/android/nsMIMEInfoAndroid.cpp b/uriloader/exthandler/android/nsMIMEInfoAndroid.cpp
index 86049a55fb..388a378308 100644
--- a/uriloader/exthandler/android/nsMIMEInfoAndroid.cpp
+++ b/uriloader/exthandler/android/nsMIMEInfoAndroid.cpp
@@ -125,6 +125,11 @@ nsMIMEInfoAndroid::GetDefaultDescription(nsAString& aDesc) {
}
NS_IMETHODIMP
+nsMIMEInfoAndroid::GetDefaultExecutable(nsIFile** aExecutable) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
nsMIMEInfoAndroid::LaunchWithURI(
nsIURI* aURI, mozilla::dom::BrowsingContext* aBrowsingContext) {
return mPrefApp->LaunchWithURI(aURI, aBrowsingContext);
diff --git a/uriloader/exthandler/moz.build b/uriloader/exthandler/moz.build
index cb96c690a6..e9009eb063 100644
--- a/uriloader/exthandler/moz.build
+++ b/uriloader/exthandler/moz.build
@@ -95,6 +95,7 @@ elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "android":
]
elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":
UNIFIED_SOURCES += [
+ "win/nsLocalHandlerAppWin.cpp",
"win/nsMIMEInfoWin.cpp",
]
diff --git a/uriloader/exthandler/nsIContentDispatchChooser.idl b/uriloader/exthandler/nsIContentDispatchChooser.idl
index 00d61e575b..c0130038d4 100644
--- a/uriloader/exthandler/nsIContentDispatchChooser.idl
+++ b/uriloader/exthandler/nsIContentDispatchChooser.idl
@@ -36,5 +36,5 @@ interface nsIContentDispatchChooser : nsISupports {
in nsIURI aURI,
in nsIPrincipal aTriggeringPrincipal,
in BrowsingContext aBrowsingContext,
- [optional] in bool aWasTriggeredExternally);
+ [optional] in boolean aWasTriggeredExternally);
};
diff --git a/uriloader/exthandler/nsIExternalProtocolService.idl b/uriloader/exthandler/nsIExternalProtocolService.idl
index 7d714035e6..5c544a967d 100644
--- a/uriloader/exthandler/nsIExternalProtocolService.idl
+++ b/uriloader/exthandler/nsIExternalProtocolService.idl
@@ -129,8 +129,8 @@ interface nsIExternalProtocolService : nsISupports
[optional] in nsIPrincipal aTriggeringPrincipal,
[optional] in nsIPrincipal aRedirectPrincipal,
[optional] in BrowsingContext aBrowsingContext,
- [optional] in bool aWasTriggeredExternally,
- [optional] in bool aHasValidUserGestureActivation);
+ [optional] in boolean aWasTriggeredExternally,
+ [optional] in boolean aHasValidUserGestureActivation);
/**
* Gets a human-readable description for the application responsible for
@@ -151,5 +151,5 @@ interface nsIExternalProtocolService : nsISupports
*
* @param aScheme The scheme to look up. For example, "mms".
*/
- bool isCurrentAppOSDefaultForProtocol(in AUTF8String aScheme);
+ boolean isCurrentAppOSDefaultForProtocol(in AUTF8String aScheme);
};
diff --git a/uriloader/exthandler/nsLocalHandlerApp.cpp b/uriloader/exthandler/nsLocalHandlerApp.cpp
index 6212d2aeb4..fa3f27758f 100644
--- a/uriloader/exthandler/nsLocalHandlerApp.cpp
+++ b/uriloader/exthandler/nsLocalHandlerApp.cpp
@@ -8,11 +8,15 @@
#include "nsIURI.h"
#include "nsIProcess.h"
#include "nsComponentManagerUtils.h"
+#include "mozilla/dom/Promise.h"
+#include "nsProxyRelease.h"
// XXX why does nsMIMEInfoImpl have a threadsafe nsISupports? do we need one
// here too?
NS_IMPL_ISUPPORTS(nsLocalHandlerApp, nsILocalHandlerApp, nsIHandlerApp)
+using namespace mozilla;
+
////////////////////////////////////////////////////////////////////////////////
//// nsIHandlerApp
@@ -28,6 +32,100 @@ NS_IMETHODIMP nsLocalHandlerApp::GetName(nsAString& aName) {
return NS_OK;
}
+/**
+ * This method returns a std::function that will be executed on a thread other
+ * than the main thread. To facilitate things, it should effectively be a global
+ * function that does not maintain a reference to the this pointer. There should
+ * be no reference to any objects that will be shared across threads. Sub-class
+ * implementations should make local copies of everything they need and capture
+ * those in the callback.
+ */
+std::function<nsresult(nsString&)>
+nsLocalHandlerApp::GetPrettyNameOnNonMainThreadCallback() {
+ nsString name;
+
+ // Calculate the name now, on the main thread, so as to avoid
+ // doing anything with the this pointer on the other thread
+ auto result = GetName(name);
+
+ return [name, result](nsString& aName) -> nsresult {
+ aName = name;
+ return result;
+ };
+}
+
+NS_IMETHODIMP
+nsLocalHandlerApp::PrettyNameAsync(JSContext* aCx, dom::Promise** aPromise) {
+ NS_ENSURE_ARG_POINTER(aPromise);
+
+ *aPromise = nullptr;
+
+ if (!mExecutable) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
+ if (NS_WARN_IF(!global)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ ErrorResult err;
+ RefPtr<dom::Promise> outer = dom::Promise::Create(global, err);
+ if (NS_WARN_IF(err.Failed())) {
+ return err.StealNSResult();
+ }
+
+ outer.forget(aPromise);
+
+ nsAutoString executablePath;
+ nsresult result = mExecutable->GetPath(executablePath);
+
+ if (NS_FAILED(result) || executablePath.IsEmpty()) {
+ (*aPromise)->MaybeReject(result);
+ return NS_OK;
+ }
+
+ nsMainThreadPtrHandle<dom::Promise> promiseHolder(
+ new nsMainThreadPtrHolder<dom::Promise>(
+ "nsLocalHandlerApp::prettyExecutableName Promise", *aPromise));
+
+ auto prettyNameGetter = GetPrettyNameOnNonMainThreadCallback();
+
+ result = NS_DispatchBackgroundTask(
+ NS_NewRunnableFunction(
+ __func__,
+ [promiseHolder /* can't move this because if the dispatch fails, we
+ call reject on the promiseHolder */
+ ,
+ prettyNameGetter = std::move(prettyNameGetter)]() mutable -> void {
+ nsAutoString prettyExecutableName;
+
+ nsresult result = prettyNameGetter(prettyExecutableName);
+
+ DebugOnly<nsresult> rv =
+ NS_DispatchToMainThread(NS_NewRunnableFunction(
+ __func__,
+ [promiseHolder = std::move(promiseHolder),
+ prettyExecutableName = std::move(prettyExecutableName),
+ result]() {
+ if (NS_FAILED(result)) {
+ promiseHolder.get()->MaybeReject(result);
+ } else {
+ promiseHolder.get()->MaybeResolve(prettyExecutableName);
+ }
+ }));
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+ "NS_DispatchToMainThread failed");
+ }),
+ NS_DISPATCH_EVENT_MAY_BLOCK);
+
+ if (NS_FAILED(result)) {
+ promiseHolder.get()->MaybeReject(result);
+ }
+
+ return NS_OK;
+}
+
NS_IMETHODIMP nsLocalHandlerApp::SetName(const nsAString& aName) {
mName.Assign(aName);
diff --git a/uriloader/exthandler/nsLocalHandlerApp.h b/uriloader/exthandler/nsLocalHandlerApp.h
index 3ea8e3e4fc..ebe43f7dcb 100644
--- a/uriloader/exthandler/nsLocalHandlerApp.h
+++ b/uriloader/exthandler/nsLocalHandlerApp.h
@@ -12,6 +12,8 @@
#include "nsIFile.h"
#include "nsTArray.h"
+#include <functional>
+
class nsLocalHandlerApp : public nsILocalHandlerApp {
public:
NS_DECL_ISUPPORTS
@@ -29,6 +31,9 @@ class nsLocalHandlerApp : public nsILocalHandlerApp {
protected:
virtual ~nsLocalHandlerApp() {}
+ virtual std::function<nsresult(nsString&)>
+ GetPrettyNameOnNonMainThreadCallback();
+
nsString mName;
nsString mDetailedDescription;
nsTArray<nsString> mParameters;
@@ -52,6 +57,11 @@ class nsLocalHandlerApp : public nsILocalHandlerApp {
# include "mac/nsLocalHandlerAppMac.h"
typedef nsLocalHandlerAppMac PlatformLocalHandlerApp_t;
# endif
+#elif XP_WIN
+# ifndef NSLOCALHANDLERAPPWIN_H_
+# include "win/nsLocalHandlerAppWin.h"
+typedef nsLocalHandlerAppWin PlatformLocalHandlerApp_t;
+# endif
#else
typedef nsLocalHandlerApp PlatformLocalHandlerApp_t;
#endif
diff --git a/uriloader/exthandler/nsMIMEInfoImpl.cpp b/uriloader/exthandler/nsMIMEInfoImpl.cpp
index 3616ab7fcf..378acb160b 100644
--- a/uriloader/exthandler/nsMIMEInfoImpl.cpp
+++ b/uriloader/exthandler/nsMIMEInfoImpl.cpp
@@ -231,6 +231,11 @@ nsMIMEInfoBase::GetDefaultDescription(nsAString& aDefaultDescription) {
}
NS_IMETHODIMP
+nsMIMEInfoBase::GetDefaultExecutable(nsIFile** aExecutable) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
nsMIMEInfoBase::GetPreferredApplicationHandler(
nsIHandlerApp** aPreferredAppHandler) {
*aPreferredAppHandler = mPreferredApplication;
@@ -483,6 +488,16 @@ nsMIMEInfoImpl::GetDefaultDescription(nsAString& aDefaultDescription) {
return NS_OK;
}
+NS_IMETHODIMP nsMIMEInfoImpl::GetDefaultExecutable(nsIFile** aExecutable) {
+ nsCOMPtr<nsIFile> defaultApp = GetDefaultApplication();
+ if (defaultApp) {
+ defaultApp.forget(aExecutable);
+ return NS_OK;
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
NS_IMETHODIMP
nsMIMEInfoImpl::GetHasDefaultHandler(bool* _retval) {
*_retval = !mDefaultAppDescription.IsEmpty();
diff --git a/uriloader/exthandler/nsMIMEInfoImpl.h b/uriloader/exthandler/nsMIMEInfoImpl.h
index 9b080ac545..d04566b92c 100644
--- a/uriloader/exthandler/nsMIMEInfoImpl.h
+++ b/uriloader/exthandler/nsMIMEInfoImpl.h
@@ -57,6 +57,7 @@ class nsMIMEInfoBase : public nsIMIMEInfo {
NS_IMETHOD GetPossibleApplicationHandlers(
nsIMutableArray** aPossibleAppHandlers) override;
NS_IMETHOD GetDefaultDescription(nsAString& aDefaultDescription) override;
+ NS_IMETHOD GetDefaultExecutable(nsIFile** aExecutable) override;
NS_IMETHOD LaunchWithFile(nsIFile* aFile) override;
NS_IMETHOD LaunchWithURI(
nsIURI* aURI, mozilla::dom::BrowsingContext* aBrowsingContext) override;
@@ -187,6 +188,7 @@ class nsMIMEInfoImpl : public nsMIMEInfoBase {
// nsIMIMEInfo methods
NS_IMETHOD GetHasDefaultHandler(bool* _retval) override;
NS_IMETHOD GetDefaultDescription(nsAString& aDefaultDescription) override;
+ NS_IMETHOD GetDefaultExecutable(nsIFile** aExecutable) override;
NS_IMETHOD IsCurrentAppOSDefault(bool* _retval) override;
// additional methods
diff --git a/uriloader/exthandler/tests/unit/test_getFromTypeAndExtension.js b/uriloader/exthandler/tests/unit/test_getFromTypeAndExtension.js
index 6f4fe52a49..87a013812b 100644
--- a/uriloader/exthandler/tests/unit/test_getFromTypeAndExtension.js
+++ b/uriloader/exthandler/tests/unit/test_getFromTypeAndExtension.js
@@ -15,3 +15,125 @@ add_task(async function test_utf8_extension() {
Assert.equal(someMIME.primaryExtension, ".ั‚ะตัั‚");
}
});
+
+function getLocalHandlers(mimeInfo) {
+ try {
+ const appList = mimeInfo?.possibleLocalHandlers || [];
+ return appList;
+ } catch (err) {
+ // if the mime info on this platform doesn't support getting local handlers,
+ // we don't need to test
+ if (err.result == Cr.NS_ERROR_NOT_IMPLEMENTED) {
+ return [];
+ }
+
+ // otherwise, throw the err because the test is broken
+ throw err;
+ }
+}
+
+add_task(async function test_default_executable() {
+ if (AppConstants.platform == "linux") {
+ return;
+ }
+
+ const mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
+ let mimeInfo = mimeService.getFromTypeAndExtension("text/html", "html");
+ if (mimeInfo !== undefined) {
+ if (mimeInfo.hasDefaultHandler) {
+ let defaultExecutableFile = mimeInfo.defaultExecutable;
+ if (defaultExecutableFile) {
+ if (AppConstants.platform == "win") {
+ Assert.ok(
+ defaultExecutableFile.leafName.endsWith(".exe"),
+ "Default browser on Windows should end with .exe"
+ );
+ }
+ }
+
+ let foundDefaultInList = false;
+
+ let appList = getLocalHandlers(mimeInfo);
+ if (!appList.length) {
+ return;
+ }
+
+ for (let index = 0; index < appList.length; index++) {
+ let app = appList.queryElementAt(index, Ci.nsILocalHandlerApp);
+ let executablePath = app.executable.path;
+
+ if (executablePath == defaultExecutableFile.path) {
+ foundDefaultInList = true;
+ break;
+ }
+ }
+
+ Assert.ok(
+ foundDefaultInList,
+ "The default browser must be returned in the list of executables from the mime info"
+ );
+ } else {
+ Assert.throws(
+ () => mimeInfo.defaultExecutable,
+ /NS_ERROR_FAILURE/,
+ "Fetching the defaultExecutable should generate an exception; this line should never be reached"
+ );
+ }
+ }
+});
+
+add_task(async function test_pretty_name_for_edge() {
+ if (AppConstants.platform == "win" && !AppConstants.IS_ESR) {
+ const mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
+
+ let mimeInfo = mimeService.getFromTypeAndExtension("text/html", "html");
+ let appList = getLocalHandlers(mimeInfo);
+ for (let index = 0; index < appList.length; index++) {
+ let app = appList.queryElementAt(index, Ci.nsILocalHandlerApp);
+ if (app) {
+ let executableName = app.executable?.displayName;
+ if (executableName) {
+ let prettyName = await app.prettyNameAsync();
+
+ // Hardcode Edge, as an extra test, when it's installed
+ if (executableName == "msedge.exe") {
+ Assert.equal(
+ prettyName,
+ "Microsoft Edge",
+ "The generated pretty name for MS Edge should match the expectation."
+ );
+ }
+
+ // The pretty name should always be something nicer than the executable name.
+ // This isn't testing that's nice, but should be good enough to validate that
+ // something other than the executable is found.
+ Assert.notEqual(executableName, prettyName);
+ }
+ }
+ }
+ }
+});
+
+add_task(async function test_pretty_names_match_names_on_non_windows() {
+ if (AppConstants.platform != "win") {
+ const mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
+
+ let mimeInfo = mimeService.getFromTypeAndExtension("text/html", "html");
+ let appList = getLocalHandlers(mimeInfo);
+ for (let index = 0; index < appList.length; index++) {
+ let app = appList.queryElementAt(index, Ci.nsILocalHandlerApp);
+ if (app) {
+ if (app.executable) {
+ let name = app.executable.name;
+ let prettyName = await app.prettyNameAsync();
+
+ Assert.equal(
+ prettyName,
+ name,
+ "On platforms other than windows, the prettyName and the name of file handlers should be the same."
+ );
+ }
+ }
+ }
+ }
+});
diff --git a/uriloader/exthandler/tests/unit/xpcshell.toml b/uriloader/exthandler/tests/unit/xpcshell.toml
index 216ad49555..91e1f65e48 100644
--- a/uriloader/exthandler/tests/unit/xpcshell.toml
+++ b/uriloader/exthandler/tests/unit/xpcshell.toml
@@ -18,6 +18,7 @@ skip-if = [
skip-if = ["os == 'mac'"] # Bug 1817727
["test_getFromTypeAndExtension.js"]
+skip-if = ["os == 'android'"]
["test_getMIMEInfo_pdf.js"]
diff --git a/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp b/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
index 330c441159..038ba672d9 100644
--- a/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
+++ b/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
@@ -9,6 +9,8 @@
#include "nsIGIOService.h"
#include "nsNetCID.h"
#include "nsIIOService.h"
+#include "nsLocalFile.h"
+
#ifdef MOZ_ENABLE_DBUS
# include "nsDBusHandlerApp.h"
#endif
@@ -17,6 +19,17 @@ nsresult nsMIMEInfoUnix::LoadUriInternal(nsIURI* aURI) {
return nsGNOMERegistry::LoadURL(aURI);
}
+NS_IMETHODIMP nsMIMEInfoUnix::GetDefaultExecutable(nsIFile** aExecutable) {
+ // This needs to be implemented before FirefoxBridge will work on Linux.
+ // To implement this and be consistent, GetHasDefaultHandler and
+ // LaunchDefaultWithFile should probably be made to be consistent.
+ // Right now, they aren't. GetHasDefaultHandler reports true in cases
+ // where calling LaunchDefaultWithFile will fail due to not finding the
+ // right executable.
+
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
NS_IMETHODIMP
nsMIMEInfoUnix::GetHasDefaultHandler(bool* _retval) {
// if a default app is set, it means the application has been set from
diff --git a/uriloader/exthandler/unix/nsMIMEInfoUnix.h b/uriloader/exthandler/unix/nsMIMEInfoUnix.h
index 2e32be4915..0d2ca67c07 100644
--- a/uriloader/exthandler/unix/nsMIMEInfoUnix.h
+++ b/uriloader/exthandler/unix/nsMIMEInfoUnix.h
@@ -20,6 +20,7 @@ class nsMIMEInfoUnix : public nsMIMEInfoImpl {
static bool HandlerExists(const char* aProtocolScheme);
protected:
+ NS_IMETHOD GetDefaultExecutable(nsIFile** aExecutable) override;
NS_IMETHOD GetHasDefaultHandler(bool* _retval) override;
virtual nsresult LoadUriInternal(nsIURI* aURI) override;
diff --git a/uriloader/exthandler/win/nsLocalHandlerAppWin.cpp b/uriloader/exthandler/win/nsLocalHandlerAppWin.cpp
new file mode 100644
index 0000000000..df5cfbee03
--- /dev/null
+++ b/uriloader/exthandler/win/nsLocalHandlerAppWin.cpp
@@ -0,0 +1,119 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsLocalHandlerAppWin.h"
+#include "nsString.h"
+#include "nsIWindowsRegKey.h"
+#include "nsILocalFileWin.h"
+#include "nsComponentManagerUtils.h"
+
+static nsresult GetPrettyNameFromFileDescription(
+ const nsCOMPtr<nsILocalFileWin>& executableOnWindows,
+ const nsString& assignedName, nsString& aName) {
+ nsresult result = NS_ERROR_FAILURE;
+
+ if (executableOnWindows) {
+ result = executableOnWindows->GetVersionInfoField("FileDescription", aName);
+
+ if (NS_FAILED(result) || aName.IsEmpty()) {
+ if (!assignedName.IsEmpty()) {
+ aName = assignedName;
+ } else {
+ result = executableOnWindows->GetLeafName(aName);
+ }
+
+ if (!aName.IsEmpty()) {
+ result = NS_OK;
+ } else {
+ result = NS_ERROR_FAILURE;
+ }
+ }
+ }
+
+ return result;
+}
+
+static nsresult GetValueFromRegistry(nsString& aName,
+ const nsCOMPtr<nsIWindowsRegKey>& appKey,
+ const nsString& registryPath,
+ const nsString& valueName) {
+ nsresult rv =
+ appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, registryPath,
+ nsIWindowsRegKey::ACCESS_QUERY_VALUE);
+
+ if (NS_SUCCEEDED(rv)) {
+ nsAutoString applicationName;
+ if (NS_SUCCEEDED(appKey->ReadStringValue(valueName, applicationName))) {
+ aName = applicationName;
+ return NS_OK;
+ }
+ }
+
+ return NS_ERROR_FAILURE;
+};
+
+std::function<nsresult(nsString&)>
+nsLocalHandlerAppWin::GetPrettyNameOnNonMainThreadCallback() {
+ // Make a copy of executable so that we don't have to worry about any other
+ // threads
+ nsCOMPtr<nsIFile> executable;
+ mExecutable->Clone(getter_AddRefs(executable));
+
+ // Get the windows interface to the file
+ nsCOMPtr<nsILocalFileWin> executableOnWindows(do_QueryInterface(executable));
+ auto appIdOrName = mAppIdOrName;
+ auto assignedName = mName;
+
+ std::function<nsresult(nsString&)> callback =
+ [assignedName, appIdOrName,
+ executableOnWindows =
+ std::move(executableOnWindows)](nsString& aName) -> nsresult {
+ // On all platforms, we want a human readable name for an application.
+ // For example: msedge -> Microsoft Edge Browser
+ //
+ // This is generated on mac directly in nsLocalHandlerAppMac::GetName.
+ // The auto-test coverage for GetName isn't thorough enough to be
+ // confident that changing GetName on Windows won't cause problems.
+ //
+ // Besides that, this is a potentially slow thing to execute, and making
+ // it asynchronous is preferable. There's a fallback to GetName() in the
+ // nsLocalHandlerApp::PrettyNameAsync to cover Mac and Linux.
+
+ if (appIdOrName.IsEmpty()) {
+ return GetPrettyNameFromFileDescription(executableOnWindows, assignedName,
+ aName);
+ }
+
+ nsCOMPtr<nsIWindowsRegKey> appKey =
+ do_CreateInstance("@mozilla.org/windows-registry-key;1");
+ if (!appKey) {
+ return GetPrettyNameFromFileDescription(executableOnWindows, assignedName,
+ aName);
+ }
+
+ // Check for ApplicationName first. Path:
+ // HKEY_CLASSES_ROOT\${APP_ID}\Application, Value entry: ApplicationName
+ nsresult rv =
+ GetValueFromRegistry(aName, appKey, appIdOrName + u"\\Application"_ns,
+ u"ApplicationName"_ns);
+ if (NS_SUCCEEDED(rv) && !aName.IsEmpty()) {
+ return rv;
+ }
+
+ // Check for the default on the Applications entry next.
+ // Path: HKEY_CLASSES_ROOT\Applications\${APP_ID}, Value entry: ""
+ // (default)
+ rv = GetValueFromRegistry(aName, appKey, u"Applications\\"_ns + appIdOrName,
+ u""_ns);
+ if (NS_SUCCEEDED(rv) && !aName.IsEmpty()) {
+ return rv;
+ }
+
+ // Fallthrough to getting the name from the file description
+ return GetPrettyNameFromFileDescription(executableOnWindows, assignedName,
+ aName);
+ };
+
+ return callback;
+}
diff --git a/uriloader/exthandler/win/nsLocalHandlerAppWin.h b/uriloader/exthandler/win/nsLocalHandlerAppWin.h
new file mode 100644
index 0000000000..68deda05f4
--- /dev/null
+++ b/uriloader/exthandler/win/nsLocalHandlerAppWin.h
@@ -0,0 +1,34 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef NSLOCALHANDLERAPPWIN_H_
+#define NSLOCALHANDLERAPPWIN_H_
+
+#include "nsLocalHandlerApp.h"
+#include "nsString.h"
+
+class nsLocalHandlerAppWin : public nsLocalHandlerApp {
+ public:
+ nsLocalHandlerAppWin() {}
+
+ nsLocalHandlerAppWin(const char16_t* aName, nsIFile* aExecutable)
+ : nsLocalHandlerApp(aName, aExecutable) {}
+
+ nsLocalHandlerAppWin(const nsAString& aName, nsIFile* aExecutable)
+ : nsLocalHandlerApp(aName, aExecutable) {}
+ virtual ~nsLocalHandlerAppWin() {}
+
+ void SetAppIdOrName(const nsString& appIdOrName) {
+ mAppIdOrName = appIdOrName;
+ }
+
+ protected:
+ std::function<nsresult(nsString&)> GetPrettyNameOnNonMainThreadCallback()
+ override;
+
+ private:
+ nsString mAppIdOrName;
+};
+
+#endif /*NSLOCALHANDLERAPPMAC_H_*/
diff --git a/uriloader/exthandler/win/nsMIMEInfoWin.cpp b/uriloader/exthandler/win/nsMIMEInfoWin.cpp
index 758b2018a7..24044c5f25 100644
--- a/uriloader/exthandler/win/nsMIMEInfoWin.cpp
+++ b/uriloader/exthandler/win/nsMIMEInfoWin.cpp
@@ -9,6 +9,7 @@
#include "nsCOMArray.h"
#include "nsLocalFile.h"
#include "nsMIMEInfoWin.h"
+#include "nsLocalHandlerAppWin.h"
#include "nsIMIMEService.h"
#include "nsNetUtil.h"
#include <windows.h>
@@ -221,6 +222,16 @@ nsMIMEInfoWin::GetHasDefaultHandler(bool* _retval) {
return NS_OK;
}
+NS_IMETHODIMP nsMIMEInfoWin::GetDefaultExecutable(nsIFile** aExecutable) {
+ nsCOMPtr<nsIFile> defaultApp = GetDefaultApplication();
+ if (defaultApp) {
+ defaultApp.forget(aExecutable);
+ return NS_OK;
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
NS_IMETHODIMP
nsMIMEInfoWin::GetEnumerator(nsISimpleEnumerator** _retval) {
nsCOMArray<nsIVariant> properties;
@@ -554,6 +565,7 @@ bool nsMIMEInfoWin::GetProgIDVerbCommandHandler(const nsAString& appProgIDName,
// entries to lower case and stores them in the trackList array.
void nsMIMEInfoWin::ProcessPath(nsCOMPtr<nsIMutableArray>& appList,
nsTArray<nsString>& trackList,
+ const nsAutoString& appIdOrName,
const nsAString& appFilesystemCommand) {
nsAutoString lower(appFilesystemCommand);
ToLowerCase(lower);
@@ -569,6 +581,9 @@ void nsMIMEInfoWin::ProcessPath(nsCOMPtr<nsIMutableArray>& appList,
nsCOMPtr<nsILocalHandlerApp> aApp;
if (!GetLocalHandlerApp(appFilesystemCommand, aApp)) return;
+ // Track the app id so that the pretty name can be determined later
+ (static_cast<nsLocalHandlerAppWin*>(aApp.get()))->SetAppIdOrName(appIdOrName);
+
// Save in our main tracking arrays
appList->AppendElement(aApp);
trackList.AppendElement(lower);
@@ -673,7 +688,7 @@ nsMIMEInfoWin::GetPossibleLocalHandlers(nsIArray** _retval) {
if (GetProgIDVerbCommandHandler(appProgId, appFilesystemCommand,
false) &&
!IsPathInList(appFilesystemCommand, trackList)) {
- ProcessPath(appList, trackList, appFilesystemCommand);
+ ProcessPath(appList, trackList, appProgId, appFilesystemCommand);
}
}
}
@@ -701,7 +716,7 @@ nsMIMEInfoWin::GetPossibleLocalHandlers(nsIArray** _retval) {
false) ||
IsPathInList(appFilesystemCommand, trackList))
continue;
- ProcessPath(appList, trackList, appFilesystemCommand);
+ ProcessPath(appList, trackList, appName, appFilesystemCommand);
}
}
regKey->Close();
@@ -729,7 +744,7 @@ nsMIMEInfoWin::GetPossibleLocalHandlers(nsIArray** _retval) {
false) ||
IsPathInList(appFilesystemCommand, trackList))
continue;
- ProcessPath(appList, trackList, appFilesystemCommand);
+ ProcessPath(appList, trackList, appProgId, appFilesystemCommand);
}
}
regKey->Close();
@@ -762,7 +777,7 @@ nsMIMEInfoWin::GetPossibleLocalHandlers(nsIArray** _retval) {
false) ||
IsPathInList(appFilesystemCommand, trackList))
continue;
- ProcessPath(appList, trackList, appFilesystemCommand);
+ ProcessPath(appList, trackList, appValue, appFilesystemCommand);
}
}
}
@@ -791,7 +806,7 @@ nsMIMEInfoWin::GetPossibleLocalHandlers(nsIArray** _retval) {
false) ||
IsPathInList(appFilesystemCommand, trackList))
continue;
- ProcessPath(appList, trackList, appFilesystemCommand);
+ ProcessPath(appList, trackList, appProgId, appFilesystemCommand);
}
}
regKey->Close();
@@ -829,7 +844,7 @@ nsMIMEInfoWin::GetPossibleLocalHandlers(nsIArray** _retval) {
false) ||
IsPathInList(appFilesystemCommand, trackList))
continue;
- ProcessPath(appList, trackList, appFilesystemCommand);
+ ProcessPath(appList, trackList, appName, appFilesystemCommand);
}
}
}
@@ -857,7 +872,7 @@ nsMIMEInfoWin::GetPossibleLocalHandlers(nsIArray** _retval) {
if (!GetAppsVerbCommandHandler(appName, appFilesystemCommand, false) ||
IsPathInList(appFilesystemCommand, trackList))
continue;
- ProcessPath(appList, trackList, appFilesystemCommand);
+ ProcessPath(appList, trackList, appName, appFilesystemCommand);
}
}
regKey->Close();
@@ -882,7 +897,7 @@ nsMIMEInfoWin::GetPossibleLocalHandlers(nsIArray** _retval) {
if (!GetAppsVerbCommandHandler(appName, appFilesystemCommand, false) ||
IsPathInList(appFilesystemCommand, trackList))
continue;
- ProcessPath(appList, trackList, appFilesystemCommand);
+ ProcessPath(appList, trackList, appName, appFilesystemCommand);
}
}
}
diff --git a/uriloader/exthandler/win/nsMIMEInfoWin.h b/uriloader/exthandler/win/nsMIMEInfoWin.h
index fa972b23a9..a7bc40c696 100644
--- a/uriloader/exthandler/win/nsMIMEInfoWin.h
+++ b/uriloader/exthandler/win/nsMIMEInfoWin.h
@@ -22,6 +22,7 @@ class nsMIMEInfoWin : public nsMIMEInfoBase, public nsIPropertyBag {
NS_IMETHOD LaunchWithFile(nsIFile* aFile) override;
NS_IMETHOD GetHasDefaultHandler(bool* _retval) override;
+ NS_IMETHOD GetDefaultExecutable(nsIFile** aExecutable) override;
NS_IMETHOD GetPossibleLocalHandlers(nsIArray** _retval) override;
NS_IMETHOD IsCurrentAppOSDefault(bool* _retval) override;
@@ -68,7 +69,7 @@ class nsMIMEInfoWin : public nsMIMEInfoBase, public nsIPropertyBag {
// Helper routine used in tracking app lists
void ProcessPath(nsCOMPtr<nsIMutableArray>& appList,
- nsTArray<nsString>& trackList,
+ nsTArray<nsString>& trackList, const nsAutoString& appId,
const nsAString& appFilesystemCommand);
// Helper routine to call mozilla::ShellExecuteByExplorer