From 5b5a3ffa8e5650012fcf278146305aabb322b975 Mon Sep 17 00:00:00 2001 From: Shadab Zafar Date: Tue, 28 Jun 2016 17:35:56 +0530 Subject: netlib: condition on PY2 rather than on PY3 Let's just hope PY4 doesn't break this! --- netlib/strutils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'netlib') diff --git a/netlib/strutils.py b/netlib/strutils.py index 414b2e57..cfcdf485 100644 --- a/netlib/strutils.py +++ b/netlib/strutils.py @@ -19,12 +19,12 @@ def native(s, *encoding_opts): """ if not isinstance(s, (six.binary_type, six.text_type)): raise TypeError("%r is neither bytes nor unicode" % s) - if six.PY3: - if isinstance(s, six.binary_type): - return s.decode(*encoding_opts) - else: + if six.PY2: if isinstance(s, six.text_type): return s.encode(*encoding_opts) + else: + if isinstance(s, six.binary_type): + return s.decode(*encoding_opts) return s -- cgit v1.2.3 From d3611777539471e53d4fdedf352ed755a4092415 Mon Sep 17 00:00:00 2001 From: Shadab Zafar Date: Sun, 3 Jul 2016 18:03:34 +0530 Subject: h2: move header parsing to netlib --- netlib/http/http2/__init__.py | 2 ++ netlib/http/http2/utils.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 netlib/http/http2/utils.py (limited to 'netlib') diff --git a/netlib/http/http2/__init__.py b/netlib/http/http2/__init__.py index 6a979a0d..60064190 100644 --- a/netlib/http/http2/__init__.py +++ b/netlib/http/http2/__init__.py @@ -1,6 +1,8 @@ from __future__ import absolute_import, print_function, division from netlib.http.http2 import framereader +from netlib.http.http2.utils import parse_headers __all__ = [ "framereader", + "parse_headers", ] diff --git a/netlib/http/http2/utils.py b/netlib/http/http2/utils.py new file mode 100644 index 00000000..4d5f580c --- /dev/null +++ b/netlib/http/http2/utils.py @@ -0,0 +1,37 @@ +from netlib.http import url + + +def parse_headers(headers): + authority = headers.get(':authority', b'') + method = headers.get(':method', b'GET') + scheme = headers.get(':scheme', b'https') + path = headers.get(':path', b'/') + + headers.clear(":method") + headers.clear(":scheme") + headers.clear(":path") + + host = None + port = None + + if path == b'*' or path.startswith(b"/"): + first_line_format = "relative" + elif method == b'CONNECT': # pragma: no cover + raise NotImplementedError("CONNECT over HTTP/2 is not implemented.") + else: # pragma: no cover + first_line_format = "absolute" + # FIXME: verify if path or :host contains what we need + scheme, host, port, _ = url.parse(path) + + if authority: + host, _, port = authority.partition(b':') + + if not host: + host = b'localhost' + + if not port: + port = 443 if scheme == b'https' else 80 + + port = int(port) + + return first_line_format, method, scheme, host, port, path -- cgit v1.2.3 From 23e295b37eb3aee9ebe7c88cc1ebb1dc2ffa9cf2 Mon Sep 17 00:00:00 2001 From: Thomas Kriechbaumer Date: Sun, 3 Jul 2016 19:04:16 +0200 Subject: py3: fix bytes vs. str --- netlib/http/http2/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'netlib') diff --git a/netlib/http/http2/utils.py b/netlib/http/http2/utils.py index 4d5f580c..4c01952d 100644 --- a/netlib/http/http2/utils.py +++ b/netlib/http/http2/utils.py @@ -2,10 +2,10 @@ from netlib.http import url def parse_headers(headers): - authority = headers.get(':authority', b'') - method = headers.get(':method', b'GET') - scheme = headers.get(':scheme', b'https') - path = headers.get(':path', b'/') + authority = headers.get(':authority', '').encode() + method = headers.get(':method', 'GET').encode() + scheme = headers.get(':scheme', 'https').encode() + path = headers.get(':path', '/').encode() headers.clear(":method") headers.clear(":scheme") -- cgit v1.2.3 From d51cf543bb74755ed5dd17ed02859912ec557ef4 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Tue, 5 Jul 2016 15:11:32 -0700 Subject: remove clean_bin, clarify unicode handling --- netlib/strutils.py | 80 ++++++++++++++++++++++++++++++---------------- netlib/websockets/frame.py | 2 +- 2 files changed, 53 insertions(+), 29 deletions(-) (limited to 'netlib') diff --git a/netlib/strutils.py b/netlib/strutils.py index 414b2e57..4beb6ffd 100644 --- a/netlib/strutils.py +++ b/netlib/strutils.py @@ -1,4 +1,4 @@ -import unicodedata +import re import codecs import six @@ -28,51 +28,71 @@ def native(s, *encoding_opts): return s -def clean_bin(s, keep_spacing=True): - # type: (Union[bytes, six.text_type], bool) -> six.text_type +# Translate control characters to "safe" characters. This implementation initially +# replaced them with the matching control pictures (http://unicode.org/charts/PDF/U2400.pdf), +# but that turned out to render badly with monospace fonts. We are back to "." therefore. +_control_char_trans = { + x: ord(".") # x + 0x2400 for unicode control group pictures + for x in range(32) +} +_control_char_trans[127] = ord(".") # 0x2421 +_control_char_trans_newline = _control_char_trans.copy() +for x in ("\r", "\n", "\t"): + del _control_char_trans_newline[ord(x)] + + +if six.PY2: + pass +else: + _control_char_trans = str.maketrans(_control_char_trans) + _control_char_trans_newline = str.maketrans(_control_char_trans_newline) + + +def escape_control_characters(text, keep_spacing=True): """ - Cleans binary data to make it safe to display. + Replace all unicode C1 control characters from the given text with their respective control pictures. + For example, a null byte is replaced with the unicode character "\u2400". - Args: - keep_spacing: If False, tabs and newlines will also be replaced. + Args: + keep_spacing: If True, tabs and newlines will not be replaced. """ - if isinstance(s, six.text_type): - if keep_spacing: - keep = u" \n\r\t" - else: - keep = u" " + # type: (six.text_type) -> six.text_type + if not isinstance(text, six.text_type): + raise ValueError("text type must be unicode but is {}".format(type(text).__name__)) + + trans = _control_char_trans_newline if keep_spacing else _control_char_trans + if six.PY2: return u"".join( - ch if (unicodedata.category(ch)[0] not in "CZ" or ch in keep) else u"." - for ch in s - ) - else: - if keep_spacing: - keep = (9, 10, 13) # \t, \n, \r, - else: - keep = () - return "".join( - chr(ch) if (31 < ch < 127 or ch in keep) else "." - for ch in six.iterbytes(s) + six.unichr(trans.get(ord(ch), ord(ch))) + for ch in text ) + return text.translate(trans) -def bytes_to_escaped_str(data): +def bytes_to_escaped_str(data, keep_spacing=False): """ Take bytes and return a safe string that can be displayed to the user. Single quotes are always escaped, double quotes are never escaped: "'" + bytes_to_escaped_str(...) + "'" gives a valid Python string. + + Args: + keep_spacing: If True, tabs and newlines will not be escaped. """ - # TODO: We may want to support multi-byte characters without escaping them. - # One way to do would be calling .decode("utf8", "backslashreplace") first - # and then escaping UTF8 control chars (see clean_bin). if not isinstance(data, bytes): raise ValueError("data must be bytes, but is {}".format(data.__class__.__name__)) # We always insert a double-quote here so that we get a single-quoted string back # https://stackoverflow.com/questions/29019340/why-does-python-use-different-quotes-for-representing-strings-depending-on-their - return repr(b'"' + data).lstrip("b")[2:-1] + ret = repr(b'"' + data).lstrip("b")[2:-1] + if keep_spacing: + ret = re.sub( + r"(? Date: Wed, 6 Jul 2016 16:47:32 -0700 Subject: fix pathod log encoding --- netlib/strutils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'netlib') diff --git a/netlib/strutils.py b/netlib/strutils.py index 809f5e17..59816dba 100644 --- a/netlib/strutils.py +++ b/netlib/strutils.py @@ -156,8 +156,8 @@ def hexdump(s): part = s[i:i + 16] x = " ".join("{:0=2x}".format(i) for i in six.iterbytes(part)) x = x.ljust(47) # 16*2 + 15 - part_repr = escape_control_characters( + part_repr = native(escape_control_characters( part.decode("ascii", "replace").replace(u"\ufffd", u"."), False - ) + )) yield (offset, x, part_repr) -- cgit v1.2.3 From 444f0a4c397e3d664ce80f65d176d871b8e1194e Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Wed, 6 Jul 2016 17:31:08 -0700 Subject: py3++ --- netlib/strutils.py | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) (limited to 'netlib') diff --git a/netlib/strutils.py b/netlib/strutils.py index 809f5e17..7ad15c96 100644 --- a/netlib/strutils.py +++ b/netlib/strutils.py @@ -114,24 +114,17 @@ def escaped_str_to_bytes(data): return codecs.escape_decode(data)[0] -def isBin(s): - """ - Does this string have any non-ASCII characters? - """ - for i in s: - i = ord(i) - if i < 9 or 13 < i < 32 or 126 < i: - return True - return False - - -def isMostlyBin(s): - s = s[:100] - return sum(isBin(ch) for ch in s) / len(s) > 0.3 +def is_mostly_bin(s): + # type: (bytes) -> bool + return sum( + i < 9 or 13 < i < 32 or 126 < i + for i in six.iterbytes(s[:100]) + ) > 30 -def isXML(s): - return s.strip().startswith("<") +def is_xml(s): + # type: (bytes) -> bool + return s.strip().startswith(b"<") def clean_hanging_newline(t): -- cgit v1.2.3 From 9c873d63f4ede1b2470f8e7ea838909e60efe998 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Wed, 6 Jul 2016 19:50:06 -0700 Subject: py3++, multidict fixes This commit improves Python 3 compatibility and fixes two multidict issues: 1. Headers.items(multi=True) now decodes fields 2. MultiDict.clear(item) has been removed, as Python's MutableMapping already defines .clear() with different semantics. This is confusing for everyone who expects a dict-like object. `.pop("attr", None)` is not fantastic, but it's the Python way to do it. --- netlib/http/headers.py | 9 +++++++++ netlib/http/http2/utils.py | 6 +++--- netlib/multidict.py | 24 +++++++----------------- 3 files changed, 19 insertions(+), 20 deletions(-) (limited to 'netlib') diff --git a/netlib/http/headers.py b/netlib/http/headers.py index f052a53b..413add87 100644 --- a/netlib/http/headers.py +++ b/netlib/http/headers.py @@ -148,6 +148,15 @@ class Headers(multidict.MultiDict): value = _always_bytes(value) super(Headers, self).insert(index, key, value) + def items(self, multi=False): + if multi: + return ( + (_native(k), _native(v)) + for k, v in self.fields + ) + else: + return super(Headers, self).items() + def replace(self, pattern, repl, flags=0): """ Replaces a regular expression pattern with repl in each "name: value" diff --git a/netlib/http/http2/utils.py b/netlib/http/http2/utils.py index 4c01952d..164bacc8 100644 --- a/netlib/http/http2/utils.py +++ b/netlib/http/http2/utils.py @@ -7,9 +7,9 @@ def parse_headers(headers): scheme = headers.get(':scheme', 'https').encode() path = headers.get(':path', '/').encode() - headers.clear(":method") - headers.clear(":scheme") - headers.clear(":path") + headers.pop(":method", None) + headers.pop(":scheme", None) + headers.pop(":path", None) host = None port = None diff --git a/netlib/multidict.py b/netlib/multidict.py index 50c879d9..51053ff6 100644 --- a/netlib/multidict.py +++ b/netlib/multidict.py @@ -170,18 +170,10 @@ class _MultiDict(MutableMapping, basetypes.Serializable): else: return super(_MultiDict, self).items() - def clear(self, key): - """ - Removes all items with the specified key, and does not raise an - exception if the key does not exist. - """ - if key in self: - del self[key] - def collect(self): """ Returns a list of (key, value) tuples, where values are either - singular if threre is only one matching item for a key, or a list + singular if there is only one matching item for a key, or a list if there are more than one. The order of the keys matches the order in the underlying fields list. """ @@ -204,18 +196,16 @@ class _MultiDict(MutableMapping, basetypes.Serializable): .. code-block:: python # Simple dict with duplicate values. - >>> d - MultiDictView[("name", "value"), ("a", "false"), ("a", "42")] + >>> d = MultiDict([("name", "value"), ("a", False), ("a", 42)]) >>> d.to_dict() { "name": "value", - "a": ["false", "42"] + "a": [False, 42] } """ - d = {} - for k, v in self.collect(): - d[k] = v - return d + return { + k: v for k, v in self.collect() + } def get_state(self): return self.fields @@ -307,4 +297,4 @@ class MultiDictView(_MultiDict): @fields.setter def fields(self, value): - return self._setter(value) + self._setter(value) -- cgit v1.2.3 From 64a867973d5bac136c2e1c3c11c457d6b04d6649 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Wed, 6 Jul 2016 21:03:17 -0700 Subject: sni is now str, not bytes --- netlib/tcp.py | 4 ++-- netlib/utils.py | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'netlib') diff --git a/netlib/tcp.py b/netlib/tcp.py index 69dafc1f..cf099edd 100644 --- a/netlib/tcp.py +++ b/netlib/tcp.py @@ -676,7 +676,7 @@ class TCPClient(_Connection): self.connection = SSL.Connection(context, self.connection) if sni: self.sni = sni - self.connection.set_tlsext_host_name(sni) + self.connection.set_tlsext_host_name(sni.encode("idna")) self.connection.set_connect_state() try: self.connection.do_handshake() @@ -705,7 +705,7 @@ class TCPClient(_Connection): if self.cert.cn: crt["subject"] = [[["commonName", self.cert.cn.decode("ascii", "strict")]]] if sni: - hostname = sni.decode("ascii", "strict") + hostname = sni else: hostname = "no-hostname" ssl_match_hostname.match_hostname(crt, hostname) diff --git a/netlib/utils.py b/netlib/utils.py index 79340cbd..23c16dc3 100644 --- a/netlib/utils.py +++ b/netlib/utils.py @@ -73,11 +73,9 @@ _label_valid = re.compile(b"(?!-)[A-Z\d-]{1,63}(? bool """ Checks if a hostname is valid. - - Args: - host (bytes): The hostname """ try: host.decode("idna") -- cgit v1.2.3 From f62e976e1e0245665aeeb08fa801661d6c766ba8 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 7 Jul 2016 17:29:22 -0700 Subject: py3++ --- netlib/http/message.py | 3 +++ netlib/http/request.py | 14 +++++++++++++- netlib/http/response.py | 7 +++++++ 3 files changed, 23 insertions(+), 1 deletion(-) (limited to 'netlib') diff --git a/netlib/http/message.py b/netlib/http/message.py index 0583c246..b268fec9 100644 --- a/netlib/http/message.py +++ b/netlib/http/message.py @@ -100,7 +100,10 @@ class Message(basetypes.Serializable): @content.setter def content(self, content): + # type: (Optional[bytes]) -> None self.data.content = content + if isinstance(content, six.text_type): + raise ValueError("Message content must be bytes, not {}".format(type(content).__name__)) if isinstance(content, bytes): self.headers["content-length"] = str(len(content)) diff --git a/netlib/http/request.py b/netlib/http/request.py index d9f4ed00..c4c39942 100644 --- a/netlib/http/request.py +++ b/netlib/http/request.py @@ -23,8 +23,20 @@ host_header_re = re.compile(r"^(?P[^:]+|\[.+\])(?::(?P\d+))?$") class RequestData(message.MessageData): def __init__(self, first_line_format, method, scheme, host, port, path, http_version, headers=(), content=None, timestamp_start=None, timestamp_end=None): + if isinstance(method, six.text_type): + method = method.encode("ascii", "strict") + if isinstance(scheme, six.text_type): + scheme = scheme.encode("ascii", "strict") + if isinstance(host, six.text_type): + host = host.encode("idna", "strict") + if isinstance(path, six.text_type): + path = path.encode("ascii", "strict") + if isinstance(http_version, six.text_type): + http_version = http_version.encode("ascii", "strict") if not isinstance(headers, nheaders.Headers): headers = nheaders.Headers(headers) + if isinstance(content, six.text_type): + raise ValueError("Content must be bytes, not {}".format(type(content).__name__)) self.first_line_format = first_line_format self.method = method @@ -356,7 +368,7 @@ class Request(message.Message): This will overwrite the existing content if there is one. """ self.headers["content-type"] = "application/x-www-form-urlencoded" - self.content = netlib.http.url.encode(value) + self.content = netlib.http.url.encode(value).encode() @urlencoded_form.setter def urlencoded_form(self, value): diff --git a/netlib/http/response.py b/netlib/http/response.py index 17d69418..7cfb55c8 100644 --- a/netlib/http/response.py +++ b/netlib/http/response.py @@ -2,6 +2,7 @@ from __future__ import absolute_import, print_function, division from email.utils import parsedate_tz, formatdate, mktime_tz import time +import six from netlib.http import cookies from netlib.http import headers as nheaders @@ -13,8 +14,14 @@ from netlib import human class ResponseData(message.MessageData): def __init__(self, http_version, status_code, reason=None, headers=(), content=None, timestamp_start=None, timestamp_end=None): + if isinstance(http_version, six.text_type): + http_version = http_version.encode("ascii", "strict") + if isinstance(reason, six.text_type): + reason = reason.encode("ascii", "strict") if not isinstance(headers, nheaders.Headers): headers = nheaders.Headers(headers) + if isinstance(content, six.text_type): + raise ValueError("Content must be bytes, not {}".format(type(content).__name__)) self.http_version = http_version self.status_code = status_code -- cgit v1.2.3 From 00dce240150595e41719e512f1b156103c3c9c31 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 7 Jul 2016 18:02:59 -0700 Subject: tests++ --- netlib/strutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'netlib') diff --git a/netlib/strutils.py b/netlib/strutils.py index cda70651..7d49e56e 100644 --- a/netlib/strutils.py +++ b/netlib/strutils.py @@ -119,7 +119,7 @@ def is_mostly_bin(s): return sum( i < 9 or 13 < i < 32 or 126 < i for i in six.iterbytes(s[:100]) - ) > 30 + ) / len(s[:100]) > 0.3 def is_xml(s): -- cgit v1.2.3 From 7a5b21556b7c707ed3da8d6fa3ece8119ea38630 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 7 Jul 2016 19:34:57 -0700 Subject: fix tests --- netlib/strutils.py | 1 + 1 file changed, 1 insertion(+) (limited to 'netlib') diff --git a/netlib/strutils.py b/netlib/strutils.py index 7d49e56e..9208f954 100644 --- a/netlib/strutils.py +++ b/netlib/strutils.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import, print_function, division import re import codecs -- cgit v1.2.3 From 0a1431ed2c638ceb34308d38250eab2717640c49 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Fri, 8 Jul 2016 15:49:38 -0700 Subject: fix #1314 --- netlib/debug.py | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) (limited to 'netlib') diff --git a/netlib/debug.py b/netlib/debug.py index a395afcb..fcd72a21 100644 --- a/netlib/debug.py +++ b/netlib/debug.py @@ -7,8 +7,6 @@ import signal import platform import traceback -import psutil - from netlib import version from OpenSSL import SSL @@ -40,15 +38,32 @@ def sysinfo(): def dump_info(sig, frm, file=sys.stdout): # pragma: no cover - p = psutil.Process() - print("****************************************************", file=file) print("Summary", file=file) print("=======", file=file) - print("num threads: ", p.num_threads(), file=file) - if hasattr(p, "num_fds"): - print("num fds: ", p.num_fds(), file=file) - print("memory: ", p.memory_info(), file=file) + + try: + import psutil + except: + print("(psutil not installed, skipping some debug info)", file=file) + else: + p = psutil.Process() + print("num threads: ", p.num_threads(), file=file) + if hasattr(p, "num_fds"): + print("num fds: ", p.num_fds(), file=file) + print("memory: ", p.memory_info(), file=file) + + print(file=file) + print("Files", file=file) + print("=====", file=file) + for i in p.open_files(): + print(i, file=file) + + print(file=file) + print("Connections", file=file) + print("===========", file=file) + for i in p.connections(): + print(i, file=file) print(file=file) print("Threads", file=file) @@ -63,18 +78,6 @@ def dump_info(sig, frm, file=sys.stdout): # pragma: no cover for i in bthreads: print(i._threadinfo(), file=file) - print(file=file) - print("Files", file=file) - print("=====", file=file) - for i in p.open_files(): - print(i, file=file) - - print(file=file) - print("Connections", file=file) - print("===========", file=file) - for i in p.connections(): - print(i, file=file) - print("****************************************************", file=file) -- cgit v1.2.3 From 0a21d270046f97a8d7da4378ca3a54b4a7f898b8 Mon Sep 17 00:00:00 2001 From: Shadab Zafar Date: Sat, 9 Jul 2016 12:43:21 +0530 Subject: strutils.hexdump returns native_strings --- netlib/strutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'netlib') diff --git a/netlib/strutils.py b/netlib/strutils.py index 9208f954..a51df886 100644 --- a/netlib/strutils.py +++ b/netlib/strutils.py @@ -146,7 +146,7 @@ def hexdump(s): A generator of (offset, hex, str) tuples """ for i in range(0, len(s), 16): - offset = "{:0=10x}".format(i).encode() + offset = "{:0=10x}".format(i) part = s[i:i + 16] x = " ".join("{:0=2x}".format(i) for i in six.iterbytes(part)) x = x.ljust(47) # 16*2 + 15 -- cgit v1.2.3 From 83a1cc5a9a62dbe22bd9e87f496928ae1664da2b Mon Sep 17 00:00:00 2001 From: Shadab Zafar Date: Sat, 9 Jul 2016 12:57:55 +0530 Subject: Make escape_control_characters handle strings on Py2 --- netlib/strutils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'netlib') diff --git a/netlib/strutils.py b/netlib/strutils.py index a51df886..32e77927 100644 --- a/netlib/strutils.py +++ b/netlib/strutils.py @@ -57,8 +57,8 @@ def escape_control_characters(text, keep_spacing=True): Args: keep_spacing: If True, tabs and newlines will not be replaced. """ - # type: (six.text_type) -> six.text_type - if not isinstance(text, six.text_type): + # type: (six.string_types) -> six.text_type + if not isinstance(text, six.string_types): raise ValueError("text type must be unicode but is {}".format(type(text).__name__)) trans = _control_char_trans_newline if keep_spacing else _control_char_trans -- cgit v1.2.3 From c92992f03bba6553ec39fc42e6716beb942967e3 Mon Sep 17 00:00:00 2001 From: Shadab Zafar Date: Fri, 8 Jul 2016 14:16:29 +0530 Subject: Move cookie expiry detection to separate function --- netlib/http/cookies.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'netlib') diff --git a/netlib/http/cookies.py b/netlib/http/cookies.py index 768a85df..90789365 100644 --- a/netlib/http/cookies.py +++ b/netlib/http/cookies.py @@ -1,7 +1,8 @@ import collections +import email.utils import re +import time -import email.utils from netlib import multidict """ @@ -260,3 +261,24 @@ def refresh_set_cookie_header(c, delta): if not ret: raise ValueError("Invalid Cookie") return ret + +def is_expired(cookie_attrs): + """ + Determines whether a cookie has expired. + + Returns: boolean + """ + expired = False + + # See if 'expires' time is in the past + if 'expires' in cookie_attrs: + e = email.utils.parsedate_tz(cookie_attrs["expires"]) + if e: + exp_ts = email.utils.mktime_tz(e) + now_ts = time.time() + expired = exp_ts < now_ts + + # or if Max-Age is 0 + expired = expired or (int(cookie_attrs.get('Max-Age', 1)) == 0) + + return expired -- cgit v1.2.3 From 39f51084003b93a2e9868f7a56acfc29c12ed79e Mon Sep 17 00:00:00 2001 From: Shadab Zafar Date: Sun, 10 Jul 2016 01:06:50 +0530 Subject: Test cookies.is_expired separately --- netlib/http/cookies.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'netlib') diff --git a/netlib/http/cookies.py b/netlib/http/cookies.py index 90789365..dd0af99c 100644 --- a/netlib/http/cookies.py +++ b/netlib/http/cookies.py @@ -262,23 +262,28 @@ def refresh_set_cookie_header(c, delta): raise ValueError("Invalid Cookie") return ret + def is_expired(cookie_attrs): """ Determines whether a cookie has expired. Returns: boolean """ - expired = False # See if 'expires' time is in the past + expires = False if 'expires' in cookie_attrs: e = email.utils.parsedate_tz(cookie_attrs["expires"]) if e: exp_ts = email.utils.mktime_tz(e) now_ts = time.time() - expired = exp_ts < now_ts + expires = exp_ts < now_ts # or if Max-Age is 0 - expired = expired or (int(cookie_attrs.get('Max-Age', 1)) == 0) + max_age = False + try: + max_age = int(cookie_attrs.get('Max-Age', 1)) == 0 + except ValueError: + pass - return expired + return expires or max_age -- cgit v1.2.3 From c90de8b9a40124c9e859d00d995e3e8133941a12 Mon Sep 17 00:00:00 2001 From: Thomas Kriechbaumer Date: Sun, 10 Jul 2016 13:16:23 +0200 Subject: fix sysinfo for py3 --- netlib/debug.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'netlib') diff --git a/netlib/debug.py b/netlib/debug.py index fcd72a21..29c7f655 100644 --- a/netlib/debug.py +++ b/netlib/debug.py @@ -17,7 +17,7 @@ def sysinfo(): "Mitmproxy version: %s" % version.VERSION, "Python version: %s" % platform.python_version(), "Platform: %s" % platform.platform(), - "SSL version: %s" % SSL.SSLeay_version(SSL.SSLEAY_VERSION), + "SSL version: %s" % SSL.SSLeay_version(SSL.SSLEAY_VERSION).decode(), ] d = platform.linux_distribution() t = "Linux distro: %s %s %s" % d -- cgit v1.2.3 From b94f5fd361af6255ad4d3c7a88b9a21868736dea Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Thu, 14 Jul 2016 16:20:27 +1200 Subject: Convert examples and example tests for new-style scripts Remove the test that just loads all the example scripts for now - it's a very low-value test, and we need to think of something better. --- netlib/utils.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'netlib') diff --git a/netlib/utils.py b/netlib/utils.py index 23c16dc3..9eebf22c 100644 --- a/netlib/utils.py +++ b/netlib/utils.py @@ -56,6 +56,13 @@ class Data(object): dirname = os.path.dirname(inspect.getsourcefile(m)) self.dirname = os.path.abspath(dirname) + def push(self, subpath): + """ + Change the data object to a path relative to the module. + """ + self.dirname = os.path.join(self.dirname, subpath) + return self + def path(self, path): """ Returns a path to the package data housed at 'path' under this -- cgit v1.2.3