diff options
Diffstat (limited to 'netlib/http')
-rw-r--r-- | netlib/http/cookies.py | 34 | ||||
-rw-r--r-- | netlib/http/http2/connections.py | 8 | ||||
-rw-r--r-- | netlib/http/request.py | 21 | ||||
-rw-r--r-- | netlib/http/response.py | 44 |
4 files changed, 72 insertions, 35 deletions
diff --git a/netlib/http/cookies.py b/netlib/http/cookies.py index 18544b5e..caa84ff7 100644 --- a/netlib/http/cookies.py +++ b/netlib/http/cookies.py @@ -1,4 +1,6 @@ +from six.moves import http_cookies as Cookie import re +from email.utils import parsedate_tz, formatdate, mktime_tz from .. import odict @@ -191,3 +193,35 @@ def format_cookie_header(od): Formats a Cookie header value. """ return _format_pairs(od.lst) + + +def refresh_set_cookie_header(c, delta): + """ + Args: + c: A Set-Cookie string + delta: Time delta in seconds + Returns: + A refreshed Set-Cookie string + """ + try: + c = Cookie.SimpleCookie(str(c)) + except Cookie.CookieError: + raise ValueError("Invalid Cookie") + for i in c.values(): + if "expires" in i: + d = parsedate_tz(i["expires"]) + if d: + d = mktime_tz(d) + delta + i["expires"] = formatdate(d) + else: + # This can happen when the expires tag is invalid. + # reddit.com sends a an expires tag like this: "Thu, 31 Dec + # 2037 23:59:59 GMT", which is valid RFC 1123, but not + # strictly correct according to the cookie spec. Browsers + # appear to parse this tolerantly - maybe we should too. + # For now, we just ignore this. + del i["expires"] + ret = c.output(header="").strip() + if not ret: + raise ValueError("Invalid Cookie") + return ret diff --git a/netlib/http/http2/connections.py b/netlib/http/http2/connections.py index 52fa7193..f900b67c 100644 --- a/netlib/http/http2/connections.py +++ b/netlib/http/http2/connections.py @@ -102,15 +102,15 @@ class HTTP2Protocol(object): port = None if path == '*' or path.startswith("/"): - form_in = "relative" + first_line_format = "relative" elif method == 'CONNECT': - form_in = "authority" + first_line_format = "authority" if ":" in authority: host, port = authority.split(":", 1) else: host = authority else: - form_in = "absolute" + first_line_format = "absolute" # FIXME: verify if path or :host contains what we need scheme, host, port, _ = utils.parse_url(path) scheme = scheme.decode('ascii') @@ -123,7 +123,7 @@ class HTTP2Protocol(object): port = int(port) request = Request( - form_in, + first_line_format, method.encode('ascii'), scheme.encode('ascii'), host.encode('ascii'), diff --git a/netlib/http/request.py b/netlib/http/request.py index 07a11969..692ba30f 100644 --- a/netlib/http/request.py +++ b/netlib/http/request.py @@ -375,24 +375,3 @@ class Request(Message): def get_form_multipart(self): # pragma: no cover warnings.warn(".get_form_multipart is deprecated, use .multipart_form instead.", DeprecationWarning) return self.multipart_form or ODict([]) - - @property - def form_in(self): # pragma: no cover - warnings.warn(".form_in is deprecated, use .first_line_format instead.", DeprecationWarning) - return self.first_line_format - - @form_in.setter - def form_in(self, form_in): # pragma: no cover - warnings.warn(".form_in is deprecated, use .first_line_format instead.", DeprecationWarning) - self.first_line_format = form_in - - @property - def form_out(self): # pragma: no cover - warnings.warn(".form_out is deprecated, use .first_line_format instead.", DeprecationWarning) - return self.first_line_format - - @form_out.setter - def form_out(self, form_out): # pragma: no cover - warnings.warn(".form_out is deprecated, use .first_line_format instead.", DeprecationWarning) - self.first_line_format = form_out - diff --git a/netlib/http/response.py b/netlib/http/response.py index 8af3c041..efd7f60a 100644 --- a/netlib/http/response.py +++ b/netlib/http/response.py @@ -1,6 +1,8 @@ from __future__ import absolute_import, print_function, division import warnings +from email.utils import parsedate_tz, formatdate, mktime_tz +import time from . import cookies from .headers import Headers @@ -94,6 +96,38 @@ class Response(Message): values.append(header) self.headers.set_all("set-cookie", values) + def refresh(self, now=None): + """ + This fairly complex and heuristic function refreshes a server + response for replay. + + - It adjusts date, expires and last-modified headers. + - It adjusts cookie expiration. + """ + if not now: + now = time.time() + delta = now - self.timestamp_start + refresh_headers = [ + "date", + "expires", + "last-modified", + ] + for i in refresh_headers: + if i in self.headers: + d = parsedate_tz(self.headers[i]) + if d: + new = mktime_tz(d) + delta + self.headers[i] = formatdate(new) + c = [] + for set_cookie_header in self.headers.get_all("set-cookie"): + try: + refreshed = cookies.refresh_set_cookie_header(set_cookie_header, delta) + except ValueError: + refreshed = set_cookie_header + c.append(refreshed) + if c: + self.headers.set_all("set-cookie", c) + # Legacy def get_cookies(self): # pragma: no cover @@ -103,13 +137,3 @@ class Response(Message): def set_cookies(self, odict): # pragma: no cover warnings.warn(".set_cookies is deprecated, use .cookies instead.", DeprecationWarning) self.cookies = odict - - @property - def msg(self): # pragma: no cover - warnings.warn(".msg is deprecated, use .reason instead.", DeprecationWarning) - return self.reason - - @msg.setter - def msg(self, reason): # pragma: no cover - warnings.warn(".msg is deprecated, use .reason instead.", DeprecationWarning) - self.reason = reason |