Helpviewer/CookieJar/CookieJar.py

changeset 0
de9c2efb9d02
child 7
c679fb30c8f3
equal deleted inserted replaced
-1:000000000000 0:de9c2efb9d02
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2009 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a QNetworkCookieJar subclass with various accept policies.
8 """
9
10 import os
11
12 from PyQt4.QtCore import *
13 from PyQt4.QtGui import *
14 from PyQt4.QtNetwork import QNetworkCookieJar, QNetworkCookie
15 from PyQt4.QtWebKit import QWebSettings
16
17 from Utilities.AutoSaver import AutoSaver
18 import Utilities
19 import Preferences
20
21 class CookieJar(QNetworkCookieJar):
22 """
23 Class implementing a QNetworkCookieJar subclass with various accept policies.
24
25 @signal cookiesChanged() emitted after the cookies have been changed
26 """
27 JAR_VERSION = 23
28
29 AcceptAlways = 0
30 AcceptNever = 1
31 AcceptOnlyFromSitesNavigatedTo = 2
32
33 KeepUntilExpire = 0
34 KeepUntilExit = 1
35 KeepUntilTimeLimit = 2
36
37 Allow = 0
38 Block = 1
39 AllowForSession = 2
40
41 def __init__(self, parent = None):
42 """
43 Constructor
44
45 @param parent reference to the parent object (QObject)
46 """
47 QNetworkCookieJar.__init__(self, parent)
48
49 self.__loaded = False
50 self.__acceptCookies = self.AcceptOnlyFromSitesNavigatedTo
51 self.__saveTimer = AutoSaver(self, self.save)
52
53 self.__cookiesFile = os.path.join(Utilities.getConfigDir(),
54 "browser", "cookies.ini")
55
56 def saveCookies(self, cookiesList):
57 """
58 Public method to save the cookies.
59
60 @param cookiesList list of cookies to be saved
61 @return saved cookies as a byte array (QByteArray)
62 """
63 data = QByteArray()
64 stream = QDataStream(data, QIODevice.WriteOnly)
65 stream.writeUInt16(self.JAR_VERSION)
66 stream.writeUInt32(len(cookiesList))
67 for cookie in cookiesList:
68 stream << cookie.toRawForm()
69
70 return data
71
72 def loadCookies(self, cookies):
73 """
74 Public method to restore the saved cookies.
75
76 @param cookies byte array containing the saved cookies (QByteArray)
77 @return list of cookies
78 """
79 if cookies.isEmpty():
80 return []
81
82 cookiesList = []
83 data = QByteArray(cookies)
84 stream = QDataStream(data, QIODevice.ReadOnly)
85
86 version = stream.readUInt16()
87 if version != self.JAR_VERSION:
88 return []
89
90 noCookies = stream.readUInt32()
91
92 rawCookie = QByteArray()
93 while not stream.atEnd():
94 stream >> rawCookie
95 newCookies = QNetworkCookie.parseCookies(rawCookie)
96 for newCookie in newCookies:
97 cookiesList.append(newCookie)
98
99 return cookiesList
100
101 def close(self):
102 """
103 Public slot to close the cookie jar.
104 """
105 if self.__loaded and self.__keepCookies == self.KeepUntilExit:
106 self.clear()
107 self.__saveTimer.saveIfNeccessary()
108
109 def clear(self):
110 """
111 Public method to clear all cookies.
112 """
113 if not self.__loaded:
114 self.load()
115
116 self.setAllCookies([])
117 self.__saveTimer.changeOccurred()
118 self.emit(SIGNAL("cookiesChanged()"))
119
120 def load(self):
121 """
122 Public method to load the cookies.
123 """
124 if self.__loaded:
125 return
126
127 cookieSettings = QSettings(self.__cookiesFile, QSettings.IniFormat)
128
129 # load cookies
130 cookies = cookieSettings.value("Cookies")
131 if cookies.isValid():
132 cookiesList = self.loadCookies(cookies.toByteArray())
133 else:
134 cookiesList = []
135 self.setAllCookies(cookiesList)
136
137 # load exceptions
138 self.__exceptionsBlock = \
139 cookieSettings.value("Exceptions/block").toStringList()
140 self.__exceptionsAllow = \
141 cookieSettings.value("Exceptions/allow").toStringList()
142 self.__exceptionsAllowForSession = \
143 cookieSettings.value("Exceptions/allowForSession").toStringList()
144 self.__exceptionsBlock.sort()
145 self.__exceptionsAllow.sort()
146 self.__exceptionsAllowForSession.sort()
147
148 self.__acceptCookies = Preferences.getHelp("AcceptCookies")
149 self.__keepCookies = Preferences.getHelp("KeepCookiesUntil")
150 if self.__keepCookies == self.KeepUntilExit:
151 self.setAllCookies([])
152
153 self.__filterTrackingCookies = Preferences.getHelp("FilterTrackingCookies")
154
155 self.__loaded = True
156 self.emit(SIGNAL("cookiesChanged()"))
157
158 def save(self):
159 """
160 Public method to save the cookies.
161 """
162 if not self.__loaded:
163 return
164
165 self.__purgeOldCookies()
166
167 cookieSettings = QSettings(self.__cookiesFile, QSettings.IniFormat)
168
169 cookiesList = self.allCookies()
170 for index in range(len(cookiesList) -1, -1, -1):
171 if cookiesList[index].isSessionCookie():
172 del cookiesList[index]
173 cookies = self.saveCookies(cookiesList)
174
175 cookieSettings.setValue("Cookies",
176 QVariant(cookies))
177 cookieSettings.setValue("Exceptions/block",
178 QVariant(self.__exceptionsBlock))
179 cookieSettings.setValue("Exceptions/allow",
180 QVariant(self.__exceptionsAllow))
181 cookieSettings.setValue("Exceptions/allowForSession",
182 QVariant(self.__exceptionsAllowForSession))
183
184 Preferences.setHelp("AcceptCookies", self.__acceptCookies)
185 Preferences.setHelp("KeepCookiesUntil", self.__keepCookies)
186 Preferences.setHelp("FilterTrackingCookies", int(self.__filterTrackingCookies))
187
188 def __purgeOldCookies(self):
189 """
190 Private method to purge old cookies
191 """
192 cookies = self.allCookies()
193 if len(cookies) == 0:
194 return
195
196 oldCount = len(cookies)
197 now = QDateTime.currentDateTime()
198 for index in range(len(cookies) - 1, -1, -1):
199 if not cookies[index].isSessionCookie() and \
200 cookies[index].expirationDate() < now:
201 del cookies[index]
202 if oldCount == len(cookies):
203 return
204 self.setAllCookies(cookies)
205 self.emit(SIGNAL("cookiesChanged()"))
206
207 def cookiesForUrl(self, url):
208 """
209 Public method to get the cookies for a URL.
210
211 @param url URL to get cookies for (QUrl)
212 @return list of cookies (list of QNetworkCookie)
213 """
214 if not self.__loaded:
215 self.load()
216
217 globalSettings = QWebSettings.globalSettings()
218 if globalSettings.testAttribute(QWebSettings.PrivateBrowsingEnabled):
219 return []
220
221 return QNetworkCookieJar.cookiesForUrl(self, url)
222
223 def setCookiesFromUrl(self, cookieList, url):
224 """
225 Public method to set cookies for a URL.
226
227 @param cookieList list of cookies to set (list of QNetworkCookie)
228 @param url url to set cookies for (QUrl)
229 @return flag indicating cookies were set (boolean)
230 """
231 if not self.__loaded:
232 self.load()
233
234 globalSettings = QWebSettings.globalSettings()
235 if globalSettings.testAttribute(QWebSettings.PrivateBrowsingEnabled):
236 return False
237
238 host = url.host()
239 eBlock = self.__isOnDomainList(self.__exceptionsBlock, host)
240 eAllow = not eBlock and \
241 self.__isOnDomainList(self.__exceptionsAllow, host)
242 eAllowSession = not eBlock and \
243 not eAllow and \
244 self.__isOnDomainList(self.__exceptionsAllowForSession, host)
245
246 addedCookies = False
247 acceptInitially = self.__acceptCookies != self.AcceptNever
248 if (acceptInitially and not eBlock) or \
249 (not acceptInitially and (eAllow or eAllowSession)):
250 # url domain == cookie domain
251 soon = QDateTime.currentDateTime()
252 soon = soon.addDays(90)
253 for cookie in cookieList:
254 lst = []
255 if not (self.__filterTrackingCookies and \
256 cookie.name().startsWith("__utm")):
257 if eAllowSession:
258 cookie.setExpirationDate(QDateTime())
259 if self.__keepCookies == self.KeepUntilTimeLimit and \
260 not cookie.isSessionCookie and \
261 cookie.expirationDate() > soon:
262 cookie.setExpirationDate(soon)
263 lst.append(cookie)
264 if QNetworkCookieJar.setCookiesFromUrl(self, lst, url):
265 addedCookies = True
266 elif self.__acceptCookies == self.AcceptAlways:
267 # force it in if wanted
268 cookies = self.allCookies()
269 for ocookie in cookies[:]:
270 # does the cookie exist already?
271 if cookie.name() == ocookie.name() and \
272 cookie.domain() == ocookie.domain() and \
273 cookie.path() == ocookie.path():
274 # found a match
275 cookies.remove(ocookie)
276
277 cookies.append(cookie)
278 self.setAllCookies(cookies)
279 addedCookies = True
280
281 if addedCookies:
282 self.__saveTimer.changeOccurred()
283 self.emit(SIGNAL("cookiesChanged()"))
284
285 return addedCookies
286
287 def acceptPolicy(self):
288 """
289 Public method to get the accept policy.
290
291 @return current accept policy
292 """
293 if not self.__loaded:
294 self.load()
295 return self.__acceptCookies
296
297 def setAcceptPolicy(self, policy):
298 """
299 Public method to set the accept policy.
300
301 @param policy accept policy to be set
302 """
303 if not self.__loaded:
304 self.load()
305 if policy > self.AcceptOnlyFromSitesNavigatedTo:
306 return
307 if policy == self.__acceptCookies:
308 return
309 self.__acceptCookies = policy
310 self.__saveTimer.changeOccurred()
311
312 def keepPolicy(self):
313 """
314 Private method to get the keep policy.
315 """
316 if not self.__loaded:
317 self.load()
318 return self.__keepCookies
319
320 def setKeepPolicy(self, policy):
321 """
322 Public method to set the keep policy.
323
324 @param policy keep policy to be set
325 """
326 if not self.__loaded:
327 self.load()
328 if policy > self.KeepUntilTimeLimit:
329 return
330 if policy == self.__keepCookies:
331 return
332 self.__keepCookies = policy
333 self.__saveTimer.changeOccurred()
334
335 def blockedCookies(self):
336 """
337 Public method to return the blocked cookies.
338
339 @return list of blocked cookies (list of strings)
340 """
341 if not self.__loaded:
342 self.load()
343 return self.__exceptionsBlock
344
345 def allowedCookies(self):
346 """
347 Public method to return the allowed cookies.
348
349 @return list of allowed cookies (list of strings)
350 """
351 if not self.__loaded:
352 self.load()
353 return self.__exceptionsAllow
354
355 def allowForSessionCookies(self):
356 """
357 Public method to return the allowed session cookies.
358
359 @return list of allowed session cookies (list of strings)
360 """
361 if not self.__loaded:
362 self.load()
363 return self.__exceptionsAllowForSession
364
365 def setBlockedCookies(self, list_):
366 """
367 Public method to set the list of blocked cookies.
368
369 @param list_ list of blocked cookies (list of strings)
370 """
371 if not self.__loaded:
372 self.load()
373 self.__exceptionsBlock = list_[:]
374 self.__exceptionsBlock.sort()
375 self.__applyRules()
376 self.__saveTimer.changeOccurred()
377
378 def setAllowedCookies(self, list_):
379 """
380 Public method to set the list of allowed cookies.
381
382 @param list_ list of allowed cookies (list of strings)
383 """
384 if not self.__loaded:
385 self.load()
386 self.__exceptionsAllow = list_[:]
387 self.__exceptionsAllow.sort()
388 self.__applyRules()
389 self.__saveTimer.changeOccurred()
390
391 def setAllowForSessionCookies(self, list_):
392 """
393 Public method to set the list of allowed session cookies.
394
395 @param list_ list of allowed session cookies (list of strings)
396 """
397 if not self.__loaded:
398 self.load()
399 self.__exceptionsAllowForSession = list_[:]
400 self.__exceptionsAllowForSession.sort()
401 self.__applyRules()
402 self.__saveTimer.changeOccurred()
403
404 def filterTrackingCookies(self):
405 """
406 Public method to get the filter tracking cookies flag.
407
408 @return filter tracking cookies flag (boolean)
409 """
410 return self.__filterTrackingCookies
411
412 def setFilterTrackingCookies(self, filterTrackingCookies):
413 """
414 Public method to set the filter tracking cookies flag.
415
416 @param filterTrackingCookies filter tracking cookies flag (boolean)
417 """
418 self.__filterTrackingCookies = filterTrackingCookies
419
420 def __isOnDomainList(self, rules, domain):
421 """
422 Private method to check, if either the rule matches the domain exactly
423 or the domain ends with ".rule".
424
425 @param rules list of rules (list of strings)
426 @param domain domain name to check (string)
427 @return flag indicating a match (boolean)
428 """
429 for rule in rules:
430 if rule.startswith("."):
431 if domain.endswith(rule):
432 return True
433
434 withoutDot = rule[1:]
435 if domain == withoutDot:
436 return True
437 else:
438 domainEnding = domain[-(len(rule) + 1):]
439 if domainEnding and \
440 domainEnding[0] == "." and \
441 domain.endswith(rule):
442 return True
443
444 if rule == domain:
445 return True
446
447 return False
448
449 def __applyRules(self):
450 """
451 Private method to apply the cookie rules.
452 """
453 cookiesList = self.allCookies()
454 changed = False
455
456 for index in range(len(cookiesList) - 1, -1, -1):
457 cookie = cookiesList[index]
458 if self.__isOnDomainList(self.__exceptionsBlock, cookie.domain()):
459 del cookiesList[index]
460 changed = True
461 elif self.__isOnDomainList(self.__exceptionsAllowForSession, cookie.domain()):
462 cookie.setExpirationDate(QDateTime())
463 changed = True
464
465 if changed:
466 self.setAllCookies(cookiesList)
467 self.__saveTimer.changeOccurred()
468 self.emit(SIGNAL("cookiesChanged()"))
469
470 def cookies(self):
471 """
472 Public method to get the cookies of the cookie jar.
473
474 @return list of all cookies (list of QNetworkCookie)
475 """
476 if not self.__loaded:
477 self.load()
478
479 return self.allCookies()
480
481 def setCookies(self, cookies):
482 """
483 Public method to set all cookies.
484
485 @param cookies list of cookies to be set (list of QNetworkCookie)
486 """
487 if not self.__loaded:
488 self.load()
489
490 self.setAllCookies(cookies)
491 self.__saveTimer.changeOccurred()
492 self.emit(SIGNAL("cookiesChanged()"))

eric ide

mercurial