Treat SSL failures as broken links in the linkcheck builder (#11431)

TLS operates at a lower layer than HTTP, and so if there is a TLS-related error from a host,
it seems unlikely that retrying with a different higher-layer protocol request
(HTTP GET instead of HTTP HEAD) could succeed.
We should not make additional HTTP requests that we do not believe will succeed.
This commit is contained in:
James Addison 2023-07-20 21:38:21 +01:00 committed by GitHub
parent e45fb5e61b
commit 13720de50c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 10 additions and 3 deletions

View File

@ -18,7 +18,7 @@ from urllib.parse import unquote, urlparse, urlsplit, urlunparse
from docutils import nodes from docutils import nodes
from requests import Response from requests import Response
from requests.exceptions import ConnectionError, HTTPError, TooManyRedirects from requests.exceptions import ConnectionError, HTTPError, SSLError, TooManyRedirects
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.builders.dummy import DummyBuilder from sphinx.builders.dummy import DummyBuilder
@ -333,6 +333,10 @@ class HyperlinkAvailabilityCheckWorker(Thread):
del response del response
break break
except SSLError as err:
# SSL failure; report that the link is broken.
return 'broken', str(err), 0
except (ConnectionError, TooManyRedirects) as err: except (ConnectionError, TooManyRedirects) as err:
# Servers drop the connection on HEAD requests, causing # Servers drop the connection on HEAD requests, causing
# ConnectionError. # ConnectionError.
@ -361,7 +365,7 @@ class HyperlinkAvailabilityCheckWorker(Thread):
continue continue
except Exception as err: except Exception as err:
# Unhandled exception (intermittent or permanent); report that the # Unhandled exception (intermittent or permanent); report that
# the link is broken. # the link is broken.
return 'broken', str(err), 0 return 'broken', str(err), 0

View File

@ -18,6 +18,7 @@ import pytest
from sphinx.builders.linkcheck import HyperlinkAvailabilityCheckWorker, RateLimit from sphinx.builders.linkcheck import HyperlinkAvailabilityCheckWorker, RateLimit
from sphinx.testing.util import strip_escseq from sphinx.testing.util import strip_escseq
from sphinx.util import requests
from sphinx.util.console import strip_colors from sphinx.util.console import strip_colors
from .utils import CERT_FILE, http_server, https_server from .utils import CERT_FILE, http_server, https_server
@ -394,7 +395,9 @@ class OKHandler(http.server.BaseHTTPRequestHandler):
def test_invalid_ssl(app): def test_invalid_ssl(app):
# Link indicates SSL should be used (https) but the server does not handle it. # Link indicates SSL should be used (https) but the server does not handle it.
with http_server(OKHandler): with http_server(OKHandler):
with mock.patch("sphinx.builders.linkcheck.requests.get", wraps=requests.get) as get_request:
app.build() app.build()
assert not get_request.called
with open(app.outdir / 'output.json', encoding='utf-8') as fp: with open(app.outdir / 'output.json', encoding='utf-8') as fp:
content = json.load(fp) content = json.load(fp)