Use HTTP/1.1 in linkcheck test webservers (#11392)

This commit is contained in:
James Addison
2023-07-22 20:12:32 +01:00
committed by GitHub
parent bef7fc2e45
commit 566e4e74a0
2 changed files with 53 additions and 8 deletions

View File

@@ -28,24 +28,40 @@ SPHINX_DOCS_INDEX = path.abspath(path.join(__file__, "..", "roots", "test-linkch
class DefaultsHandler(http.server.BaseHTTPRequestHandler): class DefaultsHandler(http.server.BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def do_HEAD(self): def do_HEAD(self):
if self.path[1:].rstrip() == "": if self.path[1:].rstrip() == "":
self.send_response(200, "OK") self.send_response(200, "OK")
self.send_header("Content-Length", "0")
self.end_headers() self.end_headers()
elif self.path[1:].rstrip() == "anchor.html": elif self.path[1:].rstrip() == "anchor.html":
self.send_response(200, "OK") self.send_response(200, "OK")
self.send_header("Content-Length", "0")
self.end_headers() self.end_headers()
else: else:
self.send_response(404, "Not Found") self.send_response(404, "Not Found")
self.send_header("Content-Length", "0")
self.end_headers() self.end_headers()
def do_GET(self): def do_GET(self):
self.do_HEAD()
if self.path[1:].rstrip() == "": if self.path[1:].rstrip() == "":
self.wfile.write(b"ok\n\n") content = b"ok\n\n"
elif self.path[1:].rstrip() == "anchor.html": elif self.path[1:].rstrip() == "anchor.html":
doc = '<!DOCTYPE html><html><body><a id="found"></a></body></html>' doc = '<!DOCTYPE html><html><body><a id="found"></a></body></html>'
self.wfile.write(doc.encode('utf-8')) content = doc.encode("utf-8")
else:
content = b""
if content:
self.send_response(200, "OK")
self.send_header("Content-Length", str(len(content)))
self.end_headers()
self.wfile.write(content)
else:
self.send_response(404, "Not Found")
self.send_header("Content-Length", "0")
self.end_headers()
@pytest.mark.sphinx('linkcheck', testroot='linkcheck', freshenv=True) @pytest.mark.sphinx('linkcheck', testroot='linkcheck', freshenv=True)
@@ -182,6 +198,8 @@ def test_anchors_ignored(app):
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-anchor', freshenv=True) @pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-anchor', freshenv=True)
def test_raises_for_invalid_status(app): def test_raises_for_invalid_status(app):
class InternalServerErrorHandler(http.server.BaseHTTPRequestHandler): class InternalServerErrorHandler(http.server.BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def do_GET(self): def do_GET(self):
self.send_error(500, "Internal Server Error") self.send_error(500, "Internal Server Error")
@@ -208,6 +226,8 @@ def custom_handler(valid_credentials=(), success_criteria=lambda _: True):
del valid_credentials del valid_credentials
class CustomHandler(http.server.BaseHTTPRequestHandler): class CustomHandler(http.server.BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def authenticated(method): def authenticated(method):
def method_if_authenticated(self): def method_if_authenticated(self):
if expected_token is None: if expected_token is None:
@@ -216,6 +236,7 @@ def custom_handler(valid_credentials=(), success_criteria=lambda _: True):
return method(self) return method(self)
else: else:
self.send_response(403, "Forbidden") self.send_response(403, "Forbidden")
self.send_header("Content-Length", "0")
self.end_headers() self.end_headers()
return method_if_authenticated return method_if_authenticated
@@ -228,8 +249,10 @@ def custom_handler(valid_credentials=(), success_criteria=lambda _: True):
def do_GET(self): def do_GET(self):
if success_criteria(self): if success_criteria(self):
self.send_response(200, "OK") self.send_response(200, "OK")
self.send_header("Content-Length", "0")
else: else:
self.send_response(400, "Bad Request") self.send_response(400, "Bad Request")
self.send_header("Content-Length", "0")
self.end_headers() self.end_headers()
return CustomHandler return CustomHandler
@@ -343,11 +366,14 @@ def test_linkcheck_request_headers_default(app):
def make_redirect_handler(*, support_head): def make_redirect_handler(*, support_head):
class RedirectOnceHandler(http.server.BaseHTTPRequestHandler): class RedirectOnceHandler(http.server.BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def do_HEAD(self): def do_HEAD(self):
if support_head: if support_head:
self.do_GET() self.do_GET()
else: else:
self.send_response(405, "Method Not Allowed") self.send_response(405, "Method Not Allowed")
self.send_header("Content-Length", "0")
self.end_headers() self.end_headers()
def do_GET(self): def do_GET(self):
@@ -356,6 +382,7 @@ def make_redirect_handler(*, support_head):
else: else:
self.send_response(302, "Found") self.send_response(302, "Found")
self.send_header("Location", "http://localhost:7777/?redirected=1") self.send_header("Location", "http://localhost:7777/?redirected=1")
self.send_header("Content-Length", "0")
self.end_headers() self.end_headers()
def log_date_time_string(self): def log_date_time_string(self):
@@ -433,13 +460,19 @@ def test_linkcheck_allowed_redirects(app, warning):
class OKHandler(http.server.BaseHTTPRequestHandler): class OKHandler(http.server.BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def do_HEAD(self): def do_HEAD(self):
self.send_response(200, "OK") self.send_response(200, "OK")
self.send_header("Content-Length", "0")
self.end_headers() self.end_headers()
def do_GET(self): def do_GET(self):
self.do_HEAD() content = b"ok\n"
self.wfile.write(b"ok\n") self.send_response(200, "OK")
self.send_header("Content-Length", str(len(content)))
self.end_headers()
self.wfile.write(content)
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-https', freshenv=True) @pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver-https', freshenv=True)
@@ -546,15 +579,21 @@ def test_connect_to_selfsigned_nonexistent_cert_file(app):
class InfiniteRedirectOnHeadHandler(http.server.BaseHTTPRequestHandler): class InfiniteRedirectOnHeadHandler(http.server.BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def do_HEAD(self): def do_HEAD(self):
self.send_response(302, "Found") self.send_response(302, "Found")
self.send_header("Location", "http://localhost:7777/") self.send_header("Location", "http://localhost:7777/")
self.send_header("Content-Length", "0")
self.end_headers() self.end_headers()
def do_GET(self): def do_GET(self):
content = b"ok\n"
self.send_response(200, "OK") self.send_response(200, "OK")
self.send_header("Content-Length", str(len(content)))
self.end_headers() self.end_headers()
self.wfile.write(b"ok\n") self.wfile.write(content)
self.close_connection = True # we don't expect the client to read this response body
@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True) @pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True)
@@ -580,11 +619,14 @@ def test_TooManyRedirects_on_HEAD(app, monkeypatch):
def make_retry_after_handler(responses): def make_retry_after_handler(responses):
class RetryAfterHandler(http.server.BaseHTTPRequestHandler): class RetryAfterHandler(http.server.BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def do_HEAD(self): def do_HEAD(self):
status, retry_after = responses.pop(0) status, retry_after = responses.pop(0)
self.send_response(status) self.send_response(status)
if retry_after: if retry_after:
self.send_header('Retry-After', retry_after) self.send_header('Retry-After', retry_after)
self.send_header("Content-Length", "0")
self.end_headers() self.end_headers()
def log_date_time_string(self): def log_date_time_string(self):
@@ -731,11 +773,14 @@ def test_limit_rate_bails_out_after_waiting_max_time(app):
class ConnectionResetHandler(http.server.BaseHTTPRequestHandler): class ConnectionResetHandler(http.server.BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def do_HEAD(self): def do_HEAD(self):
self.connection.close() self.close_connection = True
def do_GET(self): def do_GET(self):
self.send_response(200, "OK") self.send_response(200, "OK")
self.send_header("Content-Length", "0")
self.end_headers() self.end_headers()

View File

@@ -19,7 +19,7 @@ LOCK_PATH = str(TESTS_ROOT / 'test-server.lock')
class HttpServerThread(threading.Thread): class HttpServerThread(threading.Thread):
def __init__(self, handler, *args, **kwargs): def __init__(self, handler, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.server = http.server.HTTPServer(("localhost", 7777), handler) self.server = http.server.ThreadingHTTPServer(("localhost", 7777), handler)
def run(self): def run(self):
self.server.serve_forever(poll_interval=0.001) self.server.serve_forever(poll_interval=0.001)