diff --git a/doc/HACKING.asciidoc b/doc/HACKING.asciidoc index e33ac21ec..c531350b5 100644 --- a/doc/HACKING.asciidoc +++ b/doc/HACKING.asciidoc @@ -421,7 +421,8 @@ displaying it to the user. * Mention in the docstring whether your function needs a URL string or a `QUrl`. * Call `ensure_valid` from `utils.qtutils` whenever getting or creating a -`QUrl` and take appropriate action if not. +`QUrl` and take appropriate action if not. Note the URL of the current page +always could be an invalid QUrl (if nothing is loaded yet). Style conventions diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 86226af04..49855d79f 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -92,6 +92,11 @@ class CommandDispatcher: tab: Whether to open in a new tab. background: Whether to open in the background. """ + if not url.isValid(): + errstr = "Invalid URL {}" + if url.errorString(): + errstr += " - {}".format(url.errorString()) + raise cmdexc.CommandError(errstr) tabbed_browser = objreg.get('tabbed-browser') if tab and background: raise cmdexc.CommandError("Only one of -t/-b can be given!") @@ -715,9 +720,6 @@ class CommandDispatcher: """ urlstr = quickmarks.get(name) url = QUrl(urlstr) - if not url.isValid(): - raise cmdexc.CommandError("Invalid URL {} ({})".format( - urlstr, url.errorString())) self._open(url, tab, bg) @cmdutils.register(instance='command-dispatcher', name='inspector') diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index 46c3ea7db..b8584a64e 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -359,7 +359,9 @@ class DownloadManager(QObject): url: The URL to get, as QUrl page: The QWebPage to get the download from. """ - qtutils.ensure_valid(url) + if not url.isValid(): + urlutils.invalid_url_error(url, "start download") + return req = QNetworkRequest(url) reply = page.networkAccessManager().get(req) self.fetch(reply) diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index ae010d21f..3e6fc8a7b 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -327,7 +327,6 @@ class HintManager(QObject): Args: url: The URL to open as a QURL. """ - qtutils.ensure_valid(url) sel = self._context.target == Target.yank_primary mode = QClipboard.Selection if sel else QClipboard.Clipboard urlstr = url.toString(QUrl.FullyEncoded | QUrl.RemovePassword) @@ -341,7 +340,6 @@ class HintManager(QObject): Args: url: The URL to open as a QUrl. """ - qtutils.ensure_valid(url) urlstr = url.toDisplayString(QUrl.FullyEncoded) args = self._context.get_args(urlstr) message.set_cmd_text(' '.join(args)) @@ -357,19 +355,16 @@ class HintManager(QObject): message.error("No suitable link found for this element.", immediately=True) return - qtutils.ensure_valid(url) objreg.get('download-manager').get(url, elem.webFrame().page()) def _call_userscript(self, url): """Call an userscript from a hint.""" - qtutils.ensure_valid(url) cmd = self._context.args[0] args = self._context.args[1:] userscripts.run(cmd, *args, url=url) def _spawn(self, url): """Spawn a simple command from a hint.""" - qtutils.ensure_valid(url) urlstr = url.toString(QUrl.FullyEncoded | QUrl.RemovePassword) args = self._context.get_args(urlstr) subprocess.Popen(args) @@ -396,6 +391,7 @@ class HintManager(QObject): if baseurl is None: baseurl = self._context.baseurl url = baseurl.resolved(url) + qtutils.ensure_valid(url) return url def _find_prevnext(self, frame, prev=False): @@ -511,7 +507,6 @@ class HintManager(QObject): if url is None: raise cmdexc.CommandError("No {} links found!".format( "prev" if prev else "forward")) - qtutils.ensure_valid(url) if newtab: objreg.get('tabbed-browser').tabopen(url, background=False) else: diff --git a/qutebrowser/browser/quickmarks.py b/qutebrowser/browser/quickmarks.py index 4c91438f8..af357f228 100644 --- a/qutebrowser/browser/quickmarks.py +++ b/qutebrowser/browser/quickmarks.py @@ -64,7 +64,9 @@ def prompt_save(url): Args: url: The quickmark url as a QUrl. """ - qtutils.ensure_valid(url) + if not url.isValid(): + urlutils.invalid_url_error(url, "save quickmark") + return urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded) message.ask_async("Add quickmark:", usertypes.PromptMode.text, functools.partial(quickmark_add, urlstr)) diff --git a/qutebrowser/utils/urlutils.py b/qutebrowser/utils/urlutils.py index a7cb9661c..f95ac789b 100644 --- a/qutebrowser/utils/urlutils.py +++ b/qutebrowser/utils/urlutils.py @@ -28,7 +28,7 @@ from PyQt5.QtCore import QUrl from PyQt5.QtNetwork import QHostInfo from qutebrowser.config import config -from qutebrowser.utils import log, qtutils +from qutebrowser.utils import log, qtutils, message # FIXME: we probably could raise some exceptions on invalid URLs @@ -262,6 +262,17 @@ def qurl_from_user_input(urlstr): return QUrl('http://[{}]{}'.format(ipstr, rest)) +def invalid_url_error(url, action): + """Display an error message for an URL.""" + if url.isValid(): + raise ValueError("Calling invalid_url_error with valid URL {}".format( + url.toDisplayString())) + errstring = "Trying to {} with invalid URL".format(action) + if url.errorString(): + errstring += " - {}".format(url.errorString()) + message.error(errstring) + + class FuzzyUrlError(Exception): """Exception raised by fuzzy_url on problems.""" diff --git a/qutebrowser/widgets/tabbedbrowser.py b/qutebrowser/widgets/tabbedbrowser.py index cdeab74ff..4833a4aef 100644 --- a/qutebrowser/widgets/tabbedbrowser.py +++ b/qutebrowser/widgets/tabbedbrowser.py @@ -247,11 +247,13 @@ class TabbedBrowser(tabwidget.TabWidget): self._now_focused = None if tab is objreg.get('last-focused-tab', None): objreg.delete('last-focused-tab') - if not tab.cur_url.isEmpty(): - qtutils.ensure_valid(tab.cur_url) + if tab.cur_url.isValid(): history_data = qtutils.serialize(tab.history()) entry = UndoEntry(tab.cur_url, history_data) self._undo_stack.append(entry) + else: + urlutils.invalid_url_error(url, "saving tab") + return tab.shutdown() self._tabs.remove(tab) self.removeTab(idx) diff --git a/qutebrowser/widgets/webview.py b/qutebrowser/widgets/webview.py index 791483f9a..b7c712885 100644 --- a/qutebrowser/widgets/webview.py +++ b/qutebrowser/widgets/webview.py @@ -335,10 +335,13 @@ class WebView(QWebView): @pyqtSlot('QUrl') def on_url_changed(self, url): - """Update cur_url when URL has changed.""" - qtutils.ensure_valid(url) - self.cur_url = url - self.url_text_changed.emit(url.toDisplayString()) + """Update cur_url when URL has changed. + + If the URL is invalid, we just ignore it here. + """ + if url.isValid(): + self.cur_url = url + self.url_text_changed.emit(url.toDisplayString()) @pyqtSlot('QMouseEvent') def on_mouse_event(self, evt):