Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion Lib/test/test_wsgiref.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,52 @@ def bad_app(e,s):
b"A server error occurred. Please contact the administrator."
)
self.assertEqual(
err.splitlines()[-2], "AssertionError"
err.splitlines()[-2],
"AssertionError: wsgi.input.read() takes exactly one argument"
)

def test_wsgi_input_readline_type(self):
def bad_app(e, s):
# Monkey-patch the underlying input to return wrong type
class BadInput:
def read(self, size): return b""
def readline(self, *args): return "not bytes"
def readlines(self, *args): return []
def __iter__(self): return self
e["wsgi.input"].input = BadInput()
e["wsgi.input"].readline()
s("200 OK", [("Content-Type", "text/plain; charset=utf-8")])
return [b"data"]
out, err = run_amock(validator(bad_app))
self.assertIn("wsgi.input.readline() must return bytes",
err.splitlines()[-2])

def test_wsgi_errors_write_type(self):
def bad_app(e, s):
e["wsgi.errors"].write(b"not a string")
s("200 OK", [("Content-Type", "text/plain; charset=utf-8")])
return [b"data"]
out, err = run_amock(validator(bad_app))
self.assertIn("wsgi.errors.write() requires a str argument",
err.splitlines()[-2])

def test_wsgi_write_wrapper_type(self):
def bad_app(e, s):
write = s("200 OK", [("Content-Type", "text/plain; charset=utf-8")])
write("not bytes")
return [b"data"]
out, err = run_amock(validator(bad_app))
self.assertIn("write() argument must be a bytes instance",
err.splitlines()[-2])

def test_headers_tuple_length(self):
def bad_app(e, s):
s("200 OK", [("Content-Type",)])
return [b"data"]
out, err = run_amock(validator(bad_app))
self.assertIn("Individual headers must be 2-item tuples",
err.splitlines()[-2])

@force_not_colorized
def test_bytes_validation(self):
def app(e, s):
Expand Down
34 changes: 24 additions & 10 deletions Lib/wsgiref/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,23 +194,32 @@ def __init__(self, wsgi_input):
self.input = wsgi_input

def read(self, *args):
assert_(len(args) == 1)
assert_(len(args) == 1,
"wsgi.input.read() takes exactly one argument")
v = self.input.read(*args)
assert_(type(v) is bytes)
assert_(type(v) is bytes,
"wsgi.input.read() must return bytes, got %s" % type(v))
return v

def readline(self, *args):
assert_(len(args) <= 1)
assert_(len(args) <= 1,
"wsgi.input.readline() takes at most one argument")
v = self.input.readline(*args)
assert_(type(v) is bytes)
assert_(type(v) is bytes,
"wsgi.input.readline() must return bytes, got %s" % type(v))
return v

def readlines(self, *args):
assert_(len(args) <= 1)
assert_(len(args) <= 1,
"wsgi.input.readlines() takes at most one argument")
lines = self.input.readlines(*args)
assert_(type(lines) is list)
assert_(type(lines) is list,
"wsgi.input.readlines() must return a list, got %s"
% type(lines))
for line in lines:
assert_(type(line) is bytes)
assert_(type(line) is bytes,
"wsgi.input.readlines() must yield bytes, got %s"
% type(line))
return lines

def __iter__(self):
Expand All @@ -226,7 +235,9 @@ def __init__(self, wsgi_errors):
self.errors = wsgi_errors

def write(self, s):
assert_(type(s) is str)
assert_(type(s) is str,
"wsgi.errors.write() requires a str argument, got %s"
% type(s))
self.errors.write(s)

def flush(self):
Expand All @@ -245,7 +256,9 @@ def __init__(self, wsgi_writer):
self.writer = wsgi_writer

def __call__(self, s):
assert_(type(s) is bytes)
assert_(type(s) is bytes,
"write() argument must be a bytes instance, got %s"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, this is __call__

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so should I change it to the real errors? Or would we have it backward compatible?

% type(s))
self.writer(s)

class PartialIteratorWrapper:
Expand Down Expand Up @@ -391,7 +404,8 @@ def check_headers(headers):
assert_(type(item) is tuple,
"Individual headers (%r) must be of type tuple: %r"
% (item, type(item)))
assert_(len(item) == 2)
assert_(len(item) == 2,
"Individual headers must be 2-item tuples, got %r" % (item,))
name, value = item
name = check_string_type(name, "Header name")
value = check_string_type(value, "Header value")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Add descriptive error messages to all bare assertions in
:mod:`wsgiref.validate` middleware, making it easier to diagnose WSGI
compliance issues.
Loading