feat: add app.getApplicationNameForProtocol API (#20399)
* Add GetApplicationNameForProtocol. * Fix Windows implementation. * Fix up test. * Add documentation. * Implement for real on Linux using xdg-mime. Also ensure we allow blocking calls here to avoid errant DCHECKing. * Improve docs for Linux. * Clean up tests. * Add a note about not relying on the precise format. * Update docs/api/app.md Co-Authored-By: Shelley Vohr <codebytere@github.com> * Remove needless `done()`s from tests. * Use vector list initialization. * Add a simple test for isDefaultProtocolClient. * Remove unneeded include and skip a test on Linux CI. * We no longer differentiate between CI and non-CI test runs.
This commit is contained in:
parent
24939e8fa4
commit
9b01bb00d2
7 changed files with 183 additions and 20 deletions
|
@ -71,6 +71,68 @@ bool GetProtocolLaunchPath(gin_helper::Arguments* args, base::string16* exe) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Windows treats a given scheme as an Internet scheme only if its registry
|
||||
// entry has a "URL Protocol" key. Check this, otherwise we allow ProgIDs to be
|
||||
// used as custom protocols which leads to security bugs.
|
||||
bool IsValidCustomProtocol(const base::string16& scheme) {
|
||||
if (scheme.empty())
|
||||
return false;
|
||||
base::win::RegKey cmd_key(HKEY_CLASSES_ROOT, scheme.c_str(), KEY_QUERY_VALUE);
|
||||
return cmd_key.Valid() && cmd_key.HasValue(L"URL Protocol");
|
||||
}
|
||||
|
||||
// Windows 8 introduced a new protocol->executable binding system which cannot
|
||||
// be retrieved in the HKCR registry subkey method implemented below. We call
|
||||
// AssocQueryString with the new Win8-only flag ASSOCF_IS_PROTOCOL instead.
|
||||
base::string16 GetAppForProtocolUsingAssocQuery(const GURL& url) {
|
||||
const base::string16 url_scheme = base::ASCIIToUTF16(url.scheme());
|
||||
if (!IsValidCustomProtocol(url_scheme))
|
||||
return base::string16();
|
||||
|
||||
// Query AssocQueryString for a human-readable description of the program
|
||||
// that will be invoked given the provided URL spec. This is used only to
|
||||
// populate the external protocol dialog box the user sees when invoking
|
||||
// an unknown external protocol.
|
||||
wchar_t out_buffer[1024];
|
||||
DWORD buffer_size = base::size(out_buffer);
|
||||
HRESULT hr =
|
||||
AssocQueryString(ASSOCF_IS_PROTOCOL, ASSOCSTR_FRIENDLYAPPNAME,
|
||||
url_scheme.c_str(), NULL, out_buffer, &buffer_size);
|
||||
if (FAILED(hr)) {
|
||||
DLOG(WARNING) << "AssocQueryString failed!";
|
||||
return base::string16();
|
||||
}
|
||||
return base::string16(out_buffer);
|
||||
}
|
||||
|
||||
base::string16 GetAppForProtocolUsingRegistry(const GURL& url) {
|
||||
const base::string16 url_scheme = base::ASCIIToUTF16(url.scheme());
|
||||
if (!IsValidCustomProtocol(url_scheme))
|
||||
return base::string16();
|
||||
|
||||
// First, try and extract the application's display name.
|
||||
base::string16 command_to_launch;
|
||||
base::win::RegKey cmd_key_name(HKEY_CLASSES_ROOT, url_scheme.c_str(),
|
||||
KEY_READ);
|
||||
if (cmd_key_name.ReadValue(NULL, &command_to_launch) == ERROR_SUCCESS &&
|
||||
!command_to_launch.empty()) {
|
||||
return command_to_launch;
|
||||
}
|
||||
|
||||
// Otherwise, parse the command line in the registry, and return the basename
|
||||
// of the program path if it exists.
|
||||
const base::string16 cmd_key_path = url_scheme + L"\\shell\\open\\command";
|
||||
base::win::RegKey cmd_key_exe(HKEY_CLASSES_ROOT, cmd_key_path.c_str(),
|
||||
KEY_READ);
|
||||
if (cmd_key_exe.ReadValue(NULL, &command_to_launch) == ERROR_SUCCESS) {
|
||||
base::CommandLine command_line(
|
||||
base::CommandLine::FromString(command_to_launch));
|
||||
return command_line.GetProgram().BaseName().value();
|
||||
}
|
||||
|
||||
return base::string16();
|
||||
}
|
||||
|
||||
bool FormatCommandLineString(base::string16* exe,
|
||||
const std::vector<base::string16>& launch_args) {
|
||||
if (exe->empty() && !GetProcessExecPath(exe)) {
|
||||
|
@ -293,6 +355,17 @@ bool Browser::IsDefaultProtocolClient(const std::string& protocol,
|
|||
return keyVal == exe;
|
||||
}
|
||||
|
||||
base::string16 Browser::GetApplicationNameForProtocol(const GURL& url) {
|
||||
// Windows 8 or above has a new protocol association query.
|
||||
if (base::win::GetVersion() >= base::win::Version::WIN8) {
|
||||
base::string16 application_name = GetAppForProtocolUsingAssocQuery(url);
|
||||
if (!application_name.empty())
|
||||
return application_name;
|
||||
}
|
||||
|
||||
return GetAppForProtocolUsingRegistry(url);
|
||||
}
|
||||
|
||||
bool Browser::SetBadgeCount(int count) {
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue