Fix path/URL confusion in wxLaunchDefaultBrowser()

Add a helper wxLaunchBrowserParams struct with clearly distinct "url" and
"path" fields and GetPathOrURL() accessor which returns whichever is
appropriate.

This makes the code more clear and ensures that we never pass URLs (but only
file paths) to xdg-open under Unix as it doesn't handle them.

See #17227.
This commit is contained in:
Vadim Zeitlin
2016-02-07 19:32:18 +01:00
parent 36b5df11a5
commit 026659297b
6 changed files with 109 additions and 85 deletions

View File

@@ -69,8 +69,10 @@
#include <errno.h>
#if wxUSE_GUI
#include "wx/filesys.h"
#include "wx/notebook.h"
#include "wx/statusbr.h"
#include "wx/private/launchbrowser.h"
#endif // wxUSE_GUI
#include <time.h>
@@ -84,7 +86,6 @@
#if defined(__WINDOWS__)
#include "wx/msw/private.h"
#include "wx/filesys.h"
#endif
#if wxUSE_GUI && defined(__WXGTK__)
@@ -1017,20 +1018,17 @@ bool wxSetDetectableAutoRepeat( bool WXUNUSED(flag) )
// Launch default browser
// ----------------------------------------------------------------------------
#if defined(__WINDOWS__)
#if defined(__WINDOWS__) || \
defined(__WXX11__) || defined(__WXGTK__) || defined(__WXMOTIF__) || \
defined(__WXOSX__)
// implemented in a port-specific utils source file:
bool wxDoLaunchDefaultBrowser(const wxString& url, const wxString& scheme, int flags);
#elif defined(__WXX11__) || defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXOSX__)
// implemented in a port-specific utils source file:
bool wxDoLaunchDefaultBrowser(const wxString& url, int flags);
bool wxDoLaunchDefaultBrowser(const wxLaunchBrowserParams& params);
#else
// a "generic" implementation:
bool wxDoLaunchDefaultBrowser(const wxString& url, int flags)
bool wxDoLaunchDefaultBrowser(const wxLaunchBrowserParams& params)
{
// on other platforms try to use mime types or wxExecute...
@@ -1044,7 +1042,7 @@ bool wxDoLaunchDefaultBrowser(const wxString& url, int flags)
wxString mt;
ft->GetMimeType(&mt);
ok = ft->GetOpenCommand(&cmd, wxFileType::MessageParameters(url));
ok = ft->GetOpenCommand(&cmd, wxFileType::MessageParameters(params.url));
delete ft;
}
#endif // wxUSE_MIMETYPE
@@ -1053,7 +1051,7 @@ bool wxDoLaunchDefaultBrowser(const wxString& url, int flags)
{
// fallback to checking for the BROWSER environment variable
if ( !wxGetEnv(wxT("BROWSER"), &cmd) || cmd.empty() )
cmd << wxT(' ') << url;
cmd << wxT(' ') << params.url;
}
ok = ( !cmd.empty() && wxExecute(cmd) );
@@ -1067,90 +1065,54 @@ bool wxDoLaunchDefaultBrowser(const wxString& url, int flags)
}
#endif
static bool DoLaunchDefaultBrowserHelper(const wxString& urlOrig, int flags)
static bool DoLaunchDefaultBrowserHelper(const wxString& url, int flags)
{
// NOTE: we don't have to care about the wxBROWSER_NOBUSYCURSOR flag
// as it was already handled by wxLaunchDefaultBrowser
wxLaunchBrowserParams params(flags);
wxUnusedVar(flags);
wxString url(urlOrig), scheme;
wxURI uri(url);
const wxURI uri(url);
// this check is useful to avoid that wxURI recognizes as scheme parts of
// the filename, in case urlOrig is a local filename
// the filename, in case url is a local filename
// (e.g. "C:\\test.txt" when parsed by wxURI reports a scheme == "C")
bool hasValidScheme = uri.HasScheme() && uri.GetScheme().length() > 1;
#if defined(__WINDOWS__)
// NOTE: when testing wxMSW's wxLaunchDefaultBrowser all possible forms
// of the URL/flags should be tested; e.g.:
//
// for (int i=0; i<2; i++)
// {
// // test arguments without a valid URL scheme:
// wxLaunchDefaultBrowser("C:\\test.txt", i==0 ? 0 : wxBROWSER_NEW_WINDOW);
// wxLaunchDefaultBrowser("wxwidgets.org", i==0 ? 0 : wxBROWSER_NEW_WINDOW);
//
// // test arguments with different valid schemes:
// wxLaunchDefaultBrowser("file:/C%3A/test.txt", i==0 ? 0 : wxBROWSER_NEW_WINDOW);
// wxLaunchDefaultBrowser("http://wxwidgets.org", i==0 ? 0 : wxBROWSER_NEW_WINDOW);
// wxLaunchDefaultBrowser("mailto:user@host.org", i==0 ? 0 : wxBROWSER_NEW_WINDOW);
// }
// (assuming you have a C:\test.txt file)
if ( !hasValidScheme )
{
if (wxFileExists(urlOrig) || wxDirExists(urlOrig))
if (wxFileExists(url) || wxDirExists(url))
{
scheme = "file";
// do not prepend the file scheme to the URL as ShellExecuteEx() doesn't like it
params.scheme = "file";
params.path = url;
}
else
{
url.Prepend(wxS("http://"));
scheme = "http";
params.scheme = "http";
}
params.url << params.scheme << wxS("://") << url;
}
else if ( hasValidScheme )
{
scheme = uri.GetScheme();
params.url = url;
params.scheme = uri.GetScheme();
if ( uri.GetScheme() == "file" )
if ( params.scheme == "file" )
{
// TODO: extract URLToFileName() to some always compiled in
// function
#if wxUSE_FILESYSTEM
// ShellExecuteEx() doesn't like the "file" scheme when opening local files;
// remove it
url = wxFileSystem::URLToFileName(url).GetFullPath();
// for same reason as above, remove the scheme from the URL
params.path = wxFileSystem::URLToFileName(url).GetFullPath();
#endif // wxUSE_FILESYSTEM
}
}
if (wxDoLaunchDefaultBrowser(url, scheme, flags))
return true;
//else: call wxLogSysError
#else
if ( !hasValidScheme )
if ( !wxDoLaunchDefaultBrowser(params) )
{
// set the scheme of url to "http" or "file" if it does not have one
if (wxFileExists(urlOrig) || wxDirExists(urlOrig))
url.Prepend(wxS("file://"));
else
url.Prepend(wxS("http://"));
wxLogSysError(_("Failed to open URL \"%s\" in default browser."), url);
return false;
}
if (wxDoLaunchDefaultBrowser(url, flags))
return true;
//else: call wxLogSysError
#endif
wxLogSysError(_("Failed to open URL \"%s\" in default browser."),
url.c_str());
return false;
return true;
}
bool wxLaunchDefaultBrowser(const wxString& url, int flags)