JS Browser: Support for migrating cookies to python format

This commit is contained in:
Kovid Goyal 2011-09-22 11:27:38 -06:00
parent fc2ea389f1
commit f915c03a4c
3 changed files with 96 additions and 2 deletions

View File

@ -94,3 +94,10 @@ def unquote(s):
ans = ans.decode('utf-8') ans = ans.decode('utf-8')
return ans return ans
def cookie_time_fmt(time_t):
return time.strftime('%a, %d-%b-%Y %H:%M:%S GMT', time_t)
def cookie_max_age_to_expires(max_age):
gmt_expiration_time = time.gmtime(time.time() + max_age)
return cookie_time_fmt(gmt_expiration_time)

View File

@ -8,10 +8,11 @@ __copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os, pprint, time import os, pprint, time
from cookielib import Cookie
from PyQt4.Qt import (QObject, QNetworkAccessManager, QNetworkDiskCache, from PyQt4.Qt import (QObject, QNetworkAccessManager, QNetworkDiskCache,
QNetworkProxy, QNetworkProxyFactory, QEventLoop, QUrl, QNetworkProxy, QNetworkProxyFactory, QEventLoop, QUrl,
QDialog, QVBoxLayout, QSize) QDialog, QVBoxLayout, QSize, QNetworkCookieJar)
from PyQt4.QtWebKit import QWebPage, QWebSettings, QWebView from PyQt4.QtWebKit import QWebPage, QWebSettings, QWebView
from calibre import USER_AGENT, prints, get_proxies, get_proxy_info from calibre import USER_AGENT, prints, get_proxies, get_proxy_info
@ -141,6 +142,8 @@ class NetworkAccessManager(QNetworkAccessManager): # {{{
self.pf = ProxyFactory(log) self.pf = ProxyFactory(log)
self.setProxyFactory(self.pf) self.setProxyFactory(self.pf)
self.finished.connect(self.on_finished) self.finished.connect(self.on_finished)
self.cookie_jar = QNetworkCookieJar()
self.setCookieJar(self.cookie_jar)
def on_ssl_errors(self, reply, errors): def on_ssl_errors(self, reply, errors):
reply.ignoreSslErrors() reply.ignoreSslErrors()
@ -186,6 +189,37 @@ class NetworkAccessManager(QNetworkAccessManager): # {{{
d = ' %r: %r' % (h, reply.rawHeader(h)) d = ' %r: %r' % (h, reply.rawHeader(h))
debug.append(d) debug.append(d)
self.log.debug('\n'.join(debug)) self.log.debug('\n'.join(debug))
def py_cookies(self):
for c in self.cookie_jar.allCookies():
name, value = map(bytes, (c.name(), c.value()))
domain = bytes(c.domain())
initial_dot = domain_specified = domain.startswith(b'.')
secure = bool(c.isSecure())
path = unicode(c.path()).strip().encode('utf-8')
expires = c.expirationDate()
is_session_cookie = False
if expires.isValid():
expires = expires.toTime_t()
else:
expires = None
is_session_cookie = True
path_specified = True
if not path:
path = b'/'
path_specified = False
c = Cookie(0, # version
name, value,
None, # port
False, # port specified
domain, domain_specified, initial_dot, path,
path_specified,
secure, expires, is_session_cookie,
None, # Comment
None, # Comment URL
{} # rest
)
yield c
# }}} # }}}
class LoadWatcher(QObject): # {{{ class LoadWatcher(QObject): # {{{
@ -343,3 +377,11 @@ class Browser(QObject, FormsMixin):
view = BrowserView(self.page) view = BrowserView(self.page)
view.exec_() view.exec_()
def cookies(self):
'''
Return all the cookies set currently as :class:`Cookie` objects.
Returns expired cookies as well.
'''
return list(self.nam.py_cookies())

View File

@ -7,11 +7,13 @@ __license__ = 'GPL v3'
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import unittest, pprint, threading import unittest, pprint, threading, time
import cherrypy import cherrypy
from calibre.web.jsbrowser.browser import Browser from calibre.web.jsbrowser.browser import Browser
from calibre.library.server.utils import (cookie_max_age_to_expires,
cookie_time_fmt)
class Server(object): class Server(object):
@ -84,6 +86,26 @@ class Server(object):
cherrypy.response.headers['Content-Type'] = 'text/javascript' cherrypy.response.headers['Content-Type'] = 'text/javascript'
return P('content_server/jquery.js', data=True) return P('content_server/jquery.js', data=True)
@cherrypy.expose
def cookies(self):
try:
cookie = cherrypy.response.cookie
cookie[b'cookiea'] = 'The first cookie'
cookie[b'cookiea']['path'] = '/'
cookie[b'cookiea']['max-age'] = 60 # seconds
cookie[b'cookiea']['version'] = 1
cookie[b'cookieb'] = 'The second cookie'
cookie[b'cookieb']['path'] = '/'
cookie[b'cookieb']['expires'] = cookie_max_age_to_expires(60) # seconds
cookie[b'cookieb']['version'] = 1
cookie[b'cookiec'] = 'The third cookie'
cookie[b'cookiec']['path'] = '/'
self.sent_cookies = {n:('"%s"'%c.value, dict(c)) for n, c in
dict(cookie).iteritems()}
return pprint.pformat(self.sent_cookies)
except:
import traceback
traceback.print_exc()
class Test(unittest.TestCase): class Test(unittest.TestCase):
@ -160,6 +182,29 @@ class Test(unittest.TestCase):
self.browser.ajax_submit() self.browser.ajax_submit()
self.assertEqual(self.server.form_data['text'], 'Changed') self.assertEqual(self.server.form_data['text'], 'Changed')
def test_cookies(self):
'Test migration of cookies to python objects'
self.assertEqual(self.browser.visit('http://127.0.0.1:%d/cookies'%self.port),
True)
sent_cookies = self.server.sent_cookies
cookies = self.browser.cookies()
cmap = {c.name:c for c in cookies}
for name, vals in sent_cookies.iteritems():
c = cmap[name]
value, fields = vals
self.assertEqual(value, c.value)
for field in ('secure', 'path'):
cval = getattr(c, field)
if cval is False:
cval = b''
self.assertEqual(fields[field], cval,
'Field %s in %s: %r != %r'%(field, name, fields[field], cval))
cexp = cookie_time_fmt(time.gmtime(c.expires))
fexp = fields['expires']
if fexp:
self.assertEqual(fexp, cexp)
def tests(): def tests():
return unittest.TestLoader().loadTestsFromTestCase(Test) return unittest.TestLoader().loadTestsFromTestCase(Test)