diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py index 519a9432abe012..8ea851b32709da 100644 --- a/Lib/test/test_webbrowser.py +++ b/Lib/test/test_webbrowser.py @@ -328,5 +328,25 @@ def test_environment_preferred(self): self.assertEqual(webbrowser.get().name, sys.executable) +@unittest.skipIf(sys.platform[:3] != 'win', 'requires Windows') +class TestWindowsDefault(unittest.TestCase): + @mock.patch('os.startfile') + @mock.patch('os.access', return_value=False) + @mock.patch('os.path.isfile', return_value=True) + def test_do_run_startfile_for_local(self, mock_isfile, mock_access, mock_startfile): + webbrowser.WindowsDefault().open('file:///tmp/test.html') + mock_startfile.assert_called() + + @mock.patch('os.startfile') + def test_do_not_run_startfile_for_local_calc(self, mock_startfile): + webbrowser.WindowsDefault().open(sys.executable) + mock_startfile.assert_not_called() + + @mock.patch('os.startfile') + def test_do_run_startfile_with_external_resource(self, mock_startfile): + webbrowser.WindowsDefault().open('https://pythontest.net') + mock_startfile.assert_called() + + if __name__=='__main__': unittest.main() diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index 82bff835fdd0be..7acb2498ded580 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -8,6 +8,7 @@ import sys import subprocess import threading +import urllib.parse __all__ = ["Error", "open", "open_new", "open_new_tab", "get", "register"] @@ -576,9 +577,29 @@ def register_standard_browsers(): if sys.platform[:3] == "win": class WindowsDefault(BaseBrowser): + def _is_html(self, path): + HTML_EXTENSIONS = ( + '.html', '.htm', '.mht', '.mhtml', '.shtml', + '.xht', '.xhtml' + ) + return os.path.splitext(path)[-1] in HTML_EXTENSIONS + def open(self, url, new=0, autoraise=True): try: - os.startfile(url) + allowed_schemes = set( + urllib.parse.uses_relative + + urllib.parse.uses_netloc + + urllib.parse.uses_params) - set(['file', '']) + + parsed_url = urllib.parse.urlparse(url) + if parsed_url.scheme not in allowed_schemes: + path = parsed_url.path if parsed_url.scheme == 'file' else url + + if self._is_html(path): + os.startfile(url) + else: + os.startfile(url) + except OSError: # [Error 22] No application is associated with the specified # file for this operation: '' diff --git a/Misc/NEWS.d/next/Library/2019-02-19-10-50-22.bpo-36021.T83KHF.rst b/Misc/NEWS.d/next/Library/2019-02-19-10-50-22.bpo-36021.T83KHF.rst new file mode 100644 index 00000000000000..f8887ffcdbe2ee --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-02-19-10-50-22.bpo-36021.T83KHF.rst @@ -0,0 +1,2 @@ +WindowsDefault does not use os.startfile() when the location of the resource is +local file. Contributed by Stéphane Wirtel