summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBert JW Regeer <bertjw@regeer.org>2020-08-15 22:29:01 -0700
committerBert JW Regeer <bertjw@regeer.org>2020-08-16 16:49:06 -0700
commitd347823b8eb5bdc9ccecc440168032658bd752fa (patch)
tree4a7bd6794c82a2e5b59c024e16020432fefca2d4
parent1b4bcce97cceaae588b5508d42308f13be926ce2 (diff)
downloadwaitress-d347823b8eb5bdc9ccecc440168032658bd752fa.tar.gz
Reduce compat.py to minimum size
-rw-r--r--src/waitress/adjustments.py4
-rw-r--r--src/waitress/compat.py36
-rw-r--r--src/waitress/parser.py52
-rw-r--r--src/waitress/rfc7230.py6
-rw-r--r--src/waitress/task.py7
-rw-r--r--tests/test_compat.py14
-rw-r--r--tests/test_functional.py448
-rw-r--r--tests/test_parser.py104
-rw-r--r--tests/test_proxy_headers.py4
-rw-r--r--tests/test_runner.py4
-rw-r--r--tests/test_wasyncore.py48
11 files changed, 337 insertions, 390 deletions
diff --git a/src/waitress/adjustments.py b/src/waitress/adjustments.py
index f121b6e..145ac86 100644
--- a/src/waitress/adjustments.py
+++ b/src/waitress/adjustments.py
@@ -17,7 +17,7 @@ import getopt
import socket
import warnings
-from .compat import HAS_IPV6, WIN, string_types
+from .compat import HAS_IPV6, WIN
from .proxy_headers import PROXY_HEADERS
truthy = frozenset(("t", "true", "y", "yes", "on", "1"))
@@ -47,7 +47,7 @@ def asoctal(s):
def aslist_cronly(value):
- if isinstance(value, string_types):
+ if isinstance(value, str):
value = filter(None, [x.strip() for x in value.splitlines()])
return list(value)
diff --git a/src/waitress/compat.py b/src/waitress/compat.py
index 7c2630c..67543b9 100644
--- a/src/waitress/compat.py
+++ b/src/waitress/compat.py
@@ -1,50 +1,14 @@
-import _thread as thread
-from http import client as httplib
-from io import StringIO as NativeIO
-import os
import platform
# Fix for issue reported in https://github.com/Pylons/waitress/issues/138,
# Python on Windows may not define IPPROTO_IPV6 in socket.
import socket
import sys
-from urllib import parse as urlparse
-from urllib.parse import unquote_to_bytes
import warnings
# True if we are running on Windows
WIN = platform.system() == "Windows"
-string_types = (str,)
-integer_types = (int,)
-class_types = (type,)
-text_type = str
-binary_type = bytes
-long = int
-
-
-def unquote_bytes_to_wsgi(bytestring):
- return unquote_to_bytes(bytestring).decode("latin-1")
-
-
-def text_(s, encoding="latin-1", errors="strict"):
- """ If ``s`` is an instance of ``binary_type``, return
- ``s.decode(encoding, errors)``, otherwise return ``s``"""
-
- if isinstance(s, binary_type):
- return s.decode(encoding, errors)
-
- return s # pragma: no cover
-
-
-def tostr(s):
- return str(s, "latin-1", "strict")
-
-
-def tobytes(s):
- return bytes(s, "latin-1")
-
-
MAXINT = sys.maxsize
HAS_IPV6 = socket.has_ipv6
diff --git a/src/waitress/parser.py b/src/waitress/parser.py
index 4530b23..3b99921 100644
--- a/src/waitress/parser.py
+++ b/src/waitress/parser.py
@@ -18,9 +18,10 @@ processing but threads to do work.
"""
from io import BytesIO
import re
+from urllib import parse
+from urllib.parse import unquote_to_bytes
from waitress.buffers import OverflowableBuffer
-from waitress.compat import tostr, unquote_bytes_to_wsgi, urlparse
from waitress.receiver import ChunkedReceiver, FixedStreamReceiver
from waitress.utilities import (
BadRequest,
@@ -33,6 +34,10 @@ from waitress.utilities import (
from .rfc7230 import HEADER_FIELD
+def unquote_bytes_to_wsgi(bytestring):
+ return unquote_to_bytes(bytestring).decode("latin-1")
+
+
class ParsingError(Exception):
pass
@@ -80,11 +85,13 @@ class HTTPRequestParser:
bytes consumed. Sets the completed flag once both the header and the
body have been received.
"""
+
if self.completed:
return 0 # Can't consume any more.
datalen = len(data)
br = self.body_rcv
+
if br is None:
# In header.
max_header = self.adj.max_request_header_size
@@ -106,12 +113,14 @@ class HTTPRequestParser:
# If the first line + headers is over the max length, we return a
# RequestHeaderFieldsTooLarge error rather than continuing to
# attempt to parse the headers.
+
if self.header_bytes_received >= max_header:
self.parse_header(b"GET / HTTP/1.0\r\n")
self.error = RequestHeaderFieldsTooLarge(
"exceeds max_header of %s" % max_header
)
self.completed = True
+
return consumed
if index >= 0:
@@ -195,6 +204,7 @@ class HTTPRequestParser:
first line of the request).
"""
index = header_plus.find(b"\r\n")
+
if index >= 0:
first_line = header_plus[:index].rstrip()
header = header_plus[index + 2 :]
@@ -209,6 +219,7 @@ class HTTPRequestParser:
lines = get_header_lines(header)
headers = self.headers
+
for line in lines:
header = HEADER_FIELD.match(line)
@@ -219,25 +230,26 @@ class HTTPRequestParser:
if b"_" in key:
# TODO(xistence): Should we drop this request instead?
+
continue
# Only strip off whitespace that is considered valid whitespace by
# RFC7230, don't strip the rest
value = value.strip(b" \t")
- key1 = tostr(key.upper().replace(b"-", b"_"))
+ key1 = key.upper().replace(b"-", b"_").decode("latin-1")
# If a header already exists, we append subsequent values
# separated by a comma. Applications already need to handle
# the comma separated values, as HTTP front ends might do
# the concatenation for you (behavior specified in RFC2616).
try:
- headers[key1] += tostr(b", " + value)
+ headers[key1] += (b", " + value).decode("latin-1")
except KeyError:
- headers[key1] = tostr(value)
+ headers[key1] = value.decode("latin-1")
# command, uri, version will be bytes
command, uri, version = crack_first_line(first_line)
- version = tostr(version)
- command = tostr(command)
+ version = version.decode("latin-1")
+ command = command.decode("latin-1")
self.command = command
self.version = version
(
@@ -280,6 +292,7 @@ class HTTPRequestParser:
# Note: the identity transfer-coding was removed in RFC7230:
# https://tools.ietf.org/html/rfc7230#appendix-A.2 and is thus
# not supported
+
if encoding not in {"chunked"}:
raise TransferEncodingNotImplemented(
"Transfer-Encoding requested is not supported."
@@ -296,6 +309,7 @@ class HTTPRequestParser:
expect = headers.get("EXPECT", "").lower()
self.expect_continue = expect == "100-continue"
+
if connection.lower() == "close":
self.connection_close = True
@@ -306,12 +320,14 @@ class HTTPRequestParser:
raise ParsingError("Content-Length is invalid")
self.content_length = cl
+
if cl > 0:
buf = OverflowableBuffer(self.adj.inbuf_overflow)
self.body_rcv = FixedStreamReceiver(cl, buf)
def get_body_stream(self):
body_rcv = self.body_rcv
+
if body_rcv is not None:
return body_rcv.getfile()
else:
@@ -319,6 +335,7 @@ class HTTPRequestParser:
def close(self):
body_rcv = self.body_rcv
+
if body_rcv is not None:
body_rcv.getbuf().close()
@@ -346,16 +363,16 @@ def split_uri(uri):
path, query = path.split(b"?", 1)
else:
try:
- scheme, netloc, path, query, fragment = urlparse.urlsplit(uri)
+ scheme, netloc, path, query, fragment = parse.urlsplit(uri)
except UnicodeError:
raise ParsingError("Bad URI")
return (
- tostr(scheme),
- tostr(netloc),
+ scheme.decode("latin-1"),
+ netloc.decode("latin-1"),
unquote_bytes_to_wsgi(path),
- tostr(query),
- tostr(fragment),
+ query.decode("latin-1"),
+ fragment.decode("latin-1"),
)
@@ -365,20 +382,24 @@ def get_header_lines(header):
"""
r = []
lines = header.split(b"\r\n")
+
for line in lines:
if not line:
continue
if b"\r" in line or b"\n" in line:
- raise ParsingError('Bare CR or LF found in header line "%s"' % tostr(line))
+ raise ParsingError(
+ 'Bare CR or LF found in header line "%s"' % str(line, "latin-1")
+ )
if line.startswith((b" ", b"\t")):
if not r:
# https://corte.si/posts/code/pathod/pythonservers/index.html
- raise ParsingError('Malformed header line "%s"' % tostr(line))
+ raise ParsingError('Malformed header line "%s"' % str(line, "latin-1"))
r[-1] += line
else:
r.append(line)
+
return r
@@ -391,6 +412,7 @@ first_line_re = re.compile(
def crack_first_line(line):
m = first_line_re.match(line)
+
if m is not None and m.end() == len(line):
if m.group(3):
version = m.group(5)
@@ -407,9 +429,11 @@ def crack_first_line(line):
# unsuspecting souls from sending lowercase HTTP methods to waitress
# and having the request complete, while servers like nginx drop the
# request onto the floor.
+
if method != method.upper():
- raise ParsingError('Malformed HTTP method "%s"' % tostr(method))
+ raise ParsingError('Malformed HTTP method "%s"' % str(method, "latin-1"))
uri = m.group(2)
+
return method, uri, version
else:
return b"", b"", b""
diff --git a/src/waitress/rfc7230.py b/src/waitress/rfc7230.py
index cd33c90..9b25fbd 100644
--- a/src/waitress/rfc7230.py
+++ b/src/waitress/rfc7230.py
@@ -5,8 +5,6 @@ needed to properly parse HTTP messages.
import re
-from .compat import tobytes
-
WS = "[ \t]"
OWS = WS + "{0,}?"
RWS = WS + "{1,}?"
@@ -46,7 +44,7 @@ FIELD_CONTENT = FIELD_VCHAR + "+(?:[ \t]+" + FIELD_VCHAR + "+)*"
FIELD_VALUE = "(?:" + FIELD_CONTENT + ")?"
HEADER_FIELD = re.compile(
- tobytes(
+ (
"^(?P<name>" + TOKEN + "):" + OWS + "(?P<value>" + FIELD_VALUE + ")" + OWS + "$"
- )
+ ).encode("latin-1")
)
diff --git a/src/waitress/task.py b/src/waitress/task.py
index b82109f..779f01e 100644
--- a/src/waitress/task.py
+++ b/src/waitress/task.py
@@ -19,7 +19,6 @@ import threading
import time
from .buffers import ReadOnlyFileBasedBuffer
-from .compat import tobytes
from .utilities import build_http_date, logger, queue_logger
rename_headers = { # or keep them without the HTTP_ prefix added
@@ -281,7 +280,7 @@ class Task:
lines = [first_line] + next_lines
res = "%s\r\n\r\n" % "\r\n".join(lines)
- return tobytes(res)
+ return res.encode("latin-1")
def remove_content_length_header(self):
response_headers = []
@@ -317,7 +316,7 @@ class Task:
cl = self.content_length
if self.chunked_response:
# use chunked encoding response
- towrite = tobytes(hex(len(data))[2:].upper()) + b"\r\n"
+ towrite = hex(len(data))[2:].upper().encode("latin-1") + b"\r\n"
towrite += data + b"\r\n"
elif cl is not None:
towrite = data[: cl - self.content_bytes_written]
@@ -361,7 +360,7 @@ class ErrorTask(Task):
self.response_headers.append(("Connection", "close"))
self.close_on_finish = True
self.content_length = len(body)
- self.write(tobytes(body))
+ self.write(body.encode("latin-1"))
class WSGITask(Task):
diff --git a/tests/test_compat.py b/tests/test_compat.py
deleted file mode 100644
index e371348..0000000
--- a/tests/test_compat.py
+++ /dev/null
@@ -1,14 +0,0 @@
-import unittest
-
-
-class Test_unquote_bytes_to_wsgi(unittest.TestCase):
- def _callFUT(self, v):
- from waitress.compat import unquote_bytes_to_wsgi
-
- return unquote_bytes_to_wsgi(v)
-
- def test_highorder(self):
- val = b"/a%C5%9B"
- result = self._callFUT(val)
- # PEP 3333 urlunquoted-latin1-decoded-bytes
- self.assertEqual(result, "/aÅ\x9b")
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]
diff --git a/tests/test_parser.py b/tests/test_parser.py
index e0e4d25..eace4af 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -15,13 +15,26 @@
"""
import unittest
-from waitress.compat import text_, tobytes
+from waitress.adjustments import Adjustments
+from waitress.parser import (
+ HTTPRequestParser,
+ ParsingError,
+ TransferEncodingNotImplemented,
+ crack_first_line,
+ get_header_lines,
+ split_uri,
+ unquote_bytes_to_wsgi,
+)
+from waitress.utilities import (
+ BadRequest,
+ RequestEntityTooLarge,
+ RequestHeaderFieldsTooLarge,
+ ServerNotImplemented,
+)
class TestHTTPRequestParser(unittest.TestCase):
def setUp(self):
- from waitress.adjustments import Adjustments
- from waitress.parser import HTTPRequestParser
my_adj = Adjustments()
self.parser = HTTPRequestParser(my_adj)
@@ -45,8 +58,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertEqual(self.parser.headers, {})
def test_received_bad_host_header(self):
- from waitress.utilities import BadRequest
-
data = b"HTTP/1.0 GET /foobar\r\n Host: foo\r\n\r\n"
result = self.parser.received(data)
self.assertEqual(result, 36)
@@ -54,8 +65,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertEqual(self.parser.error.__class__, BadRequest)
def test_received_bad_transfer_encoding(self):
- from waitress.utilities import ServerNotImplemented
-
data = (
b"GET /foobar HTTP/1.1\r\n"
b"Transfer-Encoding: foo\r\n"
@@ -89,7 +98,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertEqual(result, 0)
def test_received_cl_too_large(self):
- from waitress.utilities import RequestEntityTooLarge
self.parser.adj.max_request_body_size = 2
data = b"GET /foobar HTTP/8.4\r\nContent-Length: 10\r\n\r\n"
@@ -99,7 +107,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(isinstance(self.parser.error, RequestEntityTooLarge))
def test_received_headers_too_large(self):
- from waitress.utilities import RequestHeaderFieldsTooLarge
self.parser.adj.max_request_header_size = 2
data = b"GET /foobar HTTP/8.4\r\nX-Foo: 1\r\n\r\n"
@@ -109,8 +116,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(isinstance(self.parser.error, RequestHeaderFieldsTooLarge))
def test_received_body_too_large(self):
- from waitress.utilities import RequestEntityTooLarge
-
self.parser.adj.max_request_body_size = 2
data = (
b"GET /foobar HTTP/1.1\r\n"
@@ -129,8 +134,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(isinstance(self.parser.error, RequestEntityTooLarge))
def test_received_error_from_parser(self):
- from waitress.utilities import BadRequest
-
data = (
b"GET /foobar HTTP/1.1\r\n"
b"Transfer-Encoding: chunked\r\n"
@@ -171,8 +174,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertEqual(self.parser.headers["FOO"], "bar")
def test_parse_header_no_cr_in_headerplus(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/8.4"
try:
@@ -183,8 +184,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(False)
def test_parse_header_bad_content_length(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/8.4\r\ncontent-length: abc\r\n"
try:
@@ -195,8 +194,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(False)
def test_parse_header_multiple_content_length(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/8.4\r\ncontent-length: 10\r\ncontent-length: 20\r\n"
try:
@@ -213,8 +210,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertEqual(self.parser.body_rcv.__class__.__name__, "ChunkedReceiver")
def test_parse_header_transfer_encoding_invalid(self):
- from waitress.parser import TransferEncodingNotImplemented
-
data = b"GET /foobar HTTP/1.1\r\ntransfer-encoding: gzip\r\n"
try:
@@ -225,7 +220,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(False)
def test_parse_header_transfer_encoding_invalid_multiple(self):
- from waitress.parser import TransferEncodingNotImplemented
data = b"GET /foobar HTTP/1.1\r\ntransfer-encoding: gzip\r\ntransfer-encoding: chunked\r\n"
@@ -237,8 +231,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(False)
def test_parse_header_transfer_encoding_invalid_whitespace(self):
- from waitress.parser import TransferEncodingNotImplemented
-
data = b"GET /foobar HTTP/1.1\r\nTransfer-Encoding:\x85chunked\r\n"
try:
@@ -249,8 +241,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(False)
def test_parse_header_transfer_encoding_invalid_unicode(self):
- from waitress.parser import TransferEncodingNotImplemented
-
# This is the binary encoding for the UTF-8 character
# https://www.compart.com/en/unicode/U+212A "unicode character "K""
# which if waitress were to accidentally do the wrong thing get
@@ -286,8 +276,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.parser.close() # doesn't raise
def test_parse_header_lf_only(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/8.4\nfoo: bar"
try:
@@ -298,8 +286,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(False)
def test_parse_header_cr_only(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/8.4\rfoo: bar"
try:
self.parser.parse_header(data)
@@ -309,8 +295,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(False)
def test_parse_header_extra_lf_in_header(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/8.4\r\nfoo: \nbar\r\n"
try:
self.parser.parse_header(data)
@@ -320,8 +304,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(False)
def test_parse_header_extra_lf_in_first_line(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar\n HTTP/8.4\r\n"
try:
self.parser.parse_header(data)
@@ -331,8 +313,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(False)
def test_parse_header_invalid_whitespace(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/8.4\r\nfoo : bar\r\n"
try:
self.parser.parse_header(data)
@@ -342,8 +322,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(False)
def test_parse_header_invalid_whitespace_vtab(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/1.1\r\nfoo:\x0bbar\r\n"
try:
self.parser.parse_header(data)
@@ -353,8 +331,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(False)
def test_parse_header_invalid_no_colon(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/1.1\r\nfoo: bar\r\nnotvalid\r\n"
try:
self.parser.parse_header(data)
@@ -364,8 +340,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(False)
def test_parse_header_invalid_folding_spacing(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/1.1\r\nfoo: bar\r\n\t\x0bbaz\r\n"
try:
self.parser.parse_header(data)
@@ -375,8 +349,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(False)
def test_parse_header_invalid_chars(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/1.1\r\nfoo: bar\r\nfoo: \x0bbaz\r\n"
try:
self.parser.parse_header(data)
@@ -386,8 +358,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(False)
def test_parse_header_empty(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/1.1\r\nfoo: bar\r\nempty:\r\n"
self.parser.parse_header(data)
@@ -397,8 +367,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertEqual(self.parser.headers["FOO"], "bar")
def test_parse_header_multiple_values(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/1.1\r\nfoo: bar, whatever, more, please, yes\r\n"
self.parser.parse_header(data)
@@ -406,8 +374,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertEqual(self.parser.headers["FOO"], "bar, whatever, more, please, yes")
def test_parse_header_multiple_values_header_folded(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/1.1\r\nfoo: bar, whatever,\r\n more, please, yes\r\n"
self.parser.parse_header(data)
@@ -415,8 +381,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertEqual(self.parser.headers["FOO"], "bar, whatever, more, please, yes")
def test_parse_header_multiple_values_header_folded_multiple(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/1.1\r\nfoo: bar, whatever,\r\n more\r\nfoo: please, yes\r\n"
self.parser.parse_header(data)
@@ -425,8 +389,6 @@ class TestHTTPRequestParser(unittest.TestCase):
def test_parse_header_multiple_values_extra_space(self):
# Tests errata from: https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4189
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/1.1\r\nfoo: abrowser/0.001 (C O M M E N T)\r\n"
self.parser.parse_header(data)
@@ -434,8 +396,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertEqual(self.parser.headers["FOO"], "abrowser/0.001 (C O M M E N T)")
def test_parse_header_invalid_backtrack_bad(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/1.1\r\nfoo: bar\r\nfoo: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\x10\r\n"
try:
self.parser.parse_header(data)
@@ -445,8 +405,6 @@ class TestHTTPRequestParser(unittest.TestCase):
self.assertTrue(False)
def test_parse_header_short_values(self):
- from waitress.parser import ParsingError
-
data = b"GET /foobar HTTP/1.1\r\none: 1\r\ntwo: 22\r\n"
self.parser.parse_header(data)
@@ -458,8 +416,6 @@ class TestHTTPRequestParser(unittest.TestCase):
class Test_split_uri(unittest.TestCase):
def _callFUT(self, uri):
- from waitress.parser import split_uri
-
(
self.proxy_scheme,
self.proxy_netloc,
@@ -499,7 +455,6 @@ class Test_split_uri(unittest.TestCase):
def test_split_uri_unicode_error_raises_parsing_error(self):
# See https://github.com/Pylons/waitress/issues/64
- from waitress.parser import ParsingError
# Either pass or throw a ParsingError, just don't throw another type of
# exception as that will cause the connection to close badly:
@@ -535,8 +490,6 @@ class Test_split_uri(unittest.TestCase):
class Test_get_header_lines(unittest.TestCase):
def _callFUT(self, data):
- from waitress.parser import get_header_lines
-
return get_header_lines(data)
def test_get_header_lines(self):
@@ -561,15 +514,11 @@ class Test_get_header_lines(unittest.TestCase):
def test_get_header_lines_malformed(self):
# https://corte.si/posts/code/pathod/pythonservers/index.html
- from waitress.parser import ParsingError
-
self.assertRaises(ParsingError, self._callFUT, b" Host: localhost\r\n\r\n")
class Test_crack_first_line(unittest.TestCase):
def _callFUT(self, line):
- from waitress.parser import crack_first_line
-
return crack_first_line(line)
def test_crack_first_line_matchok(self):
@@ -577,8 +526,6 @@ class Test_crack_first_line(unittest.TestCase):
self.assertEqual(result, (b"GET", b"/", b"1.0"))
def test_crack_first_line_lowercase_method(self):
- from waitress.parser import ParsingError
-
self.assertRaises(ParsingError, self._callFUT, b"get / HTTP/1.0")
def test_crack_first_line_nomatch(self):
@@ -595,9 +542,6 @@ class Test_crack_first_line(unittest.TestCase):
class TestHTTPRequestParserIntegration(unittest.TestCase):
def setUp(self):
- from waitress.adjustments import Adjustments
- from waitress.parser import HTTPRequestParser
-
my_adj = Adjustments()
self.parser = HTTPRequestParser(my_adj)
@@ -657,8 +601,8 @@ class TestHTTPRequestParserIntegration(unittest.TestCase):
)
# path should be utf-8 encoded
self.assertEqual(
- tobytes(parser.path).decode("utf-8"),
- text_(b"/foo/a++/\xc3\xa4=&a:int", "utf-8"),
+ parser.path.encode("latin-1").decode("utf-8"),
+ b"/foo/a++/\xc3\xa4=&a:int".decode("utf-8"),
)
self.assertEqual(
parser.query, "d=b+%2B%2F%3D%26b%3Aint&c+%2B%2F%3D%26c%3Aint=6"
@@ -721,6 +665,18 @@ class TestHTTPRequestParserIntegration(unittest.TestCase):
self.assertEqual(self.parser.headers, {"CONTENT_LENGTH": "6",})
+class Test_unquote_bytes_to_wsgi(unittest.TestCase):
+ def _callFUT(self, v):
+
+ return unquote_bytes_to_wsgi(v)
+
+ def test_highorder(self):
+ val = b"/a%C5%9B"
+ result = self._callFUT(val)
+ # PEP 3333 urlunquoted-latin1-decoded-bytes
+ self.assertEqual(result, "/aÅ\x9b")
+
+
class DummyBodyStream:
def getfile(self):
return self
diff --git a/tests/test_proxy_headers.py b/tests/test_proxy_headers.py
index 1aea477..e6f0ed6 100644
--- a/tests/test_proxy_headers.py
+++ b/tests/test_proxy_headers.py
@@ -1,7 +1,5 @@
import unittest
-from waitress.compat import tobytes
-
class TestProxyHeadersMiddleware(unittest.TestCase):
def _makeOne(self, app, **kw):
@@ -18,7 +16,7 @@ class TestProxyHeadersMiddleware(unittest.TestCase):
response.headers = response_headers
response.steps = list(app(environ, start_response))
- response.body = b"".join(tobytes(s) for s in response.steps)
+ response.body = b"".join(s.encode("latin-1") for s in response.steps)
return response
def test_get_environment_values_w_scheme_override_untrusted(self):
diff --git a/tests/test_runner.py b/tests/test_runner.py
index e77d103..2ac302c 100644
--- a/tests/test_runner.py
+++ b/tests/test_runner.py
@@ -181,9 +181,9 @@ class Test_helper(unittest.TestCase):
@contextlib.contextmanager
def capture():
- from waitress.compat import NativeIO
+ from io import StringIO
- fd = NativeIO()
+ fd = StringIO()
sys.stdout = fd
sys.stderr = fd
yield fd
diff --git a/tests/test_wasyncore.py b/tests/test_wasyncore.py
index a7e2878..970e993 100644
--- a/tests/test_wasyncore.py
+++ b/tests/test_wasyncore.py
@@ -1,3 +1,4 @@
+import _thread as thread
import contextlib
import errno
import functools
@@ -23,6 +24,7 @@ HOSTv4 = "127.0.0.1"
HOSTv6 = "::1"
# Filename used for testing
+
if os.name == "java": # pragma: no cover
# Jython disallows @ in module names
TESTFN = "$test"
@@ -66,6 +68,7 @@ def _filterwarnings(filters, quiet=False): # pragma: no cover
# in order to re-raise the warnings.
frame = sys._getframe(2)
registry = frame.f_globals.get("__warningregistry__")
+
if registry:
registry.clear()
with warnings.catch_warnings(record=True) as w:
@@ -77,19 +80,25 @@ def _filterwarnings(filters, quiet=False): # pragma: no cover
# Filter the recorded warnings
reraise = list(w)
missing = []
+
for msg, cat in filters:
seen = False
+
for w in reraise[:]:
warning = w.message
# Filter out the matching messages
+
if re.match(msg, str(warning), re.I) and issubclass(warning.__class__, cat):
seen = True
reraise.remove(w)
+
if not seen and not quiet:
# This filter caught nothing
missing.append((msg, cat.__name__))
+
if reraise:
raise AssertionError("unhandled warning %s" % reraise[0])
+
if missing:
raise AssertionError("filter (%r, %s) did not catch any warning" % missing[0])
@@ -110,11 +119,14 @@ def check_warnings(*filters, **kwargs): # pragma: no cover
check_warnings(("", Warning), quiet=True)
"""
quiet = kwargs.get("quiet")
+
if not filters:
filters = (("", Warning),)
# Preserve backward compatibility
+
if quiet is None:
quiet = True
+
return _filterwarnings(filters, quiet)
@@ -129,6 +141,7 @@ def gc_collect(): # pragma: no cover
objects to disappear.
"""
gc.collect()
+
if sys.platform.startswith("java"):
time.sleep(0.1)
gc.collect()
@@ -136,7 +149,7 @@ def gc_collect(): # pragma: no cover
def threading_setup(): # pragma: no cover
- return (compat.thread._count(), None)
+ return (thread._count(), None)
def threading_cleanup(*original_values): # pragma: no cover
@@ -145,7 +158,8 @@ def threading_cleanup(*original_values): # pragma: no cover
_MAX_COUNT = 100
for count in range(_MAX_COUNT):
- values = (compat.thread._count(), None)
+ values = (thread._count(), None)
+
if values == original_values:
break
@@ -185,6 +199,7 @@ def join_thread(thread, timeout=30.0): # pragma: no cover
after timeout seconds.
"""
thread.join(timeout)
+
if thread.is_alive():
msg = "failed to join the thread in %.1f seconds" % timeout
raise AssertionError(msg)
@@ -212,6 +227,7 @@ def bind_port(sock, host=HOST): # pragma: no cover
"tests should never set the SO_REUSEADDR "
"socket option on TCP/IP sockets!"
)
+
if hasattr(socket, "SO_REUSEPORT"):
try:
if sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT) == 1:
@@ -224,11 +240,13 @@ def bind_port(sock, host=HOST): # pragma: no cover
# thus defining SO_REUSEPORT but this process is running
# under an older kernel that does not support SO_REUSEPORT.
pass
+
if hasattr(socket, "SO_EXCLUSIVEADDRUSE"):
sock.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1)
sock.bind((host, 0))
port = sock.getsockname()[1]
+
return port
@@ -302,13 +320,16 @@ def capture_server(evt, buf, serv): # pragma no cover
else:
n = 200
start = time.time()
+
while n > 0 and time.time() - start < 3.0:
r, w, e = select.select([conn], [], [], 0.1)
+
if r:
n -= 1
data = conn.recv(10)
# keep everything except for the newline terminator
buf.write(data.replace(b"\n", b""))
+
if b"\n" in data:
break
time.sleep(0.01)
@@ -331,6 +352,7 @@ def bind_unix_socket(sock, addr): # pragma: no cover
def bind_af_aware(sock, addr):
"""Helper function to bind a socket according to its family."""
+
if HAS_UNIX_SOCKETS and sock.family == socket.AF_UNIX:
# Make sure the path doesn't exist.
unlink(addr)
@@ -345,6 +367,7 @@ if sys.platform.startswith("win"): # pragma: no cover
# Perform the operation
func(pathname)
# Now setup the wait loop
+
if waitall:
dirname = pathname
else:
@@ -357,6 +380,7 @@ if sys.platform.startswith("win"): # pragma: no cover
# Testing on an i7@4.3GHz shows that usually only 1 iteration is
# required when contention occurs.
timeout = 0.001
+
while timeout < 1.0:
# Note we are only testing for the existence of the file(s) in
# the contents of the directory regardless of any security or
@@ -366,6 +390,7 @@ if sys.platform.startswith("win"): # pragma: no cover
# Other Windows APIs can fail or give incorrect results when
# dealing with files that are pending deletion.
L = os.listdir(dirname)
+
if not (L if waitall else name in L):
return
# Increase the timeout and try again
@@ -394,17 +419,20 @@ def unlink(filename):
def _is_ipv6_enabled(): # pragma: no cover
"""Check whether IPv6 is enabled on this host."""
+
if compat.HAS_IPV6:
sock = None
try:
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.bind(("::1", 0))
+
return True
except OSError:
pass
finally:
if sock:
sock.close()
+
return False
@@ -486,6 +514,7 @@ class HelperFunctionTests(unittest.TestCase):
# Only the attribute modified by the routine we expect to be
# called should be True.
+
for attr in attributes:
self.assertEqual(getattr(tobj, attr), attr == expectedattr)
@@ -512,6 +541,7 @@ class HelperFunctionTests(unittest.TestCase):
l = []
testmap = {}
+
for i in range(10):
c = dummychannel()
l.append(c)
@@ -605,6 +635,7 @@ class DispatcherTests(unittest.TestCase):
def test_strerror(self):
# refers to bug #8573
err = asyncore._strerror(errno.EPERM)
+
if hasattr(os, "strerror"):
self.assertEqual(err, os.strerror(errno.EPERM))
err = asyncore._strerror(-1)
@@ -655,6 +686,7 @@ class DispatcherWithSendTests(unittest.TestCase):
d.send(b"\n")
n = 1000
+
while d.out_buffer and n > 0: # pragma: no cover
asyncore.poll()
n -= 1
@@ -722,6 +754,7 @@ class FileWrapperTest(unittest.TestCase):
def test_resource_warning(self):
# Issue #11453
got_warning = False
+
while got_warning is False:
# we try until we get the outcome we want because this
# test is not deterministic (gc_collect() may not
@@ -818,8 +851,10 @@ class BaseTestAPI:
def loop_waiting_for_flag(self, instance, timeout=5): # pragma: no cover
timeout = float(timeout) / 100
count = 100
+
while asyncore.socket_map and count > 0:
asyncore.loop(timeout=0.01, count=1, use_poll=self.use_poll)
+
if instance.flag:
return
count -= 1
@@ -965,6 +1000,7 @@ class BaseTestAPI:
# Make sure handle_expt is called on OOB data received.
# Note: this might fail on some platforms as OOB data is
# tenuously supported and rarely used.
+
if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
self.skipTest("Not applicable to AF_UNIX sockets.")
@@ -979,7 +1015,7 @@ class BaseTestAPI:
class TestHandler(BaseTestHandler):
def __init__(self, conn):
BaseTestHandler.__init__(self, conn)
- self.socket.send(compat.tobytes(chr(244)), socket.MSG_OOB)
+ self.socket.send(chr(244).encode("latin-1"), socket.MSG_OOB)
server = BaseServer(self.family, self.addr, TestHandler)
client = TestClient(self.family, server.address)
@@ -1081,6 +1117,7 @@ class BaseTestAPI:
@reap_threads
def test_quick_connect(self): # pragma: no cover
# see: http://bugs.python.org/issue10340
+
if self.family not in (socket.AF_INET, getattr(socket, "AF_INET6", object())):
self.skipTest("test specific to AF_INET and AF_INET6")
@@ -1692,16 +1729,19 @@ class DummyDispatcher:
def handle_read_event(self):
self.read_event_handled = True
+
if self.exc is not None:
raise self.exc
def handle_write_event(self):
self.write_event_handled = True
+
if self.exc is not None:
raise self.exc
def handle_expt_event(self):
self.expt_event_handled = True
+
if self.exc is not None:
raise self.exc
@@ -1740,6 +1780,7 @@ class DummySelect:
def select(self, *arg):
self.selected.append(arg)
+
if self.exc is not None:
raise self.exc
@@ -1754,6 +1795,7 @@ class DummyPollster:
def poll(self, timeout):
self.polled.append(timeout)
+
if self.exc is not None:
raise self.exc
else: # pragma: no cover