diff --git a/qutebrowser/browser/webpage.py b/qutebrowser/browser/webpage.py index 72c238629..8727ba9d4 100644 --- a/qutebrowser/browser/webpage.py +++ b/qutebrowser/browser/webpage.py @@ -19,6 +19,8 @@ """The main browser widgets.""" +from functools import partial + import sip from PyQt5.QtCore import pyqtSignal, pyqtSlot, PYQT_VERSION, Qt from PyQt5.QtNetwork import QNetworkReply @@ -29,6 +31,7 @@ from PyQt5.QtWebKitWidgets import QWebPage import qutebrowser.utils.message as message import qutebrowser.config.config as config import qutebrowser.utils.log as log +import qutebrowser.utils.http as http from qutebrowser.network.networkmanager import NetworkManager from qutebrowser.utils.misc import read_file from qutebrowser.utils.qt import check_print_compat @@ -63,6 +66,7 @@ class BrowserPage(QWebPage): self.setForwardUnsupportedContent(True) self.printRequested.connect(self.on_print_requested) self.downloadRequested.connect(self.on_download_requested) + self.unsupportedContent.connect(self.on_unsupported_content) self._view = view if PYQT_VERSION > 0x050300: @@ -147,6 +151,11 @@ class BrowserPage(QWebPage): suggested_file) return True + def display_content(self, reply, mimetype): + """Display a QNetworkReply with an explicitely set mimetype.""" + self.mainFrame().setContent(reply.readAll(), mimetype, reply.url()) + reply.deleteLater() + def on_print_requested(self, frame): """Handle printing when requested via javascript.""" if not check_print_compat(): @@ -168,6 +177,36 @@ class BrowserPage(QWebPage): reply = self.networkAccessManager().get(request) self.start_download.emit(reply) + @pyqtSlot('QNetworkReply') + 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) + if not inline: + # Content-Disposition: attachment -> force download + self.start_download.emit(reply) + 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( + partial(self.display_content, reply, 'image/jpeg')) + else: + # Unknown mimetype, so download anyways. + self.start_download.emit(reply) + def userAgentForUrl(self, url): """Override QWebPage::userAgentForUrl to customize the user agent.""" ua = config.get('network', 'user-agent') diff --git a/qutebrowser/network/networkmanager.py b/qutebrowser/network/networkmanager.py index e483c0af8..c3df0014f 100644 --- a/qutebrowser/network/networkmanager.py +++ b/qutebrowser/network/networkmanager.py @@ -19,8 +19,6 @@ """Our own QNetworkAccessManager.""" -from functools import partial - from PyQt5.QtCore import pyqtSlot, PYQT_VERSION, QCoreApplication from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkReply @@ -37,7 +35,6 @@ import qutebrowser.utils.log as log from qutebrowser.network.qutescheme import QuteSchemeHandler from qutebrowser.network.schemehandler import ErrorNetworkReply from qutebrowser.utils.usertypes import PromptMode -from qutebrowser.utils.http import change_content_type class NetworkManager(QNetworkAccessManager): @@ -162,10 +159,4 @@ class NetworkManager(QNetworkAccessManager): reply = super().createRequest(op, req, outgoing_data) self._requests.append(reply) reply.destroyed.connect(lambda obj: self._requests.remove(obj)) - # Some servers (e.g. the LinkedIn CDN) send a non-standard image/jpg - # header for jpg images. We change this to image/jpeg (defined in RFC - # 1341 section 7.5: https://tools.ietf.org/html/rfc1341) so QtWebKit - # displays this instead of downloading it. - reply.metaDataChanged.connect( - partial(change_content_type, reply, {'image/jpg': 'image/jpeg'})) return reply diff --git a/qutebrowser/widgets/tabbedbrowser.py b/qutebrowser/widgets/tabbedbrowser.py index cabfc74fd..718c30634 100644 --- a/qutebrowser/widgets/tabbedbrowser.py +++ b/qutebrowser/widgets/tabbedbrowser.py @@ -166,7 +166,6 @@ class TabbedBrowser(TabWidget): tab.hintmanager.openurl.connect(self.openurl) self.cur_load_started.connect(self.on_cur_load_started) # downloads - page.unsupportedContent.connect(self.start_download) page.start_download.connect(self.start_download) # misc tab.titleChanged.connect(partial(self.on_title_changed, tab))