Be more forgiving when validating URLs. Fixes #141.

This commit is contained in:
Florian Bruhin 2014-10-03 16:58:30 +02:00
parent 18ff6ea06a
commit 4dcaa1fdec
8 changed files with 37 additions and 19 deletions

View File

@ -421,7 +421,8 @@ displaying it to the user.
* Mention in the docstring whether your function needs a URL string or a * Mention in the docstring whether your function needs a URL string or a
`QUrl`. `QUrl`.
* Call `ensure_valid` from `utils.qtutils` whenever getting or creating a * 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 Style conventions

View File

@ -92,6 +92,11 @@ class CommandDispatcher:
tab: Whether to open in a new tab. tab: Whether to open in a new tab.
background: Whether to open in the background. 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') tabbed_browser = objreg.get('tabbed-browser')
if tab and background: if tab and background:
raise cmdexc.CommandError("Only one of -t/-b can be given!") raise cmdexc.CommandError("Only one of -t/-b can be given!")
@ -715,9 +720,6 @@ class CommandDispatcher:
""" """
urlstr = quickmarks.get(name) urlstr = quickmarks.get(name)
url = QUrl(urlstr) url = QUrl(urlstr)
if not url.isValid():
raise cmdexc.CommandError("Invalid URL {} ({})".format(
urlstr, url.errorString()))
self._open(url, tab, bg) self._open(url, tab, bg)
@cmdutils.register(instance='command-dispatcher', name='inspector') @cmdutils.register(instance='command-dispatcher', name='inspector')

View File

@ -359,7 +359,9 @@ class DownloadManager(QObject):
url: The URL to get, as QUrl url: The URL to get, as QUrl
page: The QWebPage to get the download from. 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) req = QNetworkRequest(url)
reply = page.networkAccessManager().get(req) reply = page.networkAccessManager().get(req)
self.fetch(reply) self.fetch(reply)

View File

@ -327,7 +327,6 @@ class HintManager(QObject):
Args: Args:
url: The URL to open as a QURL. url: The URL to open as a QURL.
""" """
qtutils.ensure_valid(url)
sel = self._context.target == Target.yank_primary sel = self._context.target == Target.yank_primary
mode = QClipboard.Selection if sel else QClipboard.Clipboard mode = QClipboard.Selection if sel else QClipboard.Clipboard
urlstr = url.toString(QUrl.FullyEncoded | QUrl.RemovePassword) urlstr = url.toString(QUrl.FullyEncoded | QUrl.RemovePassword)
@ -341,7 +340,6 @@ class HintManager(QObject):
Args: Args:
url: The URL to open as a QUrl. url: The URL to open as a QUrl.
""" """
qtutils.ensure_valid(url)
urlstr = url.toDisplayString(QUrl.FullyEncoded) urlstr = url.toDisplayString(QUrl.FullyEncoded)
args = self._context.get_args(urlstr) args = self._context.get_args(urlstr)
message.set_cmd_text(' '.join(args)) message.set_cmd_text(' '.join(args))
@ -357,19 +355,16 @@ class HintManager(QObject):
message.error("No suitable link found for this element.", message.error("No suitable link found for this element.",
immediately=True) immediately=True)
return return
qtutils.ensure_valid(url)
objreg.get('download-manager').get(url, elem.webFrame().page()) objreg.get('download-manager').get(url, elem.webFrame().page())
def _call_userscript(self, url): def _call_userscript(self, url):
"""Call an userscript from a hint.""" """Call an userscript from a hint."""
qtutils.ensure_valid(url)
cmd = self._context.args[0] cmd = self._context.args[0]
args = self._context.args[1:] args = self._context.args[1:]
userscripts.run(cmd, *args, url=url) userscripts.run(cmd, *args, url=url)
def _spawn(self, url): def _spawn(self, url):
"""Spawn a simple command from a hint.""" """Spawn a simple command from a hint."""
qtutils.ensure_valid(url)
urlstr = url.toString(QUrl.FullyEncoded | QUrl.RemovePassword) urlstr = url.toString(QUrl.FullyEncoded | QUrl.RemovePassword)
args = self._context.get_args(urlstr) args = self._context.get_args(urlstr)
subprocess.Popen(args) subprocess.Popen(args)
@ -396,6 +391,7 @@ class HintManager(QObject):
if baseurl is None: if baseurl is None:
baseurl = self._context.baseurl baseurl = self._context.baseurl
url = baseurl.resolved(url) url = baseurl.resolved(url)
qtutils.ensure_valid(url)
return url return url
def _find_prevnext(self, frame, prev=False): def _find_prevnext(self, frame, prev=False):
@ -511,7 +507,6 @@ class HintManager(QObject):
if url is None: if url is None:
raise cmdexc.CommandError("No {} links found!".format( raise cmdexc.CommandError("No {} links found!".format(
"prev" if prev else "forward")) "prev" if prev else "forward"))
qtutils.ensure_valid(url)
if newtab: if newtab:
objreg.get('tabbed-browser').tabopen(url, background=False) objreg.get('tabbed-browser').tabopen(url, background=False)
else: else:

View File

@ -64,7 +64,9 @@ def prompt_save(url):
Args: Args:
url: The quickmark url as a QUrl. 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) urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
message.ask_async("Add quickmark:", usertypes.PromptMode.text, message.ask_async("Add quickmark:", usertypes.PromptMode.text,
functools.partial(quickmark_add, urlstr)) functools.partial(quickmark_add, urlstr))

View File

@ -28,7 +28,7 @@ from PyQt5.QtCore import QUrl
from PyQt5.QtNetwork import QHostInfo from PyQt5.QtNetwork import QHostInfo
from qutebrowser.config import config 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 # 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)) 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): class FuzzyUrlError(Exception):
"""Exception raised by fuzzy_url on problems.""" """Exception raised by fuzzy_url on problems."""

View File

@ -247,11 +247,13 @@ class TabbedBrowser(tabwidget.TabWidget):
self._now_focused = None self._now_focused = None
if tab is objreg.get('last-focused-tab', None): if tab is objreg.get('last-focused-tab', None):
objreg.delete('last-focused-tab') objreg.delete('last-focused-tab')
if not tab.cur_url.isEmpty(): if tab.cur_url.isValid():
qtutils.ensure_valid(tab.cur_url)
history_data = qtutils.serialize(tab.history()) history_data = qtutils.serialize(tab.history())
entry = UndoEntry(tab.cur_url, history_data) entry = UndoEntry(tab.cur_url, history_data)
self._undo_stack.append(entry) self._undo_stack.append(entry)
else:
urlutils.invalid_url_error(url, "saving tab")
return
tab.shutdown() tab.shutdown()
self._tabs.remove(tab) self._tabs.remove(tab)
self.removeTab(idx) self.removeTab(idx)

View File

@ -335,10 +335,13 @@ class WebView(QWebView):
@pyqtSlot('QUrl') @pyqtSlot('QUrl')
def on_url_changed(self, url): def on_url_changed(self, url):
"""Update cur_url when URL has changed.""" """Update cur_url when URL has changed.
qtutils.ensure_valid(url)
self.cur_url = url If the URL is invalid, we just ignore it here.
self.url_text_changed.emit(url.toDisplayString()) """
if url.isValid():
self.cur_url = url
self.url_text_changed.emit(url.toDisplayString())
@pyqtSlot('QMouseEvent') @pyqtSlot('QMouseEvent')
def on_mouse_event(self, evt): def on_mouse_event(self, evt):