diff --git a/datadog_checks_base/datadog_checks/base/utils/http.py b/datadog_checks_base/datadog_checks/base/utils/http.py index 61782bff19f58..5154ed3bd120b 100644 --- a/datadog_checks_base/datadog_checks/base/utils/http.py +++ b/datadog_checks_base/datadog_checks/base/utils/http.py @@ -529,10 +529,10 @@ def session(self): if self._session is None: self._session = requests.Session() - # Enables HostHeaderSSLAdapter + # Enables HostHeaderSSLSNIAdapter(HostHeaderSSLAdapter) # https://toolbelt.readthedocs.io/en/latest/adapters.html#hostheaderssladapter if self.tls_use_host_header: - self._session.mount('https://', host_header_ssl.HostHeaderSSLAdapter()) + self._session.mount('https://', HostHeaderSSLSNIAdapter()) # Enable Unix Domain Socket (UDS) support. # See: https://github.com/msabramo/requests-unixsocket self._session.mount('{}://'.format(UDS_SCHEME), requests_unixsocket.UnixAdapter()) @@ -993,3 +993,42 @@ class StandardFields(object): if not PY2: StandardFields.__doc__ = '\n'.join('- `{}`'.format(field) for field in STANDARD_FIELDS) + +class HostHeaderSSLSNIAdapter(host_header_ssl.HostHeaderSSLAdapter): + """ + # HostHeaderSSLSNIAdapter is a variation of requests_toolbelt.adapters.host_header_ssl + # that includes an SNI related fix: https://github.com/requests/toolbelt/pull/293 + + # https://toolbelt.readthedocs.io/en/latest/adapters.html#hostheaderssladapter + + A HTTPS Adapter for Python Requests that sets the hostname for certificate + verification based on the Host header. + + This allows requesting the IP address directly via HTTPS without getting + a "hostname doesn't match" exception. + + Example usage: + + >>> s.mount('https://', HostHeaderSSLSNIAdapter()) + >>> s.get("https://93.184.216.34", headers={"Host": "example.org"}) + + """ + def send(self, request, **kwargs): + # HTTP headers are case-insensitive (RFC 7230) + host_header = None + for header in request.headers: + if header.lower() == "host": + host_header = request.headers[header] + break + + connection_pool_kwargs = self.poolmanager.connection_pool_kw + + if host_header: + connection_pool_kwargs["assert_hostname"] = host_header + connection_pool_kwargs["server_hostname"] = host_header + elif "assert_hostname" in connection_pool_kwargs: + # an assert_hostname from a previous request may have been left + connection_pool_kwargs.pop("assert_hostname", None) + connection_pool_kwargs.pop("server_hostname", None) + + return super(HostHeaderSSLSNIAdapter, self).send(request, **kwargs)