def get_request(self, request, *, target=None, suggested_fn=None, **kwargs): """Start a download with a QNetworkRequest. Args: request: The QNetworkRequest to download. target: Where to save the download as downloads.DownloadTarget. **kwargs: Passed to _fetch_request. Return: The created DownloadItem. """ # WORKAROUND for Qt corrupting data loaded from cache: # https://bugreports.qt.io/browse/QTBUG-42757 request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.AlwaysNetwork) if suggested_fn is not None: pass elif request.url().scheme().lower() != 'data': suggested_fn = urlutils.filename_from_url(request.url()) else: # We might be downloading a binary blob embedded on a page or even # generated dynamically via javascript. We try to figure out a more # sensible name than the base64 content of the data. origin = request.originatingObject() try: origin_url = origin.url() except AttributeError: # Raised either if origin is None or some object that doesn't # have its own url. We're probably fine with a default fallback # then. suggested_fn = 'binary blob' else: # Use the originating URL as a base for the filename (works # e.g. for pdf.js). suggested_fn = urlutils.filename_from_url(origin_url) if suggested_fn is None: suggested_fn = 'qutebrowser-download' return self._fetch_request(request, target=target, suggested_filename=suggested_fn, **kwargs)
def get_request(self, request, page=None, fileobj=None, filename=None): """Start a download with a QNetworkRequest. Args: request: The QNetworkRequest to download. page: The QWebPage to use. fileobj: The file object to write the answer to. filename: A path to write the data to. Return: If the download could start immediately, (fileobj/filename given), the created DownloadItem. If not, None. """ if fileobj is not None and filename is not None: raise TypeError("Only one of fileobj/filename may be given!") # WORKAROUND for Qt corrupting data loaded from cache: # https://bugreports.qt-project.org/browse/QTBUG-42757 request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.AlwaysNetwork) if fileobj is not None or filename is not None: return self.fetch_request(request, filename, fileobj, page) q = self._prepare_question() q.default = urlutils.filename_from_url(request.url()) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) q.answered.connect( lambda fn: self.fetch_request(request, filename=fn, page=page)) message_bridge.ask(q, blocking=False) return None
def get_request(self, request, *, fileobj=None, filename=None, prompt_download_directory=None, **kwargs): """Start a download with a QNetworkRequest. Args: request: The QNetworkRequest to download. fileobj: The file object to write the answer to. filename: A path to write the data to. prompt_download_directory: Whether to prompt for the download dir or automatically download. If None, the config is used. **kwargs: Passed to fetch_request. Return: If the download could start immediately, (fileobj/filename given), the created DownloadItem. If not, None. """ if fileobj is not None and filename is not None: raise TypeError("Only one of fileobj/filename may be given!") # WORKAROUND for Qt corrupting data loaded from cache: # https://bugreports.qt.io/browse/QTBUG-42757 request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.AlwaysNetwork) suggested_fn = urlutils.filename_from_url(request.url()) if prompt_download_directory is None: prompt_download_directory = config.get( 'storage', 'prompt-download-directory') if not prompt_download_directory and not fileobj: filename = config.get('storage', 'download-directory') if fileobj is not None or filename is not None: return self.fetch_request(request, fileobj=fileobj, filename=filename, suggested_filename=suggested_fn, **kwargs) if suggested_fn is None: suggested_fn = 'qutebrowser-download' else: encoding = sys.getfilesystemencoding() suggested_fn = utils.force_encoding(suggested_fn, encoding) q = self._prepare_question() q.default = _path_suggestion(suggested_fn) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) q.answered.connect(lambda fn: self.fetch_request( request, filename=fn, suggested_filename=suggested_fn, **kwargs)) message_bridge.ask(q, blocking=False) return None
def handle_download(self, qt_item): """Start a download coming from a QWebEngineProfile.""" qt_filename = os.path.basename(qt_item.path()) # FIXME use 5.14 API mime_type = qt_item.mimeType() url = qt_item.url() # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-90355 if version.qtwebengine_versions().webengine >= utils.VersionNumber( 5, 15, 3): needs_workaround = False elif url.scheme().lower() == 'data': if '/' in url.path().split(',')[-1]: # e.g. a slash in base64 wrong_filename = url.path().split('/')[-1] else: wrong_filename = mime_type.split('/')[1] needs_workaround = qt_filename == wrong_filename else: needs_workaround = False if needs_workaround: suggested_filename = urlutils.filename_from_url( url, fallback='qutebrowser-download') else: suggested_filename = _strip_suffix(qt_filename) use_pdfjs = pdfjs.should_use_pdfjs(mime_type, url) download = DownloadItem(qt_item, manager=self) self._init_item(download, auto_remove=use_pdfjs, suggested_filename=suggested_filename) if self._mhtml_target is not None: download.set_target(self._mhtml_target) self._mhtml_target = None return if use_pdfjs: download.set_target(downloads.PDFJSDownloadTarget()) return filename = downloads.immediate_download_path() if filename is not None: # User doesn't want to be asked, so just use the download_dir target = downloads.FileDownloadTarget(filename) download.set_target(target) return if download.cancel_for_origin(): return # Ask the user for a filename - needs to be blocking! question = downloads.get_filename_question( suggested_filename=suggested_filename, url=qt_item.url(), parent=self) self._init_filename_question(question, download) message.global_bridge.ask(question, blocking=True)
def get_request(self, request, *, fileobj=None, filename=None, prompt_download_directory=None, **kwargs): """Start a download with a QNetworkRequest. Args: request: The QNetworkRequest to download. fileobj: The file object to write the answer to. filename: A path to write the data to. prompt_download_directory: Whether to prompt for the download dir or automatically download. If None, the config is used. **kwargs: Passed to fetch_request. Return: If the download could start immediately, (fileobj/filename given), the created DownloadItem. If not, None. """ if fileobj is not None and filename is not None: raise TypeError("Only one of fileobj/filename may be given!") # WORKAROUND for Qt corrupting data loaded from cache: # https://bugreports.qt.io/browse/QTBUG-42757 request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.AlwaysNetwork) suggested_fn = urlutils.filename_from_url(request.url()) if prompt_download_directory is None: prompt_download_directory = config.get( 'storage', 'prompt-download-directory') if not prompt_download_directory and not fileobj: filename = config.get('storage', 'download-directory') if fileobj is not None or filename is not None: return self.fetch_request(request, fileobj=fileobj, filename=filename, suggested_filename=suggested_fn, **kwargs) if suggested_fn is None: suggested_fn = 'qutebrowser-download' else: encoding = sys.getfilesystemencoding() suggested_fn = utils.force_encoding(suggested_fn, encoding) q = self._prepare_question() q.default = _path_suggestion(suggested_fn) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) q.answered.connect( lambda fn: self.fetch_request(request, filename=fn, suggested_filename=suggested_fn, **kwargs)) message_bridge.ask(q, blocking=False) return None
def get_request(self, request, *, fileobj=None, filename=None, prompt_download_directory=None, **kwargs): """Start a download with a QNetworkRequest. Args: request: The QNetworkRequest to download. fileobj: The file object to write the answer to. filename: A path to write the data to. prompt_download_directory: Whether to prompt for the download dir or automatically download. If None, the config is used. **kwargs: Passed to fetch_request. Return: If the download could start immediately, (fileobj/filename given), the created DownloadItem. If not, None. """ if fileobj is not None and filename is not None: raise TypeError("Only one of fileobj/filename may be given!") # WORKAROUND for Qt corrupting data loaded from cache: # https://bugreports.qt.io/browse/QTBUG-42757 request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.AlwaysNetwork) suggested_fn = urlutils.filename_from_url(request.url()) if suggested_fn is None: suggested_fn = 'qutebrowser-download' # We won't need a question if a filename or fileobj is already given if fileobj is None and filename is None: filename, q = ask_for_filename( suggested_fn, self._win_id, parent=self, prompt_download_directory=prompt_download_directory) if fileobj is not None or filename is not None: return self.fetch_request(request, fileobj=fileobj, filename=filename, suggested_filename=suggested_fn, **kwargs) q.answered.connect(lambda fn: self.fetch_request( request, filename=fn, suggested_filename=suggested_fn, **kwargs)) self._postprocess_question(q) q.ask() return None
def get_request(self, request, *, fileobj=None, filename=None, prompt_download_directory=None, **kwargs): """Start a download with a QNetworkRequest. Args: request: The QNetworkRequest to download. fileobj: The file object to write the answer to. filename: A path to write the data to. prompt_download_directory: Whether to prompt for the download dir or automatically download. If None, the config is used. **kwargs: Passed to fetch_request. Return: If the download could start immediately, (fileobj/filename given), the created DownloadItem. If not, None. """ if fileobj is not None and filename is not None: raise TypeError("Only one of fileobj/filename may be given!") # WORKAROUND for Qt corrupting data loaded from cache: # https://bugreports.qt.io/browse/QTBUG-42757 request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.AlwaysNetwork) suggested_fn = urlutils.filename_from_url(request.url()) if suggested_fn is None: suggested_fn = 'qutebrowser-download' # We won't need a question if a filename or fileobj is already given if fileobj is None and filename is None: filename, q = ask_for_filename( suggested_fn, self._win_id, parent=self, prompt_download_directory=prompt_download_directory ) if fileobj is not None or filename is not None: return self.fetch_request(request, fileobj=fileobj, filename=filename, suggested_filename=suggested_fn, **kwargs) q.answered.connect( lambda fn: self.fetch_request(request, filename=fn, suggested_filename=suggested_fn, **kwargs)) self._postprocess_question(q) q.ask() return None
def _get_suggested_filename(self, request): """Get the suggested filename for the given request.""" filename_url = request.url() if request.url().scheme().lower() == 'data': # We might be downloading a binary blob embedded on a page or even # generated dynamically via javascript. If we happen to know where it's # coming from, we can try to figure out a more sensible name than the base64 # content of the data. origin = request.originatingObject() try: filename_url = origin.url() except AttributeError: # Raised either if origin is None or some object that doesn't # have its own url. We're probably fine with a default fallback # based on the data URL then. pass return urlutils.filename_from_url(filename_url, fallback='qutebrowser-download')
def get_request(self, request, page=None, fileobj=None, filename=None, auto_remove=False): """Start a download with a QNetworkRequest. Args: request: The QNetworkRequest to download. page: The QWebPage to use. fileobj: The file object to write the answer to. filename: A path to write the data to. auto_remove: Whether to remove the download even if ui -> remove-finished-downloads is set to false. Return: If the download could start immediately, (fileobj/filename given), the created DownloadItem. If not, None. """ if fileobj is not None and filename is not None: raise TypeError("Only one of fileobj/filename may be given!") # WORKAROUND for Qt corrupting data loaded from cache: # https://bugreports.qt-project.org/browse/QTBUG-42757 request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.AlwaysNetwork) suggested_fn = urlutils.filename_from_url(request.url()) if fileobj is not None or filename is not None: return self.fetch_request(request, page, fileobj, filename, auto_remove, suggested_fn) if suggested_fn is None: suggested_fn = 'qutebrowser-download' else: encoding = sys.getfilesystemencoding() suggested_fn = utils.force_encoding(suggested_fn, encoding) q = self._prepare_question() q.default = _path_suggestion(suggested_fn) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) q.answered.connect( lambda fn: self.fetch_request(request, page, filename=fn, auto_remove=auto_remove, suggested_filename=suggested_fn)) message_bridge.ask(q, blocking=False) return None
def handle_download(self, qt_item): """Start a download coming from a QWebEngineProfile.""" if qt_item.url().scheme().lower() == 'data': # WORKAROUND for an unknown QtWebEngine bug (?) which gives us base64 data # as filename. suggested_filename = urlutils.filename_from_url( qt_item.url(), fallback='qutebrowser-download') else: suggested_filename = _get_suggested_filename(qt_item.path()) use_pdfjs = pdfjs.should_use_pdfjs(qt_item.mimeType(), qt_item.url()) download = DownloadItem(qt_item, manager=self) self._init_item(download, auto_remove=use_pdfjs, suggested_filename=suggested_filename) if self._mhtml_target is not None: download.set_target(self._mhtml_target) self._mhtml_target = None return if use_pdfjs: download.set_target(downloads.PDFJSDownloadTarget()) return filename = downloads.immediate_download_path() if filename is not None: # User doesn't want to be asked, so just use the download_dir target = downloads.FileDownloadTarget(filename) download.set_target(target) return # Ask the user for a filename - needs to be blocking! question = downloads.get_filename_question( suggested_filename=suggested_filename, url=qt_item.url(), parent=self) self._init_filename_question(question, download) message.global_bridge.ask(question, blocking=True)
def test_invalid_url(self): """Test with an invalid QUrl.""" assert urlutils.filename_from_url(QUrl()) is None
def test_url_host(self): """Test with an URL with no path.""" url = QUrl('http://qutebrowser.org/') self.assertEqual(urlutils.filename_from_url(url), 'qutebrowser.org.html')
def test_invalid_url(self): """Test with an invalid QUrl.""" self.assertEqual(urlutils.filename_from_url(QUrl()), None)
def test_filename_from_url_fallback(qurl): assert urlutils.filename_from_url(qurl, fallback='fallback') == 'fallback'
def test_filename_from_url(qurl, output): assert urlutils.filename_from_url(qurl) == output
def get_request(self, request, *, fileobj=None, filename=None, prompt_download_directory=None, **kwargs): """Start a download with a QNetworkRequest. Args: request: The QNetworkRequest to download. fileobj: The file object to write the answer to. filename: A path to write the data to. prompt_download_directory: Whether to prompt for the download dir or automatically download. If None, the config is used. **kwargs: Passed to fetch_request. Return: If the download could start immediately, (fileobj/filename given), the created DownloadItem. If not, None. """ if fileobj is not None and filename is not None: raise TypeError("Only one of fileobj/filename may be given!") # WORKAROUND for Qt corrupting data loaded from cache: # https://bugreports.qt.io/browse/QTBUG-42757 request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.AlwaysNetwork) if request.url().scheme().lower() != 'data': suggested_fn = urlutils.filename_from_url(request.url()) else: # We might be downloading a binary blob embedded on a page or even # generated dynamically via javascript. We try to figure out a more # sensible name than the base64 content of the data. origin = request.originatingObject() try: origin_url = origin.url() except AttributeError: # Raised either if origin is None or some object that doesn't # have its own url. We're probably fine with a default fallback # then. suggested_fn = 'binary blob' else: # Use the originating URL as a base for the filename (works # e.g. for pdf.js). suggested_fn = urlutils.filename_from_url(origin_url) if suggested_fn is None: suggested_fn = 'qutebrowser-download' # We won't need a question if a filename or fileobj is already given if fileobj is None and filename is None: filename, q = ask_for_filename( suggested_fn, self._win_id, parent=self, prompt_download_directory=prompt_download_directory ) if fileobj is not None or filename is not None: return self.fetch_request(request, fileobj=fileobj, filename=filename, suggested_filename=suggested_fn, **kwargs) q.answered.connect( lambda fn: self.fetch_request(request, filename=fn, suggested_filename=suggested_fn, **kwargs)) self._postprocess_question(q) q.ask() return None
def test_url_path(self): """Test with an URL with path.""" url = QUrl('http://qutebrowser.org/test.html') assert urlutils.filename_from_url(url) == 'test.html'