From d6306783d097d9d53405b75ebecb706b8e13668c Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 25 Aug 2021 09:16:54 +0200 Subject: Move download origin handling to DownloadItem --- doc/help/settings.asciidoc | 2 -- qutebrowser/browser/downloads.py | 34 +++++++++++++++++++++- qutebrowser/browser/qtnetworkdownloads.py | 14 +++++++++ .../browser/webengine/webenginedownloads.py | 17 ++++------- qutebrowser/config/configdata.yml | 1 - 5 files changed, 52 insertions(+), 16 deletions(-) diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index 1e943c235..a069ffdda 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -2896,8 +2896,6 @@ For per-domain settings, the relevant URL is the URL initiating the download, no This setting supports URL patterns. -This setting is only available with the QtWebEngine backend. - Type: <> Default: +pass:[true]+ diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index fa4ac9da2..4f7897c9d 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -611,7 +611,11 @@ class AbstractDownloadItem(QObject): message.error(str(e)) def url(self) -> QUrl: - """Get the download's origin URL.""" + """Get the download's URL (i.e. where the file is downloaded from).""" + raise NotImplementedError + + def origin(self) -> QUrl: + """Get the download's origin URL (i.e. the page starting the download).""" raise NotImplementedError def _get_open_filename(self): @@ -819,6 +823,34 @@ class AbstractDownloadItem(QObject): self.pdfjs_requested.emit(os.path.basename(filename), self.url()) + def cancel_for_origin(self) -> bool: + """Cancel the download based on URL/origin. + + For some special cases, we want to cancel downloads immediately, before + downloading: + + - file:// downloads from file:// URLs (open the file instead) + - http:// downloads from https:// URLs (mixed content) + """ + origin = self.origin() + url = self.url() + if not origin.isValid(): + return False + + if url.scheme() == "file" and origin.scheme() == "file": + utils.open_file(url.toLocalFile()) + self.cancel() + return True + + if (url.scheme() == "http" and + origin.isValid() and origin.scheme() == "https" and + config.instance.get("downloads.prevent_mixed_content", url=origin)): + self._die("Aborting insecure download from secure page " + "(see downloads.prevent_mixed_content).") + return True + + return False + def set_target(self, target): """Set the target for a given download. diff --git a/qutebrowser/browser/qtnetworkdownloads.py b/qutebrowser/browser/qtnetworkdownloads.py index e178fb0e5..f048d293d 100644 --- a/qutebrowser/browser/qtnetworkdownloads.py +++ b/qutebrowser/browser/qtnetworkdownloads.py @@ -202,6 +202,17 @@ class DownloadItem(downloads.AbstractDownloadItem): # Note: self._reply is deleted when the download finishes return self._url + def origin(self) -> QUrl: + if self._reply is None: + return QUrl() + origin = self._reply.request().originatingObject() + try: + return origin.url() + except AttributeError: + # Raised either if origin is None or some object that doesn't + # have its own url. + return QUrl() + def _ensure_can_set_filename(self, filename): if self.fileobj is not None: # pragma: no cover raise ValueError("fileobj was already set! filename: {}, " @@ -549,6 +560,9 @@ class DownloadManager(downloads.AbstractDownloadManager): download = DownloadItem(reply, manager=self) self._init_item(download, auto_remove, suggested_filename) + if download.cancel_for_origin(): + return download + if target is not None: download.set_target(target) return download diff --git a/qutebrowser/browser/webengine/webenginedownloads.py b/qutebrowser/browser/webengine/webenginedownloads.py index 364347206..f216f9e67 100644 --- a/qutebrowser/browser/webengine/webenginedownloads.py +++ b/qutebrowser/browser/webengine/webenginedownloads.py @@ -120,6 +120,10 @@ class DownloadItem(downloads.AbstractDownloadItem): def url(self) -> QUrl: return self._qt_item.url() + def origin(self) -> QUrl: + page = self._qt_item.page() + return page.url() if page else QUrl() + def _set_fileobj(self, fileobj, *, autoclose=True): raise downloads.UnsupportedOperationError @@ -294,18 +298,7 @@ class DownloadManager(downloads.AbstractDownloadManager): download.set_target(target) return - if url.scheme() == "file" and origin.isValid() and origin.scheme() == "file": - utils.open_file(url.toLocalFile()) - qt_item.cancel() - return - - if (url.scheme() == "http" and - origin.isValid() and origin.scheme() == "https" and - config.instance.get("downloads.prevent_mixed_content", url=origin)): - # FIXME show failed download instead - message.error("Aborting insecure download from secure page " - "(see downloads.prevent_mixed_content).") - qt_item.cancel() + if download.cancel_for_origin(): return # Ask the user for a filename - needs to be blocking! diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 7b0cd05f4..e62fa6f9f 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -1359,7 +1359,6 @@ downloads.prevent_mixed_content: type: Bool default: true supports_pattern: true - backend: QtWebEngine desc: Automatically abort insecure (HTTP) downloads originating from secure (HTTPS) pages. -- cgit v1.2.3-54-g00ecf