Move download origin handling to DownloadItem

This commit is contained in:
Florian Bruhin 2021-08-25 09:16:54 +02:00
parent c022893a76
commit d6306783d0
5 changed files with 52 additions and 16 deletions

View File

@ -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: <<types,Bool>>
Default: +pass:[true]+

View File

@ -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.

View File

@ -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

View File

@ -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!

View File

@ -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.