Skip to content

Commit

Permalink
Merge pull request #9309 from jamathews/4.0.x
Browse files Browse the repository at this point in the history
Handle ConnectionError on HTTP HEAD Requests
  • Loading branch information
tk0miya committed Jun 13, 2021
2 parents 0197005 + 7e71b75 commit a5eefc0
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Expand Up @@ -67,6 +67,8 @@ Bugs fixed
* #9270: html theme : pyramid theme generates incorrect logo links
* #9217: manpage: The name of manpage directory that is generated by
:confval:`man_make_section_directory` is not correct
* #9306: Linkcheck reports broken link when remote server closes the connection
on HEAD request
* #9280: py domain: "exceptions" module is not displayed
* #9224: ``:param:`` and ``:type:`` fields does not support a type containing
whitespace (ex. ``Dict[str, str]``)
Expand Down
6 changes: 4 additions & 2 deletions sphinx/builders/linkcheck.py
Expand Up @@ -26,7 +26,7 @@
from docutils import nodes
from docutils.nodes import Element
from requests import Response
from requests.exceptions import HTTPError, TooManyRedirects
from requests.exceptions import ConnectionError, HTTPError, TooManyRedirects

from sphinx.application import Sphinx
from sphinx.builders.dummy import DummyBuilder
Expand Down Expand Up @@ -456,7 +456,9 @@ def check_uri() -> Tuple[str, str, int]:
config=self.config, auth=auth_info,
**kwargs)
response.raise_for_status()
except (HTTPError, TooManyRedirects) as err:
# Servers drop the connection on HEAD requests, causing
# ConnectionError.
except (ConnectionError, HTTPError, TooManyRedirects) as err:
if isinstance(err, HTTPError) and err.response.status_code == 429:
raise
# retry with GET request if that fails, some servers
Expand Down
26 changes: 26 additions & 0 deletions tests/test_build_linkcheck.py
Expand Up @@ -579,3 +579,29 @@ def test_limit_rate_bails_out_after_waiting_max_time(app):
rate_limits)
next_check = worker.limit_rate(FakeResponse())
assert next_check is None


class ConnectionResetHandler(http.server.BaseHTTPRequestHandler):
def do_HEAD(self):
self.connection.close()

def do_GET(self):
self.send_response(200, "OK")
self.end_headers()


@pytest.mark.sphinx('linkcheck', testroot='linkcheck-localserver', freshenv=True)
def test_get_after_head_raises_connection_error(app):
with http_server(ConnectionResetHandler):
app.build()
content = (app.outdir / 'output.txt').read_text()
assert not content
content = (app.outdir / 'output.json').read_text()
assert json.loads(content) == {
"filename": "index.rst",
"lineno": 1,
"status": "working",
"code": 0,
"uri": "http://localhost:7777/",
"info": "",
}

0 comments on commit a5eefc0

Please sign in to comment.