diff --git a/CHANGES b/CHANGES index f4a109124..0633fb999 100644 --- a/CHANGES +++ b/CHANGES @@ -10,6 +10,8 @@ Incompatible changes Features added -------------- +* #3008: ``linkcheck`` builder ignores self-signed certificate URL + Bugs fixed ---------- diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index e1eeb396c..92ab5a0d3 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -35,7 +35,7 @@ from sphinx.builders import Builder from sphinx.util import encode_uri from sphinx.util.console import purple, red, darkgreen, darkgray, \ darkred, turquoise -from sphinx.util.requests import requests, useragent_header +from sphinx.util.requests import requests, useragent_header, is_ssl_error class AnchorCheckParser(HTMLParser): @@ -152,7 +152,10 @@ class CheckExternalLinksBuilder(Builder): else: return 'broken', str(err), 0 except Exception as err: - return 'broken', str(err), 0 + if is_ssl_error(err): + return 'ignored', str(err), 0 + else: + return 'broken', str(err), 0 if response.url.rstrip('/') == req_url.rstrip('/'): return 'working', '', 0 else: @@ -211,7 +214,10 @@ class CheckExternalLinksBuilder(Builder): if lineno: self.info('(line %4d) ' % lineno, nonl=1) if status == 'ignored': - self.info(darkgray('-ignored- ') + uri) + if info: + self.info(darkgray('-ignored- ') + uri + ': ' + info) + else: + self.info(darkgray('-ignored- ') + uri) elif status == 'local': self.info(darkgray('-local- ') + uri) self.write_entry('local', docname, lineno, uri) diff --git a/sphinx/util/requests.py b/sphinx/util/requests.py index 9bd8f251c..36ac1e0e7 100644 --- a/sphinx/util/requests.py +++ b/sphinx/util/requests.py @@ -14,6 +14,7 @@ from __future__ import absolute_import import requests import warnings import pkg_resources +from requests.packages.urllib3.exceptions import SSLError # try to load requests[security] try: @@ -41,3 +42,14 @@ except pkg_resources.UnknownExtra: useragent_header = [('User-Agent', 'Mozilla/5.0 (X11; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0')] + + +def is_ssl_error(exc): + if isinstance(exc, SSLError): + return True + else: + args = getattr(exc, 'args', []) + if args and isinstance(args[0], SSLError): + return True + else: + return False