mirror of
https://github.com/servo/servo.git
synced 2025-08-12 08:55:32 +01:00
Update web-platform-tests to revision b8669365b81965f5400d6b13a7783415b44e679d
This commit is contained in:
parent
6fa1853bb1
commit
bde105ca2e
42 changed files with 933 additions and 241 deletions
|
@ -20,7 +20,6 @@ class TestFileHandler(TestUsingServer):
|
|||
self.assertEqual("text/plain", resp.info()["Content-Type"])
|
||||
self.assertEqual(open(os.path.join(doc_root, "document.txt"), 'rb').read(), resp.read())
|
||||
|
||||
@pytest.mark.xfail(sys.version_info >= (3,), reason="wptserve only works on Py2")
|
||||
def test_headers(self):
|
||||
resp = self.request("/with_headers.txt")
|
||||
self.assertEqual(200, resp.getcode())
|
||||
|
@ -29,7 +28,7 @@ class TestFileHandler(TestUsingServer):
|
|||
# This will fail if it isn't a valid uuid
|
||||
uuid.UUID(resp.info()["Another-Header"])
|
||||
self.assertEqual(resp.info()["Same-Value-Header"], resp.info()["Another-Header"])
|
||||
self.assertEqual(resp.info()["Double-Header"], "PA, SS")
|
||||
self.assert_multiple_headers(resp, "Double-Header", ["PA", "SS"])
|
||||
|
||||
|
||||
def test_range(self):
|
||||
|
@ -61,7 +60,6 @@ class TestFileHandler(TestUsingServer):
|
|||
resp.info()['Content-Range'])
|
||||
self.assertEqual(expected[-10:], data)
|
||||
|
||||
@pytest.mark.xfail(sys.version_info >= (3,), reason="wptserve only works on Py2")
|
||||
def test_multiple_ranges(self):
|
||||
resp = self.request("/document.txt", headers={"Range":"bytes=1-2,5-7,6-10"})
|
||||
self.assertEqual(206, resp.getcode())
|
||||
|
@ -69,16 +67,16 @@ class TestFileHandler(TestUsingServer):
|
|||
expected = open(os.path.join(doc_root, "document.txt"), 'rb').read()
|
||||
self.assertTrue(resp.info()["Content-Type"].startswith("multipart/byteranges; boundary="))
|
||||
boundary = resp.info()["Content-Type"].split("boundary=")[1]
|
||||
parts = data.split("--" + boundary)
|
||||
self.assertEqual("\r\n", parts[0])
|
||||
self.assertEqual("--", parts[-1])
|
||||
expected_parts = [("1-2", expected[1:3]), ("5-10", expected[5:11])]
|
||||
parts = data.split(b"--" + boundary.encode("ascii"))
|
||||
self.assertEqual(b"\r\n", parts[0])
|
||||
self.assertEqual(b"--", parts[-1])
|
||||
expected_parts = [(b"1-2", expected[1:3]), (b"5-10", expected[5:11])]
|
||||
for expected_part, part in zip(expected_parts, parts[1:-1]):
|
||||
header_string, body = part.split("\r\n\r\n")
|
||||
headers = dict(item.split(": ", 1) for item in header_string.split("\r\n") if item.strip())
|
||||
self.assertEqual(headers["Content-Type"], "text/plain")
|
||||
self.assertEqual(headers["Content-Range"], "bytes %s/%i" % (expected_part[0], len(expected)))
|
||||
self.assertEqual(expected_part[1] + "\r\n", body)
|
||||
header_string, body = part.split(b"\r\n\r\n")
|
||||
headers = dict(item.split(b": ", 1) for item in header_string.split(b"\r\n") if item.strip())
|
||||
self.assertEqual(headers[b"Content-Type"], b"text/plain")
|
||||
self.assertEqual(headers[b"Content-Range"], b"bytes %s/%i" % (expected_part[0], len(expected)))
|
||||
self.assertEqual(expected_part[1] + b"\r\n", body)
|
||||
|
||||
def test_range_invalid(self):
|
||||
with self.assertRaises(HTTPError) as cm:
|
||||
|
@ -236,12 +234,11 @@ class TestJSONHandler(TestUsingServer):
|
|||
|
||||
|
||||
class TestPythonHandler(TestUsingServer):
|
||||
@pytest.mark.xfail(sys.version_info >= (3,), reason="wptserve only works on Py2")
|
||||
def test_string(self):
|
||||
resp = self.request("/test_string.py")
|
||||
self.assertEqual(200, resp.getcode())
|
||||
self.assertEqual("text/plain", resp.info()["Content-Type"])
|
||||
self.assertEqual("PASS", resp.read())
|
||||
self.assertEqual(b"PASS", resp.read())
|
||||
|
||||
def test_tuple_2(self):
|
||||
resp = self.request("/test_tuple_2.py")
|
||||
|
|
|
@ -159,8 +159,8 @@ class FileHandler(object):
|
|||
rv = (self.load_headers(request, os.path.join(os.path.split(path)[0], "__dir__")) +
|
||||
self.load_headers(request, path))
|
||||
|
||||
if not any(key.lower() == "content-type" for (key, _) in rv):
|
||||
rv.insert(0, ("Content-Type", guess_content_type(path)))
|
||||
if not any(key.lower() == b"content-type" for (key, _) in rv):
|
||||
rv.insert(0, (b"Content-Type", guess_content_type(path).encode("ascii")))
|
||||
|
||||
return rv
|
||||
|
||||
|
@ -173,14 +173,14 @@ class FileHandler(object):
|
|||
use_sub = False
|
||||
|
||||
try:
|
||||
with open(headers_path) as headers_file:
|
||||
with open(headers_path, "rb") as headers_file:
|
||||
data = headers_file.read()
|
||||
except IOError:
|
||||
return []
|
||||
else:
|
||||
if use_sub:
|
||||
data = template(request, data, escape_type="none")
|
||||
return [tuple(item.strip() for item in line.split(":", 1))
|
||||
return [tuple(item.strip() for item in line.split(b":", 1))
|
||||
for line in data.splitlines() if line]
|
||||
|
||||
def get_data(self, response, path, byte_ranges):
|
||||
|
|
|
@ -8,7 +8,7 @@ from .constants import response_codes, h2_headers
|
|||
from .logger import get_logger
|
||||
from io import BytesIO
|
||||
|
||||
from six import binary_type, text_type, itervalues
|
||||
from six import binary_type, text_type, integer_types, itervalues, PY3
|
||||
from hyperframe.frame import HeadersFrame, DataFrame, ContinuationFrame
|
||||
from hpack.struct import HeaderTuple
|
||||
|
||||
|
@ -157,6 +157,8 @@ class Response(object):
|
|||
cookies = self.headers.get("Set-Cookie")
|
||||
parser = BaseCookie()
|
||||
for cookie in cookies:
|
||||
if PY3:
|
||||
cookie = cookie.decode("iso-8859-1")
|
||||
parser.load(cookie)
|
||||
|
||||
if name in parser.keys():
|
||||
|
@ -237,18 +239,18 @@ class MultipartContent(object):
|
|||
def __init__(self, boundary=None, default_content_type=None):
|
||||
self.items = []
|
||||
if boundary is None:
|
||||
boundary = str(uuid.uuid4())
|
||||
boundary = text_type(uuid.uuid4())
|
||||
self.boundary = boundary
|
||||
self.default_content_type = default_content_type
|
||||
|
||||
def __call__(self):
|
||||
boundary = "--" + self.boundary
|
||||
rv = ["", boundary]
|
||||
boundary = b"--" + self.boundary.encode("ascii")
|
||||
rv = [b"", boundary]
|
||||
for item in self.items:
|
||||
rv.append(str(item))
|
||||
rv.append(item.to_bytes())
|
||||
rv.append(boundary)
|
||||
rv[-1] += "--"
|
||||
return "\r\n".join(rv)
|
||||
rv[-1] += b"--"
|
||||
return b"\r\n".join(rv)
|
||||
|
||||
def append_part(self, data, content_type=None, headers=None):
|
||||
if content_type is None:
|
||||
|
@ -265,6 +267,7 @@ class MultipartContent(object):
|
|||
|
||||
class MultipartPart(object):
|
||||
def __init__(self, data, content_type=None, headers=None):
|
||||
assert isinstance(data, binary_type), data
|
||||
self.headers = ResponseHeaders()
|
||||
|
||||
if content_type is not None:
|
||||
|
@ -272,7 +275,7 @@ class MultipartPart(object):
|
|||
|
||||
if headers is not None:
|
||||
for name, value in headers:
|
||||
if name.lower() == "content-type":
|
||||
if name.lower() == b"content-type":
|
||||
func = self.headers.set
|
||||
else:
|
||||
func = self.headers.append
|
||||
|
@ -280,13 +283,36 @@ class MultipartPart(object):
|
|||
|
||||
self.data = data
|
||||
|
||||
def __str__(self):
|
||||
def to_bytes(self):
|
||||
rv = []
|
||||
for item in self.headers:
|
||||
rv.append("%s: %s" % item)
|
||||
rv.append("")
|
||||
for key, value in self.headers:
|
||||
assert isinstance(key, binary_type)
|
||||
assert isinstance(value, binary_type)
|
||||
rv.append(b"%s: %s" % (key, value))
|
||||
rv.append(b"")
|
||||
rv.append(self.data)
|
||||
return "\r\n".join(rv)
|
||||
return b"\r\n".join(rv)
|
||||
|
||||
|
||||
def _maybe_encode(s):
|
||||
"""Encodes a text-type string into binary data using iso-8859-1.
|
||||
|
||||
Returns `str` in Python 2 and `bytes` in Python 3. The function is a no-op
|
||||
if the argument already has a binary type.
|
||||
"""
|
||||
if isinstance(s, binary_type):
|
||||
return s
|
||||
|
||||
# Python 3 assumes iso-8859-1 when parsing headers, which will garble text
|
||||
# with non ASCII characters. We try to encode the text back to binary.
|
||||
# https://github.com/python/cpython/blob/273fc220b25933e443c82af6888eb1871d032fb8/Lib/http/client.py#L213
|
||||
if isinstance(s, text_type):
|
||||
return s.encode("iso-8859-1")
|
||||
|
||||
if isinstance(s, integer_types):
|
||||
return b"%i" % (s,)
|
||||
|
||||
raise TypeError("Unexpected value in ResponseHeaders: %r" % s)
|
||||
|
||||
|
||||
class ResponseHeaders(object):
|
||||
|
@ -301,6 +327,8 @@ class ResponseHeaders(object):
|
|||
:param key: Name of the header to set
|
||||
:param value: Value to set the header to
|
||||
"""
|
||||
key = _maybe_encode(key)
|
||||
value = _maybe_encode(value)
|
||||
self.data[key.lower()] = (key, [value])
|
||||
|
||||
def append(self, key, value):
|
||||
|
@ -310,6 +338,8 @@ class ResponseHeaders(object):
|
|||
:param key: Name of the header to add
|
||||
:param value: Value to set for the header
|
||||
"""
|
||||
key = _maybe_encode(key)
|
||||
value = _maybe_encode(value)
|
||||
if key.lower() in self.data:
|
||||
self.data[key.lower()][1].append(value)
|
||||
else:
|
||||
|
@ -317,6 +347,7 @@ class ResponseHeaders(object):
|
|||
|
||||
def get(self, key, default=missing):
|
||||
"""Get the set values for a particular header."""
|
||||
key = _maybe_encode(key)
|
||||
try:
|
||||
return self[key]
|
||||
except KeyError:
|
||||
|
@ -328,12 +359,15 @@ class ResponseHeaders(object):
|
|||
"""Get a list of values for a particular header
|
||||
|
||||
"""
|
||||
key = _maybe_encode(key)
|
||||
return self.data[key.lower()][1]
|
||||
|
||||
def __delitem__(self, key):
|
||||
key = _maybe_encode(key)
|
||||
del self.data[key.lower()]
|
||||
|
||||
def __contains__(self, key):
|
||||
key = _maybe_encode(key)
|
||||
return key.lower() in self.data
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
|
@ -623,6 +657,9 @@ class ResponseWriter(object):
|
|||
self.file_chunk_size = 32 * 1024
|
||||
self.default_status = 200
|
||||
|
||||
def _seen_header(self, name):
|
||||
return self.encode(name.lower()) in self._headers_seen
|
||||
|
||||
def write_status(self, code, message=None):
|
||||
"""Write out the status line of a response.
|
||||
|
||||
|
@ -648,19 +685,25 @@ class ResponseWriter(object):
|
|||
"""
|
||||
if not self._status_written:
|
||||
self.write_status(self.default_status)
|
||||
self._headers_seen.add(name.lower())
|
||||
self.write("%s: %s\r\n" % (name, value))
|
||||
self._headers_seen.add(self.encode(name.lower()))
|
||||
self.write(name)
|
||||
self.write(b": ")
|
||||
if isinstance(value, int):
|
||||
self.write(text_type(value))
|
||||
else:
|
||||
self.write(value)
|
||||
self.write(b"\r\n")
|
||||
if not self._response.explicit_flush:
|
||||
self.flush()
|
||||
|
||||
def write_default_headers(self):
|
||||
for name, f in [("Server", self._handler.version_string),
|
||||
("Date", self._handler.date_time_string)]:
|
||||
if name.lower() not in self._headers_seen:
|
||||
if not self._seen_header(name):
|
||||
self.write_header(name, f())
|
||||
|
||||
if (isinstance(self._response.content, (binary_type, text_type)) and
|
||||
"content-length" not in self._headers_seen):
|
||||
not self._seen_header("content-length")):
|
||||
#Would be nice to avoid double-encoding here
|
||||
self.write_header("Content-Length", len(self.encode(self._response.content)))
|
||||
|
||||
|
@ -675,7 +718,7 @@ class ResponseWriter(object):
|
|||
self.write_default_headers()
|
||||
|
||||
self.write("\r\n")
|
||||
if "content-length" not in self._headers_seen:
|
||||
if not self._seen_header("content-length"):
|
||||
self._response.close_connection = True
|
||||
if not self._response.explicit_flush:
|
||||
self.flush()
|
||||
|
@ -735,7 +778,7 @@ class ResponseWriter(object):
|
|||
elif isinstance(data, text_type):
|
||||
return data.encode(self._response.encoding)
|
||||
else:
|
||||
raise ValueError
|
||||
raise ValueError("data %r should be text or binary, but is %s" % (data, type(data)))
|
||||
|
||||
def flush(self):
|
||||
"""Flush the output. Returns False if the flush failed due to
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue