X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FN2VC.git;a=blobdiff_plain;f=juju%2Fclient%2Fgocookies.py;fp=juju%2Fclient%2Fgocookies.py;h=3e48b8d2abd28968ffb6639a4f154c3b2ad1b0c8;hp=0000000000000000000000000000000000000000;hb=b8a8281b1785358bd5632a119c016f21811172c6;hpb=dcdf82bbc1ef310379f746518b2dd3b006353cb3 diff --git a/juju/client/gocookies.py b/juju/client/gocookies.py new file mode 100644 index 0000000..3e48b8d --- /dev/null +++ b/juju/client/gocookies.py @@ -0,0 +1,102 @@ +import datetime +import http.cookiejar as cookiejar +import json +import time + +import pyrfc3339 + + +class GoCookieJar(cookiejar.FileCookieJar): + '''A CookieJar implementation that reads and writes cookies + to the cookiejar format as understood by the Go package + github.com/juju/persistent-cookiejar.''' + def _really_load(self, f, filename, ignore_discard, ignore_expires): + '''Implement the _really_load method called by FileCookieJar + to implement the actual cookie loading''' + data = json.load(f) or [] + now = time.time() + for cookie in map(go_to_py_cookie, data): + if not ignore_expires and cookie.is_expired(now): + continue + self.set_cookie(cookie) + + def save(self, filename=None, ignore_discard=False, ignore_expires=False): + '''Implement the FileCookieJar abstract method.''' + if filename is None: + if self.filename is not None: + filename = self.filename + else: + raise ValueError(cookiejar.MISSING_FILENAME_TEXT) + + # TODO: obtain file lock, read contents of file, and merge with + # current content. + go_cookies = [] + now = time.time() + for cookie in self: + if not ignore_discard and cookie.discard: + continue + if not ignore_expires and cookie.is_expired(now): + continue + go_cookies.append(py_to_go_cookie(cookie)) + with open(filename, "w") as f: + f.write(json.dumps(go_cookies)) + + +def go_to_py_cookie(go_cookie): + '''Convert a Go-style JSON-unmarshaled cookie into a Python cookie''' + expires = None + if go_cookie.get('Expires') is not None: + t = pyrfc3339.parse(go_cookie['Expires']) + expires = t.timestamp() + return cookiejar.Cookie( + version=0, + name=go_cookie['Name'], + value=go_cookie['Value'], + port=None, + port_specified=False, + # Unfortunately Python cookies don't record the original + # host that the cookie came from, so we'll just use Domain + # for that purpose, and record that the domain was specified, + # even though it probably was not. This means that + # we won't correctly record the CanonicalHost entry + # when writing the cookie file after reading it. + domain=go_cookie['Domain'], + domain_specified=not go_cookie['HostOnly'], + domain_initial_dot=False, + path=go_cookie['Path'], + path_specified=True, + secure=go_cookie['Secure'], + expires=expires, + discard=False, + comment=None, + comment_url=None, + rest=None, + rfc2109=False, + ) + + +def py_to_go_cookie(py_cookie): + '''Convert a python cookie to the JSON-marshalable Go-style cookie form.''' + # TODO (perhaps): + # HttpOnly + # Creation + # LastAccess + # Updated + # not done properly: CanonicalHost. + go_cookie = { + 'Name': py_cookie.name, + 'Value': py_cookie.value, + 'Domain': py_cookie.domain, + 'HostOnly': not py_cookie.domain_specified, + 'Persistent': not py_cookie.discard, + 'Secure': py_cookie.secure, + 'CanonicalHost': py_cookie.domain, + } + if py_cookie.path_specified: + go_cookie['Path'] = py_cookie.path + if py_cookie.expires is not None: + unix_time = datetime.datetime.fromtimestamp(py_cookie.expires) + # Note: fromtimestamp bizarrely produces a time without + # a time zone, so we need to use accept_naive. + go_cookie['Expires'] = pyrfc3339.generate(unix_time, accept_naive=True) + return go_cookie