Beispiel #1
0
    def on_unsupported_content(self, reply):
        """Handle an unsupportedContent signal.

        Most likely this will mean we need to download the reply, but we
        correct for some common errors the server do.

        At some point we might want to implement the MIME Sniffing standard
        here: http://mimesniff.spec.whatwg.org/
        """
        inline, suggested_filename = http.parse_content_disposition(reply)
        download_manager = objreg.get('qtnetwork-download-manager')
        if not inline:
            # Content-Disposition: attachment -> force download
            download_manager.fetch(reply,
                                   suggested_filename=suggested_filename)
            return
        mimetype, _rest = http.parse_content_type(reply)
        if mimetype == 'image/jpg':
            # Some servers (e.g. the LinkedIn CDN) send a non-standard
            # image/jpg (instead of image/jpeg, defined in RFC 1341 section
            # 7.5). If this is the case, we force displaying with a corrected
            # mimetype.
            if reply.isFinished():
                self.display_content(reply, 'image/jpeg')
            else:
                reply.finished.connect(functools.partial(
                    self.display_content, reply, 'image/jpeg'))
        elif pdfjs.should_use_pdfjs(mimetype, reply.url()):
            download_manager.fetch(reply,
                                   target=downloads.PDFJSDownloadTarget(),
                                   auto_remove=True)
        else:
            # Unknown mimetype, so download anyways.
            download_manager.fetch(reply,
                                   suggested_filename=suggested_filename)
 def check_unnamed(self, header):
     """Check if the passed header results in an unnamed attachment."""
     reply = self.stubs.FakeNetworkReply(
         headers={'Content-Disposition': header})
     cd_inline, cd_filename = http.parse_content_disposition(reply)
     assert cd_filename == DEFAULT_NAME
     assert not cd_inline
 def check_unnamed(self, header):
     """Check if the passed header results in an unnamed attachment."""
     reply = self.stubs.FakeNetworkReply(
         headers={'Content-Disposition': header})
     cd_inline, cd_filename = http.parse_content_disposition(reply)
     assert cd_filename == DEFAULT_NAME
     assert not cd_inline
Beispiel #4
0
    def on_unsupported_content(self, reply):
        """Handle an unsupportedContent signal.

        Most likely this will mean we need to download the reply, but we
        correct for some common errors the server do.

        At some point we might want to implement the MIME Sniffing standard
        here: https://mimesniff.spec.whatwg.org/
        """
        inline, suggested_filename = http.parse_content_disposition(reply)
        download_manager = objreg.get('qtnetwork-download-manager')
        if not inline:
            # Content-Disposition: attachment -> force download
            download_manager.fetch(reply,
                                   suggested_filename=suggested_filename)
            return
        mimetype, _rest = http.parse_content_type(reply)
        if mimetype == 'image/jpg':
            # Some servers (e.g. the LinkedIn CDN) send a non-standard
            # image/jpg (instead of image/jpeg, defined in RFC 1341 section
            # 7.5). If this is the case, we force displaying with a corrected
            # mimetype.
            if reply.isFinished():
                self.display_content(reply, 'image/jpeg')
            else:
                reply.finished.connect(functools.partial(
                    self.display_content, reply, 'image/jpeg'))
        elif pdfjs.should_use_pdfjs(mimetype, reply.url()):
            download_manager.fetch(reply,
                                   target=downloads.PDFJSDownloadTarget(),
                                   auto_remove=True)
        else:
            # Unknown mimetype, so download anyways.
            download_manager.fetch(reply,
                                   suggested_filename=suggested_filename)
 def check_filename(self, header, filename, expected_inline=False):
     """Check if the passed header has the given filename."""
     reply = self.stubs.FakeNetworkReply(
         headers={'Content-Disposition': header})
     cd_inline, cd_filename = http.parse_content_disposition(reply)
     assert cd_filename is not None
     assert cd_filename == filename
     assert cd_inline == expected_inline
 def check_filename(self, header, filename, expected_inline=False):
     """Check if the passed header has the given filename."""
     reply = self.stubs.FakeNetworkReply(
         headers={'Content-Disposition': header})
     cd_inline, cd_filename = http.parse_content_disposition(reply)
     assert cd_filename is not None
     assert cd_filename == filename
     assert cd_inline == expected_inline
 def check_ignored(self, header):
     """Check if the passed header is ignored."""
     reply = self.stubs.FakeNetworkReply(
         headers={'Content-Disposition': header})
     with self.caplog.at_level(logging.ERROR, 'network'):
         cd_inline, cd_filename = http.parse_content_disposition(reply)
     assert cd_filename == DEFAULT_NAME
     assert cd_inline
 def check_ignored(self, header):
     """Check if the passed header is ignored."""
     reply = self.stubs.FakeNetworkReply(
         headers={'Content-Disposition': header})
     with self.caplog.at_level(logging.ERROR, 'rfc6266'):
         # with self.assertLogs(log.rfc6266, logging.ERROR):
         cd_inline, cd_filename = http.parse_content_disposition(reply)
     assert cd_filename == DEFAULT_NAME
     assert cd_inline
    def fetch(self,
              reply,
              *,
              target=None,
              auto_remove=False,
              suggested_filename=None,
              prompt_download_directory=None):
        """Download a QNetworkReply to disk.

        Args:
            reply: The QNetworkReply to download.
            target: Where to save the download as downloads.DownloadTarget.
            auto_remove: Whether to remove the download even if
                         downloads.remove_finished is set to -1.
            suggested_filename: The filename to use for the file.
            prompt_download_directory: Whether to prompt for a location to
                                       download the file to.

        Return:
            The created DownloadItem.
        """
        if not suggested_filename:
            try:
                suggested_filename = target.suggested_filename()
            except downloads.NoFilenameError:
                _, suggested_filename = http.parse_content_disposition(reply)
        log.downloads.debug("fetch: {} -> {}".format(reply.url(),
                                                     suggested_filename))
        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

        # Neither filename nor fileobj were given

        filename = downloads.immediate_download_path(prompt_download_directory)
        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 download

        # Ask the user for a filename
        question = downloads.get_filename_question(
            suggested_filename=suggested_filename,
            url=reply.url(),
            parent=self)
        self._init_filename_question(question, download)
        message.global_bridge.ask(question, blocking=False)

        return download
    def test_attonly(self, stubs):
        """'attachment' only.

        UA should offer to download the resource.
        """
        reply = stubs.FakeNetworkReply(
            headers={'Content-Disposition': 'attachment'})
        cd_inline, cd_filename = http.parse_content_disposition(reply)
        assert not cd_inline
        assert cd_filename == DEFAULT_NAME
    def test_attonly(self, stubs):
        """'attachment' only.

        UA should offer to download the resource.
        """
        reply = stubs.FakeNetworkReply(
            headers={'Content-Disposition': 'attachment'})
        cd_inline, cd_filename = http.parse_content_disposition(reply)
        assert not cd_inline
        assert cd_filename == DEFAULT_NAME
    def fetch(self, reply, *, target=None, auto_remove=False,
              suggested_filename=None, prompt_download_directory=None):
        """Download a QNetworkReply to disk.

        Args:
            reply: The QNetworkReply to download.
            target: Where to save the download as downloads.DownloadTarget.
            auto_remove: Whether to remove the download even if
                         downloads.remove_finished is set to -1.

        Return:
            The created DownloadItem.
        """
        if not suggested_filename:
            try:
                suggested_filename = target.suggested_filename()
            except downloads.NoFilenameError:
                _, suggested_filename = http.parse_content_disposition(reply)
        log.downloads.debug("fetch: {} -> {}".format(reply.url(),
                                                     suggested_filename))
        download = DownloadItem(reply, manager=self)
        self._init_item(download, auto_remove, suggested_filename)

        if target is not None:
            download.set_target(target)
            return download

        # Neither filename nor fileobj were given

        filename = downloads.immediate_download_path(prompt_download_directory)
        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 download

        # Ask the user for a filename
        question = downloads.get_filename_question(
            suggested_filename=suggested_filename, url=reply.url(),
            parent=self)
        self._init_filename_question(question, download)
        message.global_bridge.ask(question, blocking=False)

        return download
Beispiel #13
0
    def on_unsupported_content(self, reply):
        """Handle an unsupportedContent signal.

        Most likely this will mean we need to download the reply, but we
        correct for some common errors the server do.

        At some point we might want to implement the MIME Sniffing standard
        here: http://mimesniff.spec.whatwg.org/
        """
        inline, suggested_filename = http.parse_content_disposition(reply)
        download_manager = objreg.get('qtnetwork-download-manager',
                                      scope='window',
                                      window=self._win_id)
        if not inline:
            # Content-Disposition: attachment -> force download
            download_manager.fetch(reply,
                                   suggested_filename=suggested_filename)
            return
        mimetype, _rest = http.parse_content_type(reply)
        if mimetype == 'image/jpg':
            # Some servers (e.g. the LinkedIn CDN) send a non-standard
            # image/jpg (instead of image/jpeg, defined in RFC 1341 section
            # 7.5). If this is the case, we force displaying with a corrected
            # mimetype.
            if reply.isFinished():
                self.display_content(reply, 'image/jpeg')
            else:
                reply.finished.connect(
                    functools.partial(self.display_content, reply,
                                      'image/jpeg'))
        elif (mimetype in ['application/pdf', 'application/x-pdf']
              and config.val.content.pdfjs):
            # Use pdf.js to display the page
            self._show_pdfjs(reply)
        else:
            # Unknown mimetype, so download anyways.
            download_manager.fetch(reply,
                                   suggested_filename=suggested_filename)
Beispiel #14
0
    def on_unsupported_content(self, reply):
        """Handle an unsupportedContent signal.

        Most likely this will mean we need to download the reply, but we
        correct for some common errors the server do.

        At some point we might want to implement the MIME Sniffing standard
        here: http://mimesniff.spec.whatwg.org/
        """
        inline, suggested_filename = http.parse_content_disposition(reply)
        download_manager = objreg.get('download-manager', scope='window',
                                      window=self._win_id)
        if not inline:
            # Content-Disposition: attachment -> force download
            download_manager.fetch(reply,
                                   suggested_filename=suggested_filename)
            return
        mimetype, _rest = http.parse_content_type(reply)
        if mimetype == 'image/jpg':
            # Some servers (e.g. the LinkedIn CDN) send a non-standard
            # image/jpg (instead of image/jpeg, defined in RFC 1341 section
            # 7.5). If this is the case, we force displaying with a corrected
            # mimetype.
            if reply.isFinished():
                self.display_content(reply, 'image/jpeg')
            else:
                reply.finished.connect(functools.partial(
                    self.display_content, reply, 'image/jpeg'))
        elif (mimetype in ['application/pdf', 'application/x-pdf'] and
              config.get('content', 'enable-pdfjs')):
            # Use pdf.js to display the page
            self._show_pdfjs(reply)
        else:
            # Unknown mimetype, so download anyways.
            download_manager.fetch(reply,
                                   suggested_filename=suggested_filename)
Beispiel #15
0
    def fetch(self,
              reply,
              *,
              fileobj=None,
              filename=None,
              auto_remove=False,
              suggested_filename=None,
              prompt_download_directory=None):
        """Download a QNetworkReply to disk.

        Args:
            reply: The QNetworkReply to download.
            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 -1.

        Return:
            The created DownloadItem.
        """
        if fileobj is not None and filename is not None:  # pragma: no cover
            raise TypeError("Only one of fileobj/filename may be given!")
        if not suggested_filename:
            if filename is not None:
                suggested_filename = os.path.basename(filename)
            elif fileobj is not None and getattr(fileobj, 'name', None):
                suggested_filename = fileobj.name
            else:
                _, suggested_filename = http.parse_content_disposition(reply)
        log.downloads.debug("fetch: {} -> {}".format(reply.url(),
                                                     suggested_filename))
        download = DownloadItem(reply, self._win_id, self)
        download.cancelled.connect(
            functools.partial(self.remove_item, download))

        delay = config.get('ui', 'remove-finished-downloads')
        if delay > -1:
            download.finished.connect(
                functools.partial(self.remove_item_delayed, download, delay))
        elif auto_remove:
            download.finished.connect(
                functools.partial(self.remove_item, download))

        download.data_changed.connect(
            functools.partial(self.on_data_changed, download))
        download.error.connect(self.on_error)
        download.redirected.connect(
            functools.partial(self.on_redirect, download))
        download.basename = suggested_filename
        idx = len(self.downloads)
        download.index = idx + 1  # "Human readable" index
        self.beginInsertRows(QModelIndex(), idx, idx)
        self.downloads.append(download)
        self.endInsertRows()

        if not self._update_timer.isActive():
            self._update_timer.start()

        if fileobj is not None:
            download.set_fileobj(fileobj)
            download.autoclose = False
            return download

        if filename is not None:
            download.set_filename(filename)
            return download

        # Neither filename nor fileobj were given, prepare a question
        filename, q = ask_for_filename(
            suggested_filename,
            self._win_id,
            parent=self,
            prompt_download_directory=prompt_download_directory,
        )

        # User doesn't want to be asked, so just use the download_dir
        if filename is not None:
            download.set_filename(filename)
            return download

        # Ask the user for a filename
        self._postprocess_question(q)
        q.answered.connect(download.set_filename)
        q.cancelled.connect(download.cancel)
        download.cancelled.connect(q.abort)
        download.error.connect(q.abort)
        q.ask()

        return download
Beispiel #16
0
 def test_none(self, stubs, url):
     """Test with no filename at all."""
     reply = stubs.FakeNetworkReply(url=QUrl(url))
     inline, filename = http.parse_content_disposition(reply)
     assert inline
     assert filename == 'qutebrowser-download'
Beispiel #17
0
    def fetch(self, reply, *, target=None, auto_remove=False,
              suggested_filename=None, prompt_download_directory=None):
        """Download a QNetworkReply to disk.

        Args:
            reply: The QNetworkReply to download.
            target: Where to save the download as usertypes.DownloadTarget.
            auto_remove: Whether to remove the download even if
                         ui -> remove-finished-downloads is set to -1.

        Return:
            The created DownloadItem.
        """
        if not suggested_filename:
            if isinstance(target, usertypes.FileDownloadTarget):
                suggested_filename = os.path.basename(target.filename)
            elif (isinstance(target, usertypes.FileObjDownloadTarget) and
                  getattr(target.fileobj, 'name', None)):
                suggested_filename = target.fileobj.name
            else:
                _, suggested_filename = http.parse_content_disposition(reply)
        log.downloads.debug("fetch: {} -> {}".format(reply.url(),
                                                     suggested_filename))
        download = DownloadItem(reply, self._win_id, self)
        download.cancelled.connect(
            functools.partial(self.remove_item, download))

        delay = config.get('ui', 'remove-finished-downloads')
        if delay > -1:
            download.finished.connect(
                functools.partial(self.remove_item_delayed, download, delay))
        elif auto_remove:
            download.finished.connect(
                functools.partial(self.remove_item, download))

        download.data_changed.connect(
            functools.partial(self.on_data_changed, download))
        download.error.connect(self.on_error)
        download.redirected.connect(
            functools.partial(self.on_redirect, download))
        download.basename = suggested_filename
        idx = len(self.downloads)
        download.index = idx + 1  # "Human readable" index
        self.beginInsertRows(QModelIndex(), idx, idx)
        self.downloads.append(download)
        self.endInsertRows()

        if not self._update_timer.isActive():
            self._update_timer.start()

        if target is not None:
            self._set_download_target(download, suggested_filename, target)
            return download

        # Neither filename nor fileobj were given, prepare a question
        filename, q = ask_for_filename(
            suggested_filename, self._win_id, parent=self,
            prompt_download_directory=prompt_download_directory,
        )

        # User doesn't want to be asked, so just use the download_dir
        if filename is not None:
            target = usertypes.FileDownloadTarget(filename)
            self._set_download_target(download, suggested_filename, target)
            return download

        # Ask the user for a filename
        self._postprocess_question(q)
        q.answered.connect(
            functools.partial(self._set_download_target, download,
                              suggested_filename))
        q.cancelled.connect(download.cancel)
        download.cancelled.connect(q.abort)
        download.error.connect(q.abort)
        q.ask()

        return download
def test_parse_content_disposition(caplog, template, stubs, s):
    """Test parsing headers based on templates which hypothesis completes."""
    header = template.format(s)
    reply = stubs.FakeNetworkReply(headers={'Content-Disposition': header})
    with caplog.at_level(logging.ERROR, 'rfc6266'):
        http.parse_content_disposition(reply)
Beispiel #19
0
def test_parse_content_disposition_hypothesis(caplog, template, stubs, s):
    """Test parsing headers based on templates which hypothesis completes."""
    header = template.format(s)
    reply = stubs.FakeNetworkReply(headers={'Content-Disposition': header})
    with caplog.at_level(logging.ERROR, 'network'):
        http.parse_content_disposition(reply)
Beispiel #20
0
 def test_url(self, stubs, url):
     """Test with a filename in the URL."""
     reply = stubs.FakeNetworkReply(url=QUrl(url))
     inline, filename = http.parse_content_disposition(reply)
     assert inline
     assert filename == 'path'
Beispiel #21
0
def test_no_content_disposition(stubs, url, expected):
    reply = stubs.FakeNetworkReply(url=QUrl(url))
    inline, filename = http.parse_content_disposition(reply)
    assert inline
    assert filename == expected
Beispiel #22
0
def test_no_content_disposition(stubs, url, expected):
    reply = stubs.FakeNetworkReply(url=QUrl(url))
    inline, filename = http.parse_content_disposition(reply)
    assert inline
    assert filename == expected