if "Connection" not in self.request.headers:
self.request.headers["Connection"] = "close"
if "Host" not in self.request.headers:
- self.request.headers["Host"] = parsed.netloc
+ if '@' in parsed.netloc:
+ self.request.headers["Host"] = parsed.netloc.rpartition('@')[-1]
+ else:
+ self.request.headers["Host"] = parsed.netloc
username, password = None, None
if parsed.username is not None:
username, password = parsed.username, parsed.password
import collections
import gzip
import logging
+import re
import socket
from tornado.ioloop import IOLoop
assert not self.request.body
self.write("ok")
+class HostEchoHandler(RequestHandler):
+ def get(self):
+ self.write(self.request.headers["Host"])
+
class SimpleHTTPClientTestCase(AsyncHTTPTestCase, LogTrapTestCase):
def setUp(self):
url("/no_content", NoContentHandler),
url("/303_post", SeeOther303PostHandler),
url("/303_get", SeeOther303GetHandler),
+ url("/host_echo", HostEchoHandler),
], gzip=True)
def test_singleton(self):
# 204 status with non-zero content length is malformed
response = self.fetch("/no_content?error=1")
self.assertEqual(response.code, 599)
+
+ def test_host_header(self):
+ host_re = re.compile(b("^localhost:[0-9]+$"))
+ response = self.fetch("/host_echo")
+ self.assertTrue(host_re.match(response.body))
+
+ url = self.get_url("/host_echo").replace("http://", "http://me:secret@")
+ self.http_client.fetch(url, self.stop)
+ response = self.wait()
+ self.assertTrue(host_re.match(response.body), response.body)
method).
* The ``Etag`` header is now returned on 304 responses to an ``If-None-Match``
request, improving compatibility with some caches.
+* `tornado.simple_httpclient` no longer includes basic auth credentials
+ in the ``Host`` header when those credentials are extracted from the URL.