From: Ben Darnell Date: Thu, 27 Mar 2025 21:36:30 +0000 (-0400) Subject: httputil: Add test for 400 vs 405 method validation X-Git-Tag: v6.5.0b1~16^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F3473%2Fhead;p=thirdparty%2Ftornado.git httputil: Add test for 400 vs 405 method validation --- diff --git a/tornado/test/httpserver_test.py b/tornado/test/httpserver_test.py index 7b411ed6..69ff065c 100644 --- a/tornado/test/httpserver_test.py +++ b/tornado/test/httpserver_test.py @@ -30,7 +30,7 @@ from tornado.testing import ( from tornado.test.util import abstract_base_test from tornado.web import Application, RequestHandler, stream_request_body -from contextlib import closing +from contextlib import closing, contextmanager import datetime import gzip import logging @@ -634,6 +634,38 @@ ok ) yield stream.read_until_close() + @gen_test + def test_invalid_methods(self): + # RFC 9110 distinguishes between syntactically invalid methods and those that are + # valid but unknown. The former must give a 400 status code, while the latter should + # give a 405. + test_cases = [ + ("FOO", 405, None), + ("FOO,BAR", 400, ".*Malformed HTTP request line"), + ] + for method, code, log_msg in test_cases: + if log_msg is not None: + expect_log = ExpectLog(gen_log, log_msg, level=logging.INFO) + else: + + @contextmanager + def noop_context(): + yield + + expect_log = noop_context() # type: ignore + with ( + self.subTest(method=method), + closing(IOStream(socket.socket())) as stream, + expect_log, + ): + yield stream.connect(("127.0.0.1", self.get_http_port())) + stream.write(utf8(f"{method} /echo HTTP/1.1\r\n\r\n")) + resp = yield stream.read_until(b"\r\n\r\n") + self.assertTrue( + resp.startswith(b"HTTP/1.1 %d" % code), + f"expected status code {code} in {resp!r}", + ) + class XHeaderTest(HandlerBaseTestCase): class Handler(RequestHandler):