cookies/cache: Handle por^H^Hrivate browsing mode.

See #43.
This commit is contained in:
Florian Bruhin 2014-12-10 13:12:53 +01:00
parent 0b82fdb4d8
commit 76c5c8bf8e
3 changed files with 184 additions and 34 deletions

View File

@ -22,7 +22,7 @@
import os.path import os.path
from PyQt5.QtCore import QStandardPaths from PyQt5.QtCore import QStandardPaths
from PyQt5.QtNetwork import QNetworkDiskCache from PyQt5.QtNetwork import QNetworkDiskCache, QNetworkCacheMetaData
from qutebrowser.config import config from qutebrowser.config import config
from qutebrowser.utils import utils, standarddir, objreg from qutebrowser.utils import utils, standarddir, objreg
@ -48,3 +48,110 @@ class DiskCache(QNetworkDiskCache):
def cache_size_changed(self): def cache_size_changed(self):
"""Update cache size if the config was changed.""" """Update cache size if the config was changed."""
self.setMaximumCacheSize(config.get('storage', 'cache-size')) 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()

View File

@ -26,33 +26,13 @@ from qutebrowser.config import config, lineparser
from qutebrowser.utils import utils, standarddir, objreg from qutebrowser.utils import utils, standarddir, objreg
class CookieJar(QNetworkCookieJar): class RAMCookieJar(QNetworkCookieJar):
"""Our own cookie jar to save cookies to disk if desired.""" """An in-RAM cookie jar."""
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 __repr__(self): def __repr__(self):
return utils.get_repr(self, count=len(self.allCookies())) 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): def setCookiesFromUrl(self, cookies, url):
"""Add the cookies in the cookies list to this cookie jar. """Add the cookies in the cookies list to this cookie jar.
@ -68,6 +48,35 @@ class CookieJar(QNetworkCookieJar):
else: else:
return super().setCookiesFromUrl(cookies, url) 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): def save(self):
"""Save cookies to disk.""" """Save cookies to disk."""
if not config.get('content', 'cookies-store'): if not config.get('content', 'cookies-store'):

View File

@ -32,6 +32,7 @@ else:
from qutebrowser.config import config from qutebrowser.config import config
from qutebrowser.utils import message, log, usertypes, utils, objreg from qutebrowser.utils import message, log, usertypes, utils, objreg
from qutebrowser.network import qutescheme, networkreply from qutebrowser.network import qutescheme, networkreply
from qutebrowser.browser import cookies
class NetworkManager(QNetworkAccessManager): class NetworkManager(QNetworkAccessManager):
@ -62,22 +63,44 @@ class NetworkManager(QNetworkAccessManager):
self._scheme_handlers = { self._scheme_handlers = {
'qute': qutescheme.QuteSchemeHandler(win_id), 'qute': qutescheme.QuteSchemeHandler(win_id),
} }
self._set_cookiejar()
# We have a shared cookie jar and cache - we restore their parents so self._set_cache()
# 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)
if SSL_AVAILABLE: if SSL_AVAILABLE:
self.sslErrors.connect(self.on_ssl_errors) self.sslErrors.connect(self.on_ssl_errors)
self.authenticationRequired.connect(self.on_authentication_required) self.authenticationRequired.connect(self.on_authentication_required)
self.proxyAuthenticationRequired.connect( self.proxyAuthenticationRequired.connect(
self.on_proxy_authentication_required) 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): def _ask(self, win_id, text, mode):
"""Ask a blocking question in the statusbar. """Ask a blocking question in the statusbar.
@ -160,6 +183,17 @@ class NetworkManager(QNetworkAccessManager):
authenticator.realm()), mode=usertypes.PromptMode.user_pwd) authenticator.realm()), mode=usertypes.PromptMode.user_pwd)
self._fill_authenticator(authenticator, answer) 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: # WORKAROUND for:
# http://www.riverbankcomputing.com/pipermail/pyqt/2014-September/034806.html # http://www.riverbankcomputing.com/pipermail/pyqt/2014-September/034806.html
# #