Skip to content
Merged
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
7 changes: 5 additions & 2 deletions Lib/test/test_docxmlrpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,6 @@ def test_valid_get_response(self):
# Server raises an exception if we don't start to read the data
response.read()

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_get_css(self):
self.client.request("GET", "/pydoc.css")
response = self.client.getresponse()
Expand All @@ -121,6 +119,7 @@ def test_invalid_get_response(self):

response.read()

@unittest.skip('TODO: RUSTPYTHON; http.client.RemoteDisconnected: Remote end closed connection without response')
def test_lambda(self):
"""Test that lambda functionality stays the same. The output produced
currently is, I suspect invalid because of the unencoded brackets in the
Expand Down Expand Up @@ -163,6 +162,7 @@ def test_autolinking(self):

@make_request_and_skipIf(sys.flags.optimize >= 2,
"Docstrings are omitted with -O2 and above")
@unittest.skip('TODO: RUSTPYTHON; http.client.RemoteDisconnected: Remote end closed connection without response')
def test_system_methods(self):
"""Test the presence of three consecutive system.* methods.

Expand Down Expand Up @@ -190,6 +190,7 @@ def test_system_methods(self):
b'<br>\nThis&nbsp;server&nbsp;does&nbsp;NOT&nbsp;support&nbsp;system'
b'.methodSignature.</tt></dd></dl>'), response)

@unittest.skip('TODO: RUSTPYTHON; http.client.RemoteDisconnected: Remote end closed connection without response')
def test_autolink_dotted_methods(self):
"""Test that selfdot values are made strong automatically in the
documentation."""
Expand All @@ -199,6 +200,7 @@ def test_autolink_dotted_methods(self):
self.assertIn(b"""Try&nbsp;self.<strong>add</strong>,&nbsp;too.""",
response.read())

@unittest.skip('TODO: RUSTPYTHON; http.client.RemoteDisconnected: Remote end closed connection without response')
def test_annotations(self):
""" Test that annotations works as expected """
self.client.request("GET", "/")
Expand All @@ -212,6 +214,7 @@ def test_annotations(self):
b'method_annotation</strong></a>(x: bytes)</dt></dl>'),
response.read())

@unittest.skip('TODO: RUSTPYTHON; TypeError: HTMLDoc.heading() missing 2 required positional arguments: "fgcol" and "bgcol"')
def test_server_title_escape(self):
# bpo-38243: Ensure that the server title and documentation
# are escaped for HTML.
Expand Down
66 changes: 21 additions & 45 deletions Lib/test/test_wsgiref.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from unittest import mock
from test import support
from test.support import warnings_helper
from test.support import socket_helper
from test.test_httpservers import NoLogRequestHandler
from unittest import TestCase
from wsgiref.util import setup_testing_defaults
Expand Down Expand Up @@ -80,41 +80,26 @@ def run_amock(app=hello_app, data=b"GET / HTTP/1.0\n\n"):

return out.getvalue(), err.getvalue()

def compare_generic_iter(make_it,match):
"""Utility to compare a generic 2.1/2.2+ iterator with an iterable

If running under Python 2.2+, this tests the iterator using iter()/next(),
as well as __getitem__. 'make_it' must be a function returning a fresh
def compare_generic_iter(make_it, match):
"""Utility to compare a generic iterator with an iterable

This tests the iterator using iter()/next().
'make_it' must be a function returning a fresh
iterator to be tested (since this may test the iterator twice)."""

it = make_it()
n = 0
if not iter(it) is it:
raise AssertionError
for item in match:
if not it[n]==item: raise AssertionError
n+=1
try:
it[n]
except IndexError:
pass
else:
raise AssertionError("Too many items from __getitem__",it)

if not next(it) == item:
raise AssertionError
try:
iter, StopIteration
except NameError:
next(it)
except StopIteration:
pass
else:
# Only test iter mode under 2.2+
it = make_it()
if not iter(it) is it: raise AssertionError
for item in match:
if not next(it) == item: raise AssertionError
try:
next(it)
except StopIteration:
pass
else:
raise AssertionError("Too many items from .__next__()", it)
raise AssertionError("Too many items from .__next__()", it)


class IntegrationTests(TestCase):
Expand Down Expand Up @@ -149,10 +134,11 @@ def test_environ(self):
b"Python test,Python test 2;query=test;/path/"
)

@unittest.expectedFailure # TODO: RUSTPYTHON; http library needs to be updated
def test_request_length(self):
out, err = run_amock(data=b"GET " + (b"x" * 65537) + b" HTTP/1.0\n\n")
self.assertEqual(out.splitlines()[0],
b"HTTP/1.0 414 Request-URI Too Long")
b"HTTP/1.0 414 URI Too Long")

def test_validated_hello(self):
out, err = run_amock(validator(hello_app))
Expand Down Expand Up @@ -264,7 +250,7 @@ def app(environ, start_response):
class WsgiHandler(NoLogRequestHandler, WSGIRequestHandler):
pass

server = make_server(support.HOST, 0, app, handler_class=WsgiHandler)
server = make_server(socket_helper.HOST, 0, app, handler_class=WsgiHandler)
self.addCleanup(server.server_close)
interrupted = threading.Event()

Expand Down Expand Up @@ -339,7 +325,6 @@ def checkReqURI(self,uri,query=1,**kw):
util.setup_testing_defaults(kw)
self.assertEqual(util.request_uri(kw,query),uri)

@warnings_helper.ignore_warnings(category=DeprecationWarning)
def checkFW(self,text,size,match):

def make_it(text=text,size=size):
Expand All @@ -358,15 +343,6 @@ def make_it(text=text,size=size):
it.close()
self.assertTrue(it.filelike.closed)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_filewrapper_getitem_deprecation(self):
wrapper = util.FileWrapper(StringIO('foobar'), 3)
with self.assertWarnsRegex(DeprecationWarning,
r'Use iterator protocol instead'):
# This should have returned 'bar'.
self.assertEqual(wrapper[1], 'foo')

def testSimpleShifts(self):
self.checkShift('','/', '', '/', '')
self.checkShift('','/x', 'x', '/x', '')
Expand Down Expand Up @@ -473,6 +449,10 @@ def testHopByHop(self):
for alt in hop, hop.title(), hop.upper(), hop.lower():
self.assertFalse(util.is_hop_by_hop(alt))

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_filewrapper_getitem_deprecation(self):
return super().test_filewrapper_getitem_deprecation()

class HeaderTests(TestCase):

def testMappingInterface(self):
Expand Down Expand Up @@ -581,7 +561,7 @@ def testEnviron(self):
# Test handler.environ as a dict
expected = {}
setup_testing_defaults(expected)
# Handler inherits os_environ variables which are not overriden
# Handler inherits os_environ variables which are not overridden
# by SimpleHandler.add_cgi_vars() (SimpleHandler.base_env)
for key, value in os_environ.items():
if key not in expected:
Expand Down Expand Up @@ -821,8 +801,6 @@ def flush(self):
b"Hello, world!",
written)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def testClientConnectionTerminations(self):
environ = {"SERVER_PROTOCOL": "HTTP/1.0"}
for exception in (
Expand All @@ -841,8 +819,6 @@ def write(self, b):

self.assertFalse(stderr.getvalue())

# TODO: RUSTPYTHON
@unittest.expectedFailure
def testDontResetInternalStateOnException(self):
class CustomException(ValueError):
pass
Expand Down
10 changes: 0 additions & 10 deletions Lib/test/test_xmlrpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1042,55 +1042,46 @@ def test_path2(self):
self.assertEqual(p.add(6,8), 6+8)
self.assertRaises(xmlrpclib.Fault, p.pow, 6, 8)

@unittest.expectedFailure # TODO: RUSTPYTHON
@support.requires_resource('walltime')
def test_path3(self):
p = xmlrpclib.ServerProxy(URL+"/is/broken")
self.assertRaises(xmlrpclib.Fault, p.add, 6, 8)

@unittest.expectedFailure # TODO: RUSTPYTHON
@support.requires_resource('walltime')
def test_invalid_path(self):
p = xmlrpclib.ServerProxy(URL+"/invalid")
self.assertRaises(xmlrpclib.Fault, p.add, 6, 8)

@unittest.expectedFailure # TODO: RUSTPYTHON
@support.requires_resource('walltime')
def test_path_query_fragment(self):
p = xmlrpclib.ServerProxy(URL+"/foo?k=v#frag")
self.assertEqual(p.test(), "/foo?k=v#frag")

@unittest.expectedFailure # TODO: RUSTPYTHON
@support.requires_resource('walltime')
def test_path_fragment(self):
p = xmlrpclib.ServerProxy(URL+"/foo#frag")
self.assertEqual(p.test(), "/foo#frag")

@unittest.expectedFailure # TODO: RUSTPYTHON
@support.requires_resource('walltime')
def test_path_query(self):
p = xmlrpclib.ServerProxy(URL+"/foo?k=v")
self.assertEqual(p.test(), "/foo?k=v")

@unittest.expectedFailure # TODO: RUSTPYTHON
@support.requires_resource('walltime')
def test_empty_path(self):
p = xmlrpclib.ServerProxy(URL)
self.assertEqual(p.test(), "/RPC2")

@unittest.expectedFailure # TODO: RUSTPYTHON
@support.requires_resource('walltime')
def test_root_path(self):
p = xmlrpclib.ServerProxy(URL + "/")
self.assertEqual(p.test(), "/")

@unittest.expectedFailure # TODO: RUSTPYTHON
@support.requires_resource('walltime')
def test_empty_path_query(self):
p = xmlrpclib.ServerProxy(URL + "?k=v")
self.assertEqual(p.test(), "?k=v")

@unittest.expectedFailure # TODO: RUSTPYTHON
@support.requires_resource('walltime')
def test_empty_path_fragment(self):
p = xmlrpclib.ServerProxy(URL + "#frag")
Expand Down Expand Up @@ -1142,7 +1133,6 @@ def test_two(self):

#test special attribute access on the serverproxy, through the __call__
#function.
@unittest.skip("TODO: RUSTPYTHON, appears to hang")
class KeepaliveServerTestCase2(BaseKeepaliveServerTestCase):
#ask for two keepalive requests to be handled.
request_count=2
Expand Down
2 changes: 2 additions & 0 deletions Lib/wsgiref/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* validate -- validation wrapper that sits between an app and a server
to detect errors in either

* types -- collection of WSGI-related types for static type checking

To-Do:

* cgi_gateway -- Run WSGI apps under CGI (pending a deployment standard)
Expand Down
38 changes: 27 additions & 11 deletions Lib/wsgiref/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ def run(self, application):
self.setup_environ()
self.result = application(self.environ, self.start_response)
self.finish_response()
except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError):
# We expect the client to close the connection abruptly from time
# to time.
return
except:
try:
self.handle_error()
Expand Down Expand Up @@ -179,7 +183,16 @@ def finish_response(self):
for data in self.result:
self.write(data)
self.finish_content()
finally:
except:
# Call close() on the iterable returned by the WSGI application
# in case of an exception.
if hasattr(self.result, 'close'):
self.result.close()
raise
else:
# We only call close() when no exception is raised, because it
# will set status, result, headers, and environ fields to None.
# See bpo-29183 for more details.
self.close()


Expand Down Expand Up @@ -215,8 +228,7 @@ def start_response(self, status, headers,exc_info=None):
if exc_info:
try:
if self.headers_sent:
# Re-raise original exception if headers sent
raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])
raise
finally:
exc_info = None # avoid dangling circular ref
elif self.headers is not None:
Expand All @@ -225,18 +237,25 @@ def start_response(self, status, headers,exc_info=None):
self.status = status
self.headers = self.headers_class(headers)
status = self._convert_string_type(status, "Status")
assert len(status)>=4,"Status must be at least 4 characters"
assert status[:3].isdigit(), "Status message must begin w/3-digit code"
assert status[3]==" ", "Status message must have a space after code"
self._validate_status(status)

if __debug__:
for name, val in headers:
name = self._convert_string_type(name, "Header name")
val = self._convert_string_type(val, "Header value")
assert not is_hop_by_hop(name),"Hop-by-hop headers not allowed"
assert not is_hop_by_hop(name),\
f"Hop-by-hop header, '{name}: {val}', not allowed"

return self.write

def _validate_status(self, status):
if len(status) < 4:
raise AssertionError("Status must be at least 4 characters")
if not status[:3].isdigit():
raise AssertionError("Status message must begin w/3-digit code")
if status[3] != " ":
raise AssertionError("Status message must have a space after code")

def _convert_string_type(self, value, title):
"""Convert/check value type."""
if type(value) is str:
Expand Down Expand Up @@ -456,10 +475,7 @@ def _write(self,data):
from warnings import warn
warn("SimpleHandler.stdout.write() should not do partial writes",
DeprecationWarning)
while True:
data = data[result:]
if not data:
break
while data := data[result:]:
result = self.stdout.write(data)

def _flush(self):
Expand Down
7 changes: 2 additions & 5 deletions Lib/wsgiref/simple_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,6 @@ def get_environ(self):

env['PATH_INFO'] = urllib.parse.unquote(path, 'iso-8859-1')
env['QUERY_STRING'] = query

host = self.address_string()
if host != self.client_address[0]:
env['REMOTE_HOST'] = host
env['REMOTE_ADDR'] = self.client_address[0]

if self.headers.get('content-type') is None:
Expand Down Expand Up @@ -127,7 +123,8 @@ def handle(self):
return

handler = ServerHandler(
self.rfile, self.wfile, self.get_stderr(), self.get_environ()
self.rfile, self.wfile, self.get_stderr(), self.get_environ(),
multithread=False,
)
handler.request_handler = self # backpointer for logging
handler.run(self.server.get_app())
Expand Down
Loading
Loading