diff options
Diffstat (limited to 'tests/test_functional.py')
-rw-r--r-- | tests/test_functional.py | 448 |
1 files changed, 214 insertions, 234 deletions
diff --git a/tests/test_functional.py b/tests/test_functional.py index 9d94b8e..968fbe6 100644 --- a/tests/test_functional.py +++ b/tests/test_functional.py @@ -1,4 +1,5 @@ import errno +from http import client as httplib import logging import multiprocessing import os @@ -11,7 +12,6 @@ import time import unittest from waitress import server -from waitress.compat import httplib, tobytes from waitress.utilities import cleanup_unix_socket dn = os.path.dirname @@ -57,6 +57,7 @@ class FixtureTcpWSGIServer(server.TcpWSGIServer): kw["port"] = 0 # Bind to any available port. super().__init__(application, **kw) host, port = self.socket.getsockname() + if os.name == "nt": host = "127.0.0.1" queue.put((host, port)) @@ -99,9 +100,9 @@ class SubprocessTests: def assertline(self, line, status, reason, version): v, s, r = (x.strip() for x in line.split(None, 2)) - self.assertEqual(s, tobytes(status)) - self.assertEqual(r, tobytes(reason)) - self.assertEqual(v, tobytes(version)) + self.assertEqual(s, status.encode("latin-1")) + self.assertEqual(r, reason.encode("latin-1")) + self.assertEqual(v, version.encode("latin-1")) def create_socket(self): return socket.socket(self.server.family, socket.SOCK_STREAM) @@ -143,9 +144,11 @@ class SleepyThreadTests(TcpTests, unittest.TestCase): ) r, w = os.pipe() procs = [] + for cmd in cmds: procs.append(subprocess.Popen(cmd, stdout=w)) time.sleep(3) + for proc in procs: if proc.returncode is not None: # pragma: no cover proc.terminate() @@ -178,11 +181,11 @@ class EchoTests: from tests.fixtureapps import echo line, headers, body = read_http(fp) + return line, headers, echo.parse_response(body) def test_date_and_server(self): - to_send = "GET / HTTP/1.0\r\nContent-Length: 0\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET / HTTP/1.0\r\nContent-Length: 0\r\n\r\n" self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -193,8 +196,7 @@ class EchoTests: def test_bad_host_header(self): # https://corte.si/posts/code/pathod/pythonservers/index.html - to_send = "GET / HTTP/1.0\r\n Host: 0\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET / HTTP/1.0\r\n Host: 0\r\n\r\n" self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -204,9 +206,8 @@ class EchoTests: self.assertTrue(headers.get("date")) def test_send_with_body(self): - to_send = "GET / HTTP/1.0\r\nContent-Length: 5\r\n\r\n" - to_send += "hello" - to_send = tobytes(to_send) + to_send = b"GET / HTTP/1.0\r\nContent-Length: 5\r\n\r\n" + to_send += b"hello" self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -216,8 +217,7 @@ class EchoTests: self.assertEqual(echo.body, b"hello") def test_send_empty_body(self): - to_send = "GET / HTTP/1.0\r\nContent-Length: 0\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET / HTTP/1.0\r\nContent-Length: 0\r\n\r\n" self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -228,6 +228,7 @@ class EchoTests: def test_multiple_requests_with_body(self): orig_sock = self.sock + for x in range(3): self.sock = self.create_socket() self.test_send_with_body() @@ -236,6 +237,7 @@ class EchoTests: def test_multiple_requests_without_body(self): orig_sock = self.sock + for x in range(3): self.sock = self.create_socket() self.test_send_empty_body() @@ -243,13 +245,13 @@ class EchoTests: self.sock = orig_sock def test_without_crlf(self): - data = "Echo\r\nthis\r\nplease" - s = tobytes( - "GET / HTTP/1.0\r\n" - "Connection: close\r\n" - "Content-Length: %d\r\n" - "\r\n" - "%s" % (len(data), data) + data = b"Echo\r\nthis\r\nplease" + s = ( + b"GET / HTTP/1.0\r\n" + b"Connection: close\r\n" + b"Content-Length: %d\r\n" + b"\r\n" + b"%s" % (len(data), data) ) self.connect() self.sock.send(s) @@ -258,40 +260,42 @@ class EchoTests: self.assertline(line, "200", "OK", "HTTP/1.0") self.assertEqual(int(echo.content_length), len(data)) self.assertEqual(len(echo.body), len(data)) - self.assertEqual(echo.body, tobytes(data)) + self.assertEqual(echo.body, (data)) def test_large_body(self): # 1024 characters. - body = "This string has 32 characters.\r\n" * 32 - s = tobytes( - "GET / HTTP/1.0\r\nContent-Length: %d\r\n\r\n%s" % (len(body), body) - ) + body = b"This string has 32 characters.\r\n" * 32 + s = b"GET / HTTP/1.0\r\nContent-Length: %d\r\n\r\n%s" % (len(body), body) self.connect() self.sock.send(s) fp = self.sock.makefile("rb", 0) line, headers, echo = self._read_echo(fp) self.assertline(line, "200", "OK", "HTTP/1.0") self.assertEqual(echo.content_length, "1024") - self.assertEqual(echo.body, tobytes(body)) + self.assertEqual(echo.body, body) def test_many_clients(self): conns = [] + for n in range(50): h = self.make_http_connection() h.request("GET", "/", headers={"Accept": "text/plain"}) conns.append(h) responses = [] + for h in conns: response = h.getresponse() self.assertEqual(response.status, 200) responses.append(response) + for response in responses: response.read() + for h in conns: h.close() def test_chunking_request_without_content(self): - header = tobytes("GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n") + header = b"GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n" self.connect() self.sock.send(header) self.sock.send(b"0\r\n\r\n") @@ -306,10 +310,11 @@ class EchoTests: control_line = b"20;\r\n" # 20 hex = 32 dec s = b"This string has 32 characters.\r\n" expected = s * 12 - header = tobytes("GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n") + header = b"GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n" self.connect() self.sock.send(header) fp = self.sock.makefile("rb", 0) + for n in range(12): self.sock.send(control_line) self.sock.send(s) @@ -322,13 +327,12 @@ class EchoTests: self.assertFalse("transfer-encoding" in headers) def test_broken_chunked_encoding(self): - control_line = "20;\r\n" # 20 hex = 32 dec - s = "This string has 32 characters.\r\n" - to_send = "GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n" - to_send += control_line + s + "\r\n" + control_line = b"20;\r\n" # 20 hex = 32 dec + s = b"This string has 32 characters.\r\n" + to_send = b"GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n" + to_send += control_line + s + b"\r\n" # garbage in input - to_send += "garbage\r\n" - to_send = tobytes(to_send) + to_send += b"garbage\r\n" self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -347,13 +351,12 @@ class EchoTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_broken_chunked_encoding_missing_chunk_end(self): - control_line = "20;\r\n" # 20 hex = 32 dec - s = "This string has 32 characters.\r\n" - to_send = "GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n" + control_line = b"20;\r\n" # 20 hex = 32 dec + s = b"This string has 32 characters.\r\n" + to_send = b"GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n" to_send += control_line + s # garbage in input - to_send += "garbage" - to_send = tobytes(to_send) + to_send += b"garbage" self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -374,10 +377,8 @@ class EchoTests: def test_keepalive_http_10(self): # Handling of Keep-Alive within HTTP 1.0 - data = "Default: Don't keep me alive" - s = tobytes( - "GET / HTTP/1.0\r\nContent-Length: %d\r\n\r\n%s" % (len(data), data) - ) + data = b"Default: Don't keep me alive" + s = b"GET / HTTP/1.0\r\nContent-Length: %d\r\n\r\n%s" % (len(data), data) self.connect() self.sock.send(s) response = httplib.HTTPResponse(self.sock) @@ -392,13 +393,13 @@ class EchoTests: # If header Connection: Keep-Alive is explicitly sent, # we want to keept the connection open, we also need to return # the corresponding header - data = "Keep me alive" - s = tobytes( - "GET / HTTP/1.0\r\n" - "Connection: Keep-Alive\r\n" - "Content-Length: %d\r\n" - "\r\n" - "%s" % (len(data), data) + data = b"Keep me alive" + s = ( + b"GET / HTTP/1.0\r\n" + b"Connection: Keep-Alive\r\n" + b"Content-Length: %d\r\n" + b"\r\n" + b"%s" % (len(data), data) ) self.connect() self.sock.send(s) @@ -412,10 +413,8 @@ class EchoTests: # Handling of Keep-Alive within HTTP 1.1 # All connections are kept alive, unless stated otherwise - data = "Default: Keep me alive" - s = tobytes( - "GET / HTTP/1.1\r\nContent-Length: %d\r\n\r\n%s" % (len(data), data) - ) + data = b"Default: Keep me alive" + s = b"GET / HTTP/1.1\r\nContent-Length: %d\r\n\r\n%s" % (len(data), data) self.connect() self.sock.send(s) response = httplib.HTTPResponse(self.sock) @@ -425,13 +424,13 @@ class EchoTests: def test_keepalive_http11_explicit(self): # Explicitly set keep-alive - data = "Default: Keep me alive" - s = tobytes( - "GET / HTTP/1.1\r\n" - "Connection: keep-alive\r\n" - "Content-Length: %d\r\n" - "\r\n" - "%s" % (len(data), data) + data = b"Default: Keep me alive" + s = ( + b"GET / HTTP/1.1\r\n" + b"Connection: keep-alive\r\n" + b"Content-Length: %d\r\n" + b"\r\n" + b"%s" % (len(data), data) ) self.connect() self.sock.send(s) @@ -442,13 +441,13 @@ class EchoTests: def test_keepalive_http11_connclose(self): # specifying Connection: close explicitly - data = "Don't keep me alive" - s = tobytes( - "GET / HTTP/1.1\r\n" - "Connection: close\r\n" - "Content-Length: %d\r\n" - "\r\n" - "%s" % (len(data), data) + data = b"Don't keep me alive" + s = ( + b"GET / HTTP/1.1\r\n" + b"Connection: close\r\n" + b"Content-Length: %d\r\n" + b"\r\n" + b"%s" % (len(data), data) ) self.connect() self.sock.send(s) @@ -459,14 +458,13 @@ class EchoTests: def test_proxy_headers(self): to_send = ( - "GET / HTTP/1.0\r\n" - "Content-Length: 0\r\n" - "Host: www.google.com:8080\r\n" - "X-Forwarded-For: 192.168.1.1\r\n" - "X-Forwarded-Proto: https\r\n" - "X-Forwarded-Port: 5000\r\n\r\n" + b"GET / HTTP/1.0\r\n" + b"Content-Length: 0\r\n" + b"Host: www.google.com:8080\r\n" + b"X-Forwarded-For: 192.168.1.1\r\n" + b"X-Forwarded-Proto: https\r\n" + b"X-Forwarded-Port: 5000\r\n\r\n" ) - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -492,27 +490,30 @@ class PipeliningTests: def test_pipelining(self): s = ( - "GET / HTTP/1.0\r\n" - "Connection: %s\r\n" - "Content-Length: %d\r\n" - "\r\n" - "%s" + b"GET / HTTP/1.0\r\n" + b"Connection: %s\r\n" + b"Content-Length: %d\r\n" + b"\r\n" + b"%s" ) to_send = b"" count = 25 + for n in range(count): - body = "Response #%d\r\n" % (n + 1) + body = b"Response #%d\r\n" % (n + 1) + if n + 1 < count: - conn = "keep-alive" + conn = b"keep-alive" else: - conn = "close" - to_send += tobytes(s % (conn, len(body), body)) + conn = b"close" + to_send += s % (conn, len(body), body) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) + for n in range(count): - expect_body = tobytes("Response #%d\r\n" % (n + 1)) + expect_body = b"Response #%d\r\n" % (n + 1) line = fp.readline() # status line version, status, reason = (x.strip() for x in line.split(None, 2)) headers = parse_headers(fp) @@ -534,14 +535,14 @@ class ExpectContinueTests: def test_expect_continue(self): # specifying Connection: close explicitly - data = "I have expectations" - to_send = tobytes( - "GET / HTTP/1.1\r\n" - "Connection: close\r\n" - "Content-Length: %d\r\n" - "Expect: 100-continue\r\n" - "\r\n" - "%s" % (len(data), data) + data = b"I have expectations" + to_send = ( + b"GET / HTTP/1.1\r\n" + b"Connection: close\r\n" + b"Content-Length: %d\r\n" + b"Expect: 100-continue\r\n" + b"\r\n" + b"%s" % (len(data), data) ) self.connect() self.sock.send(to_send) @@ -559,7 +560,7 @@ class ExpectContinueTests: response_body = fp.read(length) self.assertEqual(int(status), 200) self.assertEqual(length, len(response_body)) - self.assertEqual(response_body, tobytes(data)) + self.assertEqual(response_body, data) class BadContentLengthTests: @@ -574,11 +575,11 @@ class BadContentLengthTests: def test_short_body(self): # check to see if server closes connection when body is too short # for cl header - to_send = tobytes( - "GET /short_body HTTP/1.0\r\n" - "Connection: Keep-Alive\r\n" - "Content-Length: 0\r\n" - "\r\n" + to_send = ( + b"GET /short_body HTTP/1.0\r\n" + b"Connection: Keep-Alive\r\n" + b"Content-Length: 0\r\n" + b"\r\n" ) self.connect() self.sock.send(to_send) @@ -591,7 +592,7 @@ class BadContentLengthTests: self.assertEqual(int(status), 200) self.assertNotEqual(content_length, len(response_body)) self.assertEqual(len(response_body), content_length - 1) - self.assertEqual(response_body, tobytes("abcdefghi")) + self.assertEqual(response_body, b"abcdefghi") # remote closed connection (despite keepalive header); not sure why # first send succeeds self.send_check_error(to_send) @@ -600,11 +601,11 @@ class BadContentLengthTests: def test_long_body(self): # check server doesnt close connection when body is too short # for cl header - to_send = tobytes( - "GET /long_body HTTP/1.0\r\n" - "Connection: Keep-Alive\r\n" - "Content-Length: 0\r\n" - "\r\n" + to_send = ( + b"GET /long_body HTTP/1.0\r\n" + b"Connection: Keep-Alive\r\n" + b"Content-Length: 0\r\n" + b"\r\n" ) self.connect() self.sock.send(to_send) @@ -616,7 +617,7 @@ class BadContentLengthTests: response_body = fp.read(content_length) self.assertEqual(int(status), 200) self.assertEqual(content_length, len(response_body)) - self.assertEqual(response_body, tobytes("abcdefgh")) + self.assertEqual(response_body, b"abcdefgh") # remote does not close connection (keepalive header) self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -638,14 +639,13 @@ class NoContentLengthTests: self.stop_subprocess() def test_http10_generator(self): - body = string.ascii_letters + body = string.ascii_letters.encode("latin-1") to_send = ( - "GET / HTTP/1.0\r\n" - "Connection: Keep-Alive\r\n" - "Content-Length: %d\r\n\r\n" % len(body) + b"GET / HTTP/1.0\r\n" + b"Connection: Keep-Alive\r\n" + b"Content-Length: %d\r\n\r\n" % len(body) ) to_send += body - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -653,21 +653,20 @@ class NoContentLengthTests: self.assertline(line, "200", "OK", "HTTP/1.0") self.assertEqual(headers.get("content-length"), None) self.assertEqual(headers.get("connection"), "close") - self.assertEqual(response_body, tobytes(body)) + self.assertEqual(response_body, body) # remote closed connection (despite keepalive header), because # generators cannot have a content-length divined self.send_check_error(to_send) self.assertRaises(ConnectionClosed, read_http, fp) def test_http10_list(self): - body = string.ascii_letters + body = string.ascii_letters.encode("latin-1") to_send = ( - "GET /list HTTP/1.0\r\n" - "Connection: Keep-Alive\r\n" - "Content-Length: %d\r\n\r\n" % len(body) + b"GET /list HTTP/1.0\r\n" + b"Connection: Keep-Alive\r\n" + b"Content-Length: %d\r\n\r\n" % len(body) ) to_send += body - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -675,7 +674,7 @@ class NoContentLengthTests: self.assertline(line, "200", "OK", "HTTP/1.0") self.assertEqual(headers["content-length"], str(len(body))) self.assertEqual(headers.get("connection"), "Keep-Alive") - self.assertEqual(response_body, tobytes(body)) + self.assertEqual(response_body, body) # remote keeps connection open because it divined the content length # from a length-1 list self.sock.send(to_send) @@ -683,14 +682,13 @@ class NoContentLengthTests: self.assertline(line, "200", "OK", "HTTP/1.0") def test_http10_listlentwo(self): - body = string.ascii_letters + body = string.ascii_letters.encode("latin-1") to_send = ( - "GET /list_lentwo HTTP/1.0\r\n" - "Connection: Keep-Alive\r\n" - "Content-Length: %d\r\n\r\n" % len(body) + b"GET /list_lentwo HTTP/1.0\r\n" + b"Connection: Keep-Alive\r\n" + b"Content-Length: %d\r\n\r\n" % len(body) ) to_send += body - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -698,7 +696,7 @@ class NoContentLengthTests: self.assertline(line, "200", "OK", "HTTP/1.0") self.assertEqual(headers.get("content-length"), None) self.assertEqual(headers.get("connection"), "close") - self.assertEqual(response_body, tobytes(body)) + self.assertEqual(response_body, body) # remote closed connection (despite keepalive header), because # lists of length > 1 cannot have their content length divined self.send_check_error(to_send) @@ -706,18 +704,20 @@ class NoContentLengthTests: def test_http11_generator(self): body = string.ascii_letters - to_send = "GET / HTTP/1.1\r\nContent-Length: %s\r\n\r\n" % len(body) + body = body.encode("latin-1") + to_send = b"GET / HTTP/1.1\r\nContent-Length: %d\r\n\r\n" % len(body) to_send += body - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb") line, headers, response_body = read_http(fp) self.assertline(line, "200", "OK", "HTTP/1.1") expected = b"" + for chunk in chunks(body, 10): - expected += tobytes( - "%s\r\n%s\r\n" % (str(hex(len(chunk))[2:].upper()), chunk) + expected += b"%s\r\n%s\r\n" % ( + hex(len(chunk))[2:].upper().encode("latin-1"), + chunk, ) expected += b"0\r\n\r\n" self.assertEqual(response_body, expected) @@ -726,17 +726,16 @@ class NoContentLengthTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_http11_list(self): - body = string.ascii_letters - to_send = "GET /list HTTP/1.1\r\nContent-Length: %d\r\n\r\n" % len(body) + body = string.ascii_letters.encode("latin-1") + to_send = b"GET /list HTTP/1.1\r\nContent-Length: %d\r\n\r\n" % len(body) to_send += body - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) line, headers, response_body = read_http(fp) self.assertline(line, "200", "OK", "HTTP/1.1") self.assertEqual(headers["content-length"], str(len(body))) - self.assertEqual(response_body, tobytes(body)) + self.assertEqual(response_body, body) # remote keeps connection open because it divined the content length # from a length-1 list self.sock.send(to_send) @@ -744,19 +743,20 @@ class NoContentLengthTests: self.assertline(line, "200", "OK", "HTTP/1.1") def test_http11_listlentwo(self): - body = string.ascii_letters - to_send = "GET /list_lentwo HTTP/1.1\r\nContent-Length: %s\r\n\r\n" % len(body) + body = string.ascii_letters.encode("latin-1") + to_send = b"GET /list_lentwo HTTP/1.1\r\nContent-Length: %d\r\n\r\n" % len(body) to_send += body - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb") line, headers, response_body = read_http(fp) self.assertline(line, "200", "OK", "HTTP/1.1") expected = b"" - for chunk in (body[0], body[1:]): - expected += tobytes( - "%s\r\n%s\r\n" % (str(hex(len(chunk))[2:].upper()), chunk) + + for chunk in (body[:1], body[1:]): + expected += b"%s\r\n%s\r\n" % ( + (hex(len(chunk))[2:].upper().encode("latin-1")), + chunk, ) expected += b"0\r\n\r\n" self.assertEqual(response_body, expected) @@ -777,11 +777,11 @@ class WriteCallbackTests: def test_short_body(self): # check to see if server closes connection when body is too short # for cl header - to_send = tobytes( - "GET /short_body HTTP/1.0\r\n" - "Connection: Keep-Alive\r\n" - "Content-Length: 0\r\n" - "\r\n" + to_send = ( + b"GET /short_body HTTP/1.0\r\n" + b"Connection: Keep-Alive\r\n" + b"Content-Length: 0\r\n" + b"\r\n" ) self.connect() self.sock.send(to_send) @@ -793,7 +793,7 @@ class WriteCallbackTests: self.assertEqual(cl, 9) self.assertNotEqual(cl, len(response_body)) self.assertEqual(len(response_body), cl - 1) - self.assertEqual(response_body, tobytes("abcdefgh")) + self.assertEqual(response_body, b"abcdefgh") # remote closed connection (despite keepalive header) self.send_check_error(to_send) self.assertRaises(ConnectionClosed, read_http, fp) @@ -801,11 +801,11 @@ class WriteCallbackTests: def test_long_body(self): # check server doesnt close connection when body is too long # for cl header - to_send = tobytes( - "GET /long_body HTTP/1.0\r\n" - "Connection: Keep-Alive\r\n" - "Content-Length: 0\r\n" - "\r\n" + to_send = ( + b"GET /long_body HTTP/1.0\r\n" + b"Connection: Keep-Alive\r\n" + b"Content-Length: 0\r\n" + b"\r\n" ) self.connect() self.sock.send(to_send) @@ -814,7 +814,7 @@ class WriteCallbackTests: content_length = int(headers.get("content-length")) or None self.assertEqual(content_length, 9) self.assertEqual(content_length, len(response_body)) - self.assertEqual(response_body, tobytes("abcdefghi")) + self.assertEqual(response_body, b"abcdefghi") # remote does not close connection (keepalive header) self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -824,11 +824,11 @@ class WriteCallbackTests: def test_equal_body(self): # check server doesnt close connection when body is equal to # cl header - to_send = tobytes( - "GET /equal_body HTTP/1.0\r\n" - "Connection: Keep-Alive\r\n" - "Content-Length: 0\r\n" - "\r\n" + to_send = ( + b"GET /equal_body HTTP/1.0\r\n" + b"Connection: Keep-Alive\r\n" + b"Content-Length: 0\r\n" + b"\r\n" ) self.connect() self.sock.send(to_send) @@ -838,7 +838,7 @@ class WriteCallbackTests: self.assertEqual(content_length, 9) self.assertline(line, "200", "OK", "HTTP/1.0") self.assertEqual(content_length, len(response_body)) - self.assertEqual(response_body, tobytes("abcdefghi")) + self.assertEqual(response_body, b"abcdefghi") # remote does not close connection (keepalive header) self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -847,11 +847,11 @@ class WriteCallbackTests: def test_no_content_length(self): # wtf happens when there's no content-length - to_send = tobytes( - "GET /no_content_length HTTP/1.0\r\n" - "Connection: Keep-Alive\r\n" - "Content-Length: 0\r\n" - "\r\n" + to_send = ( + b"GET /no_content_length HTTP/1.0\r\n" + b"Connection: Keep-Alive\r\n" + b"Content-Length: 0\r\n" + b"\r\n" ) self.connect() self.sock.send(to_send) @@ -860,7 +860,7 @@ class WriteCallbackTests: line, headers, response_body = read_http(fp) content_length = headers.get("content-length") self.assertEqual(content_length, None) - self.assertEqual(response_body, tobytes("abcdefghi")) + self.assertEqual(response_body, b"abcdefghi") # remote closed connection (despite keepalive header) self.send_check_error(to_send) self.assertRaises(ConnectionClosed, read_http, fp) @@ -881,10 +881,9 @@ class TooLargeTests: self.stop_subprocess() def test_request_body_too_large_with_wrong_cl_http10(self): - body = "a" * self.toobig - to_send = "GET / HTTP/1.0\r\nContent-Length: 5\r\n\r\n" + body = b"a" * self.toobig + to_send = b"GET / HTTP/1.0\r\nContent-Length: 5\r\n\r\n" to_send += body - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb") @@ -900,12 +899,11 @@ class TooLargeTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_request_body_too_large_with_wrong_cl_http10_keepalive(self): - body = "a" * self.toobig + body = b"a" * self.toobig to_send = ( - "GET / HTTP/1.0\r\nContent-Length: 5\r\nConnection: Keep-Alive\r\n\r\n" + b"GET / HTTP/1.0\r\nContent-Length: 5\r\nConnection: Keep-Alive\r\n\r\n" ) to_send += body - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb") @@ -923,10 +921,9 @@ class TooLargeTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_request_body_too_large_with_no_cl_http10(self): - body = "a" * self.toobig - to_send = "GET / HTTP/1.0\r\n\r\n" + body = b"a" * self.toobig + to_send = b"GET / HTTP/1.0\r\n\r\n" to_send += body - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -939,10 +936,9 @@ class TooLargeTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_request_body_too_large_with_no_cl_http10_keepalive(self): - body = "a" * self.toobig - to_send = "GET / HTTP/1.0\r\nConnection: Keep-Alive\r\n\r\n" + body = b"a" * self.toobig + to_send = b"GET / HTTP/1.0\r\nConnection: Keep-Alive\r\n\r\n" to_send += body - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -962,10 +958,9 @@ class TooLargeTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_request_body_too_large_with_wrong_cl_http11(self): - body = "a" * self.toobig - to_send = "GET / HTTP/1.1\r\nContent-Length: 5\r\n\r\n" + body = b"a" * self.toobig + to_send = b"GET / HTTP/1.1\r\nContent-Length: 5\r\n\r\n" to_send += body - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb") @@ -984,10 +979,9 @@ class TooLargeTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_request_body_too_large_with_wrong_cl_http11_connclose(self): - body = "a" * self.toobig - to_send = "GET / HTTP/1.1\r\nContent-Length: 5\r\nConnection: close\r\n\r\n" + body = b"a" * self.toobig + to_send = b"GET / HTTP/1.1\r\nContent-Length: 5\r\nConnection: close\r\n\r\n" to_send += body - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -1001,10 +995,9 @@ class TooLargeTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_request_body_too_large_with_no_cl_http11(self): - body = "a" * self.toobig - to_send = "GET / HTTP/1.1\r\n\r\n" + body = b"a" * self.toobig + to_send = b"GET / HTTP/1.1\r\n\r\n" to_send += body - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb") @@ -1026,10 +1019,9 @@ class TooLargeTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_request_body_too_large_with_no_cl_http11_connclose(self): - body = "a" * self.toobig - to_send = "GET / HTTP/1.1\r\nConnection: close\r\n\r\n" + body = b"a" * self.toobig + to_send = b"GET / HTTP/1.1\r\nConnection: close\r\n\r\n" to_send += body - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -1043,12 +1035,11 @@ class TooLargeTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_request_body_too_large_chunked_encoding(self): - control_line = "20;\r\n" # 20 hex = 32 dec - s = "This string has 32 characters.\r\n" - to_send = "GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n" + control_line = b"20;\r\n" # 20 hex = 32 dec + s = b"This string has 32 characters.\r\n" + to_send = b"GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n" repeat = control_line + s to_send += repeat * ((self.toobig // len(repeat)) + 1) - to_send = tobytes(to_send) self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -1073,8 +1064,7 @@ class InternalServerErrorTests: self.stop_subprocess() def test_before_start_response_http_10(self): - to_send = "GET /before_start_response HTTP/1.0\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /before_start_response HTTP/1.0\r\n\r\n" self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -1089,8 +1079,7 @@ class InternalServerErrorTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_before_start_response_http_11(self): - to_send = "GET /before_start_response HTTP/1.1\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /before_start_response HTTP/1.1\r\n\r\n" self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -1108,9 +1097,7 @@ class InternalServerErrorTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_before_start_response_http_11_close(self): - to_send = tobytes( - "GET /before_start_response HTTP/1.1\r\nConnection: close\r\n\r\n" - ) + to_send = b"GET /before_start_response HTTP/1.1\r\nConnection: close\r\n\r\n" self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -1129,8 +1116,7 @@ class InternalServerErrorTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_after_start_response_http10(self): - to_send = "GET /after_start_response HTTP/1.0\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /after_start_response HTTP/1.0\r\n\r\n" self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -1149,8 +1135,7 @@ class InternalServerErrorTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_after_start_response_http11(self): - to_send = "GET /after_start_response HTTP/1.1\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /after_start_response HTTP/1.1\r\n\r\n" self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -1168,9 +1153,7 @@ class InternalServerErrorTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_after_start_response_http11_close(self): - to_send = tobytes( - "GET /after_start_response HTTP/1.1\r\nConnection: close\r\n\r\n" - ) + to_send = b"GET /after_start_response HTTP/1.1\r\nConnection: close\r\n\r\n" self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -1189,8 +1172,7 @@ class InternalServerErrorTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_after_write_cb(self): - to_send = "GET /after_write_cb HTTP/1.1\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /after_write_cb HTTP/1.1\r\n\r\n" self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -1202,8 +1184,7 @@ class InternalServerErrorTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_in_generator(self): - to_send = "GET /in_generator HTTP/1.1\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /in_generator HTTP/1.1\r\n\r\n" self.connect() self.sock.send(to_send) fp = self.sock.makefile("rb", 0) @@ -1225,8 +1206,7 @@ class FileWrapperTests: self.stop_subprocess() def test_filelike_http11(self): - to_send = "GET /filelike HTTP/1.1\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /filelike HTTP/1.1\r\n\r\n" self.connect() @@ -1243,8 +1223,7 @@ class FileWrapperTests: # connection has not been closed def test_filelike_nocl_http11(self): - to_send = "GET /filelike_nocl HTTP/1.1\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /filelike_nocl HTTP/1.1\r\n\r\n" self.connect() @@ -1261,8 +1240,7 @@ class FileWrapperTests: # connection has not been closed def test_filelike_shortcl_http11(self): - to_send = "GET /filelike_shortcl HTTP/1.1\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /filelike_shortcl HTTP/1.1\r\n\r\n" self.connect() @@ -1280,8 +1258,7 @@ class FileWrapperTests: # connection has not been closed def test_filelike_longcl_http11(self): - to_send = "GET /filelike_longcl HTTP/1.1\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /filelike_longcl HTTP/1.1\r\n\r\n" self.connect() @@ -1298,8 +1275,7 @@ class FileWrapperTests: # connection has not been closed def test_notfilelike_http11(self): - to_send = "GET /notfilelike HTTP/1.1\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /notfilelike HTTP/1.1\r\n\r\n" self.connect() @@ -1316,8 +1292,7 @@ class FileWrapperTests: # connection has not been closed def test_notfilelike_iobase_http11(self): - to_send = "GET /notfilelike_iobase HTTP/1.1\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /notfilelike_iobase HTTP/1.1\r\n\r\n" self.connect() @@ -1334,8 +1309,7 @@ class FileWrapperTests: # connection has not been closed def test_notfilelike_nocl_http11(self): - to_send = "GET /notfilelike_nocl HTTP/1.1\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /notfilelike_nocl HTTP/1.1\r\n\r\n" self.connect() @@ -1351,8 +1325,7 @@ class FileWrapperTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_notfilelike_shortcl_http11(self): - to_send = "GET /notfilelike_shortcl HTTP/1.1\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /notfilelike_shortcl HTTP/1.1\r\n\r\n" self.connect() @@ -1370,8 +1343,7 @@ class FileWrapperTests: # connection has not been closed def test_notfilelike_longcl_http11(self): - to_send = "GET /notfilelike_longcl HTTP/1.1\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /notfilelike_longcl HTTP/1.1\r\n\r\n" self.connect() @@ -1389,8 +1361,7 @@ class FileWrapperTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_filelike_http10(self): - to_send = "GET /filelike HTTP/1.0\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /filelike HTTP/1.0\r\n\r\n" self.connect() @@ -1408,8 +1379,7 @@ class FileWrapperTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_filelike_nocl_http10(self): - to_send = "GET /filelike_nocl HTTP/1.0\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /filelike_nocl HTTP/1.0\r\n\r\n" self.connect() @@ -1427,8 +1397,7 @@ class FileWrapperTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_notfilelike_http10(self): - to_send = "GET /notfilelike HTTP/1.0\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /notfilelike HTTP/1.0\r\n\r\n" self.connect() @@ -1446,8 +1415,7 @@ class FileWrapperTests: self.assertRaises(ConnectionClosed, read_http, fp) def test_notfilelike_nocl_http10(self): - to_send = "GET /notfilelike_nocl HTTP/1.0\r\n\r\n" - to_send = tobytes(to_send) + to_send = b"GET /notfilelike_nocl HTTP/1.0\r\n\r\n" self.connect() @@ -1571,13 +1539,16 @@ def parse_headers(fp): """Parses only RFC2822 headers from a file pointer. """ headers = {} + while True: line = fp.readline() + if line in (b"\r\n", b"\n", b""): break line = line.decode("iso-8859-1") name, value = line.strip().split(":", 1) headers[name.lower().strip()] = value.lower().strip() + return headers @@ -1606,22 +1577,28 @@ def read_http(fp): # pragma: no cover except OSError as exc: fp.close() # errno 104 is ENOTRECOVERABLE, In WinSock 10054 is ECONNRESET + if get_errno(exc) in (errno.ECONNABORTED, errno.ECONNRESET, 104, 10054): raise ConnectionClosed raise + if not response_line: raise ConnectionClosed header_lines = [] + while True: line = fp.readline() + if line in (b"\r\n", b"\r\n", b""): break else: header_lines.append(line) headers = dict() + for x in header_lines: x = x.strip() + if not x: continue key, value = x.split(b": ", 1) @@ -1634,8 +1611,10 @@ def read_http(fp): # pragma: no cover num = int(headers["content-length"]) body = b"" left = num + while left > 0: data = fp.read(left) + if not data: break body += data @@ -1671,5 +1650,6 @@ def get_errno(exc): # pragma: no cover def chunks(l, n): """ Yield successive n-sized chunks from l. """ + for i in range(0, len(l), n): yield l[i : i + n] |