WIP: Properly signal scheme errors

This commit is contained in:
Florian Bruhin 2018-07-10 00:55:29 +02:00 committed by Florian Bruhin
parent 2fcdc5a0c9
commit 92fcc523c5
5 changed files with 55 additions and 45 deletions

View File

@ -60,36 +60,39 @@ csrf_token = None
_HANDLERS = {}
class NoHandlerFound(Exception):
class Error(Exception):
"""Raised when no handler was found for the given URL."""
"""Exception for generic errors on a qute:// page."""
pass
class QuteSchemeOSError(Exception):
class NotFoundError(Error):
"""Called when there was an OSError inside a handler."""
"""Raised when the given URL was not found."""
pass
class QuteSchemeError(Exception):
class SchemeOSError(Error):
"""Exception to signal that a handler should return an ErrorReply.
"""Raised when there was an OSError inside a handler."""
Attributes correspond to the arguments in
networkreply.ErrorNetworkReply.
pass
Attributes:
errorstring: Error string to print.
error: Numerical error value.
"""
def __init__(self, errorstring, error):
self.errorstring = errorstring
self.error = error
super().__init__(errorstring)
class UrlInvalidError(Error):
"""Raised when an invalid URL was opened."""
pass
class RequestDeniedError(Error):
"""Raised when the request is forbidden."""
pass
class Redirect(Exception):
@ -180,13 +183,13 @@ def data_for_url(url):
try:
handler = _HANDLERS[host]
except KeyError:
raise NoHandlerFound(url)
raise NotFoundError("No handler found for {}".format(
url.toDisplayString()))
try:
mimetype, data = handler(url)
except OSError as e:
# FIXME:qtwebengine how to handle this?
raise QuteSchemeOSError(e)
raise SchemeOSError(e)
assert mimetype is not None, url
if mimetype == 'text/html' and isinstance(data, str):
@ -262,13 +265,13 @@ def qute_history(url):
offset = QUrlQuery(url).queryItemValue("offset")
offset = int(offset) if offset else None
except ValueError as e:
raise QuteSchemeError("Query parameter offset is invalid", e)
raise UrlInvalidError("Query parameter offset is invalid")
# Use start_time in query or current time.
try:
start_time = QUrlQuery(url).queryItemValue("start_time")
start_time = float(start_time) if start_time else time.time()
except ValueError as e:
raise QuteSchemeError("Query parameter start_time is invalid", e)
raise UrlInvalidError("Query parameter start_time is invalid")
return 'text/html', json.dumps(history_data(start_time, offset))
else:
@ -290,7 +293,7 @@ def qute_javascript(url):
path = "javascript" + os.sep.join(path.split('/'))
return 'text/html', utils.read_file(path, binary=False)
else:
raise QuteSchemeError("No file specified", ValueError())
raise UrlInvalidError("No file specified")
@add_handler('pyeval')
@ -379,7 +382,7 @@ def qute_help(url):
try:
bdata = utils.read_file(path, binary=True)
except OSError as e:
raise QuteSchemeOSError(e)
raise SchemeOSError(e)
mimetype, _encoding = mimetypes.guess_type(urlpath)
assert mimetype is not None, url
return mimetype, bdata
@ -461,8 +464,7 @@ def qute_settings(url):
if url.path() == '/set':
if url.password() != csrf_token:
message.error("Invalid CSRF token for qute://settings!")
raise QuteSchemeError("Invalid CSRF token!",
QNetworkReply.ContentAccessDenied)
raise RequestDeniedError("Invalid CSRF token!")
return _qute_settings_set(url)
# Requests to qute://settings/set should only be allowed from

View File

@ -80,16 +80,19 @@ class QuteSchemeHandler(QWebEngineUrlSchemeHandler):
log.misc.debug("Got request for {}".format(url.toDisplayString()))
try:
mimetype, data = qutescheme.data_for_url(url)
except qutescheme.NoHandlerFound:
log.misc.debug("No handler found for {}".format(
url.toDisplayString()))
except qutescheme.NotFoundError:
log.misc.exception("Error while handling qute://* URL")
job.fail(QWebEngineUrlRequestJob.UrlNotFound)
except qutescheme.QuteSchemeOSError:
# FIXME:qtwebengine how do we show a better error here?
except qutescheme.UrlInvalidError:
log.misc.exception("Error while handling qute://* URL")
job.fail(QWebEngineUrlRequestJob.UrlInvalid)
except qutescheme.RequestDeniedError:
log.misc.exception("Error while handling qute://* URL")
job.fail(QWebEngineUrlRequestJob.RequestDenied)
except qutescheme.SchemeOSError:
log.misc.exception("OSError while handling qute://* URL")
job.fail(QWebEngineUrlRequestJob.UrlNotFound)
except qutescheme.QuteSchemeError:
# FIXME:qtwebengine how do we show a better error here?
except qutescheme.Error:
log.misc.exception("Error while handling qute://* URL")
job.fail(QWebEngineUrlRequestJob.RequestFailed)
except qutescheme.Redirect as e:

View File

@ -59,15 +59,21 @@ def handler(request, operation, current_url):
try:
mimetype, data = qutescheme.data_for_url(url)
except qutescheme.NoHandlerFound:
errorstr = "No handler found for {}!".format(url.toDisplayString())
return networkreply.ErrorNetworkReply(
request, errorstr, QNetworkReply.ContentNotFoundError)
except qutescheme.QuteSchemeOSError as e:
except qutescheme.NotFoundError as e:
return networkreply.ErrorNetworkReply(
request, str(e), QNetworkReply.ContentNotFoundError)
except qutescheme.QuteSchemeError as e:
return networkreply.ErrorNetworkReply(request, e.errorstring, e.error)
except qutescheme.SchemeOSError as e:
return networkreply.ErrorNetworkReply(
request, str(e), QNetworkReply.ContentNotFoundError)
except qutescheme.UrlInvalidError as e:
return networkreply.ErrorNetworkReply(
request, str(e), QNetworkReply.ContentOperationNotPermittedError)
except qutescheme.RequestDeniedError as e:
return networkreply.ErrorNetworkReply(
request, str(e), QNetworkReply.ContentAccessDenied)
except qutescheme.Error as e:
return networkreply.ErrorNetworkReply(
request, str(e), QNetworkReply.InternalServerError)
except qutescheme.Redirect as e:
qtutils.ensure_valid(e.url)
return networkreply.RedirectNetworkReply(e.url)
@ -86,9 +92,8 @@ def qute_pdfjs(url):
# information, as the failed pdfjs requests are still in the log.
log.misc.warning(
"pdfjs resource requested but not found: {}".format(e.path))
raise qutescheme.QuteSchemeError("Can't find pdfjs resource "
"'{}'".format(e.path),
QNetworkReply.ContentNotFoundError)
raise qutescheme.NotFoundError("Can't find pdfjs resource '{}'".format(
e.path))
else:
mimetype, _encoding = mimetypes.guess_type(url.fileName())
assert mimetype is not None, url

View File

@ -61,13 +61,13 @@ class TestJavascriptHandler:
def test_qutejavascript_404(self):
url = QUrl("qute://javascript/404.js")
with pytest.raises(qutescheme.QuteSchemeOSError):
with pytest.raises(qutescheme.SchemeOSError):
qutescheme.data_for_url(url)
def test_qutejavascript_empty_query(self):
url = QUrl("qute://javascript")
with pytest.raises(qutescheme.QuteSchemeError):
with pytest.raises(qutescheme.InvalidURLError):
qutescheme.qute_javascript(url)

View File

@ -56,7 +56,7 @@ class TestPDFJSHandler:
def test_nonexisting_resource(self, caplog):
"""Test with a resource that does not exist."""
with caplog.at_level(logging.WARNING, 'misc'):
with pytest.raises(qutescheme.QuteSchemeError):
with pytest.raises(qutescheme.NotFoundError):
qutescheme.data_for_url(QUrl('qute://pdfjs/no/file.html'))
assert len(caplog.records) == 1
assert (caplog.records[0].message ==