diff --git a/qutebrowser/browser/cache.py b/qutebrowser/browser/cache.py index c3fa0437d..425d9962f 100644 --- a/qutebrowser/browser/cache.py +++ b/qutebrowser/browser/cache.py @@ -22,7 +22,7 @@ import os.path from PyQt5.QtCore import QStandardPaths -from PyQt5.QtNetwork import QNetworkDiskCache +from PyQt5.QtNetwork import QNetworkDiskCache, QNetworkCacheMetaData from qutebrowser.config import config from qutebrowser.utils import utils, standarddir, objreg @@ -48,3 +48,110 @@ class DiskCache(QNetworkDiskCache): def cache_size_changed(self): """Update cache size if the config was changed.""" self.setMaximumCacheSize(config.get('storage', 'cache-size')) + + def cacheSize(self): + """Return the current size taken up by the cache. + + Return: + An int. + """ + if objreg.get('general', 'private-browsing'): + return 0 + else: + return super().cacheSize() + + def fileMetaData(self, filename): + """Returns the QNetworkCacheMetaData for the cache file filename. + + Args: + filename: The file name as a string. + + Return: + A QNetworkCacheMetaData object. + """ + if objreg.get('general', 'private-browsing'): + return QNetworkCacheMetaData() + else: + return super().fileMetaData(filename) + + def data(self, url): + """Return the data associated with url. + + Args: + url: A QUrl. + + return: + A QIODevice or None. + """ + if objreg.get('general', 'private-browsing'): + return None + else: + return super().data(url) + + def insert(self, device): + """Insert the data in device and the prepared meta data into the cache. + + Args: + device: A QIODevice. + """ + if objreg.get('general', 'private-browsing'): + return + else: + super().insert(device) + + def metaData(self, url): + """Return the meta data for the url url. + + Args: + url: A QUrl. + + Return: + A QNetworkCacheMetaData object. + """ + if objreg.get('general', 'private-browsing'): + return QNetworkCacheMetaData() + else: + return super().metaData(url) + + def prepare(self, meta_data): + """Return the device that should be populated with the data. + + Args: + meta_data: A QNetworkCacheMetaData object. + + Return: + A QIODevice or None. + """ + if objreg.get('general', 'private-browsing'): + return None + else: + return super().prepare(meta_data) + + def remove(self, url): + """Remove the cache entry for url. + + Return: + True on success, False otherwise. + """ + if objreg.get('general', 'private-browsing'): + return False + else: + return super().remove(url) + + def updateMetaData(self, meta_data): + """Updates the cache meta date for the meta_data's url to meta_data. + + Args: + meta_data: A QNetworkCacheMetaData object. + """ + if objreg.get('general', 'private-browsing'): + return + else: + super().updateMetaData(meta_data) + + def clear(self): + """Removes all items from the cache.""" + if objreg.get('general', 'private-browsing'): + return + else: + super().clear() diff --git a/qutebrowser/browser/cookies.py b/qutebrowser/browser/cookies.py index 5fe2bb1bf..7ba786ed6 100644 --- a/qutebrowser/browser/cookies.py +++ b/qutebrowser/browser/cookies.py @@ -26,33 +26,13 @@ from qutebrowser.config import config, lineparser from qutebrowser.utils import utils, standarddir, objreg -class CookieJar(QNetworkCookieJar): +class RAMCookieJar(QNetworkCookieJar): - """Our own cookie jar to save cookies to disk if desired.""" - - def __init__(self, parent=None): - super().__init__(parent) - datadir = standarddir.get(QStandardPaths.DataLocation) - self._linecp = lineparser.LineConfigParser(datadir, 'cookies', - binary=True) - cookies = [] - for line in self._linecp: - cookies += QNetworkCookie.parseCookies(line) - self.setAllCookies(cookies) - objreg.get('config').changed.connect(self.cookies_store_changed) + """An in-RAM cookie jar.""" def __repr__(self): return utils.get_repr(self, count=len(self.allCookies())) - def purge_old_cookies(self): - """Purge expired cookies from the cookie jar.""" - # Based on: - # http://qt-project.org/doc/qt-5/qtwebkitexamples-webkitwidgets-browser-cookiejar-cpp.html - now = QDateTime.currentDateTime() - cookies = [c for c in self.allCookies() - if c.isSessionCookie() or c.expirationDate() >= now] - self.setAllCookies(cookies) - def setCookiesFromUrl(self, cookies, url): """Add the cookies in the cookies list to this cookie jar. @@ -68,6 +48,35 @@ class CookieJar(QNetworkCookieJar): else: return super().setCookiesFromUrl(cookies, url) + +class CookieJar(RAMCookieJar): + + """A cookie jar saving cookies to disk. + + Attributes: + _linecp: The LineConfigParser managing the cookies file. + """ + + def __init__(self, parent=None): + super().__init__(parent) + datadir = standarddir.get(QStandardPaths.DataLocation) + self._linecp = lineparser.LineConfigParser(datadir, 'cookies', + binary=True) + cookies = [] + for line in self._linecp: + cookies += QNetworkCookie.parseCookies(line) + self.setAllCookies(cookies) + objreg.get('config').changed.connect(self.cookies_store_changed) + + def purge_old_cookies(self): + """Purge expired cookies from the cookie jar.""" + # Based on: + # http://qt-project.org/doc/qt-5/qtwebkitexamples-webkitwidgets-browser-cookiejar-cpp.html + now = QDateTime.currentDateTime() + cookies = [c for c in self.allCookies() + if c.isSessionCookie() or c.expirationDate() >= now] + self.setAllCookies(cookies) + def save(self): """Save cookies to disk.""" if not config.get('content', 'cookies-store'): diff --git a/qutebrowser/network/networkmanager.py b/qutebrowser/network/networkmanager.py index 356aa638f..8b6378866 100644 --- a/qutebrowser/network/networkmanager.py +++ b/qutebrowser/network/networkmanager.py @@ -32,6 +32,7 @@ else: from qutebrowser.config import config from qutebrowser.utils import message, log, usertypes, utils, objreg from qutebrowser.network import qutescheme, networkreply +from qutebrowser.browser import cookies class NetworkManager(QNetworkAccessManager): @@ -62,22 +63,44 @@ class NetworkManager(QNetworkAccessManager): self._scheme_handlers = { 'qute': qutescheme.QuteSchemeHandler(win_id), } - - # We have a shared cookie jar and cache - we restore their parents so - # we don't take ownership of them. - app = QCoreApplication.instance() - cookie_jar = objreg.get('cookie-jar') - self.setCookieJar(cookie_jar) - cookie_jar.setParent(app) - cache = objreg.get('cache') - self.setCache(cache) - cache.setParent(app) - + self._set_cookiejar() + self._set_cache() if SSL_AVAILABLE: self.sslErrors.connect(self.on_ssl_errors) self.authenticationRequired.connect(self.on_authentication_required) self.proxyAuthenticationRequired.connect( self.on_proxy_authentication_required) + objreg.get('config').changed.connect(self.on_config_changed) + + def _set_cookiejar(self, private=False): + """Set the cookie jar of the NetworkManager correctly. + + Args: + private: Whether we're currently in private browsing mode. + """ + if private: + cookie_jar = cookies.RAMCookieJar(self) + self.setCookieJar(cookie_jar) + else: + # We have a shared cookie jar - we restore its parent so we don't + # take ownership of it. + app = QCoreApplication.instance() + cookie_jar = objreg.get('cookie-jar') + self.setCookieJar(cookie_jar) + cookie_jar.setParent(app) + + def _set_cache(self): + """Set the cache of the NetworkManager correctly. + + We can't switch the whole cache in private mode because QNAM would + delete the old cache. + """ + # We have a shared cache - we restore its parent so we don't take + # ownership of it. + app = QCoreApplication.instance() + cache = objreg.get('cache') + self.setCache(cache) + cache.setParent(app) def _ask(self, win_id, text, mode): """Ask a blocking question in the statusbar. @@ -160,6 +183,17 @@ class NetworkManager(QNetworkAccessManager): authenticator.realm()), mode=usertypes.PromptMode.user_pwd) self._fill_authenticator(authenticator, answer) + @config.change_filter('general', 'private-browsing') + def on_config_changed(self): + """Set cookie jar when entering/leaving private browsing mode.""" + private_browsing = config.get('general', 'private-browsing') + if private_browsing: + # switched from normal mode to private mode + self._set_cookiejar(private=True) + else: + # switched from private mode to normal mode + self._set_cookiejar() + # WORKAROUND for: # http://www.riverbankcomputing.com/pipermail/pyqt/2014-September/034806.html #