aboutsummaryrefslogtreecommitdiffstats
path: root/netlib
diff options
context:
space:
mode:
Diffstat (limited to 'netlib')
-rw-r--r--netlib/certutils.py2
-rw-r--r--netlib/http/cookies.py34
-rw-r--r--netlib/http/http2/connections.py8
-rw-r--r--netlib/http/request.py21
-rw-r--r--netlib/http/response.py44
5 files changed, 73 insertions, 36 deletions
diff --git a/netlib/certutils.py b/netlib/certutils.py
index 616a778e..34e01ed3 100644
--- a/netlib/certutils.py
+++ b/netlib/certutils.py
@@ -386,7 +386,7 @@ class SSLCert(Serializable):
@classmethod
def from_state(cls, state):
- cls.from_pem(state)
+ return cls.from_pem(state)
@classmethod
def from_pem(cls, txt):
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