From 56ec1ee597f91fb59ec660dfe7a4fdd68f2209eb Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Sun, 19 Feb 2012 19:33:08 -0800 Subject: [PATCH] Pass parsed hostname around explictly instead of storing it on the urlsplit result. In some versions of python (including 2.5 and 3.2 but not 2.6 or 2.7), urlsplit results use __slots__ and therefore don't allow artibrary attributes to be set. Also move the storing of the parsed hostname above hostname_mapping, since the cert should be checked against the requested url, not the remapped one. Closes #448. --- tornado/simple_httpclient.py | 15 +++++++++------ tornado/test/httpserver_test.py | 2 +- website/sphinx/releases/next.rst | 2 ++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/tornado/simple_httpclient.py b/tornado/simple_httpclient.py index 9617472bc..aa2bec637 100644 --- a/tornado/simple_httpclient.py +++ b/tornado/simple_httpclient.py @@ -160,9 +160,9 @@ class _HTTPConnection(object): if re.match(r'^\[.*\]$', host): # raw ipv6 addresses in urls are enclosed in brackets host = host[1:-1] + parsed_hostname = host # save final parsed host for _on_connect if self.client.hostname_mapping is not None: host = self.client.hostname_mapping.get(host, host) - parsed._hostname = host # save correct hostname for _on_connect if request.allow_ipv6: af = socket.AF_UNSPEC @@ -222,7 +222,8 @@ class _HTTPConnection(object): self._on_timeout) self.stream.set_close_callback(self._on_close) self.stream.connect(sockaddr, - functools.partial(self._on_connect, parsed)) + functools.partial(self._on_connect, parsed, + parsed_hostname)) def _on_timeout(self): self._timeout = None @@ -231,7 +232,7 @@ class _HTTPConnection(object): error=HTTPError(599, "Timeout"))) self.stream.close() - def _on_connect(self, parsed): + def _on_connect(self, parsed, parsed_hostname): if self._timeout is not None: self.io_loop.remove_timeout(self._timeout) self._timeout = None @@ -242,9 +243,11 @@ class _HTTPConnection(object): if (self.request.validate_cert and isinstance(self.stream, SSLIOStream)): match_hostname(self.stream.socket.getpeercert(), - # ipv6 addresses are broken until 2.7, here is - # correctly parsed value calculated in __init__ - parsed._hostname) + # ipv6 addresses are broken (in + # parsed.hostname) until 2.7, here is + # correctly parsed value calculated in + # __init__ + parsed_hostname) if (self.request.method not in self._SUPPORTED_METHODS and not self.request.allow_nonstandard_methods): raise KeyError("unknown method %s" % self.request.method) diff --git a/tornado/test/httpserver_test.py b/tornado/test/httpserver_test.py index 01f8f837e..71134f115 100644 --- a/tornado/test/httpserver_test.py +++ b/tornado/test/httpserver_test.py @@ -173,7 +173,7 @@ class RawRequestHTTPConnection(simple_httpclient._HTTPConnection): def set_request(self, request): self.__next_request = request - def _on_connect(self, parsed): + def _on_connect(self, parsed, parsed_hostname): self.stream.write(self.__next_request) self.__next_request = None self.stream.read_until(b("\r\n\r\n"), self._on_headers) diff --git a/website/sphinx/releases/next.rst b/website/sphinx/releases/next.rst index 107507ce4..a6c7faf41 100644 --- a/website/sphinx/releases/next.rst +++ b/website/sphinx/releases/next.rst @@ -11,3 +11,5 @@ In progress instead of leaving them for garbage collection. * Repeated calls to `RequestHandler.set_cookie` with the same name now overwrite the previous cookie instead of producing additional copies. +* `tornado.simple_httpclient` correctly verifies SSL certificates for + URLs containing IPv6 literals (This bug affected Python 2.5 and 2.6). -- 2.47.3