В разделе комментариев вопроса Стеффен Ульрих направил меня к ответу. Нет прямой поддержки тому, что я пытаюсь сделать через http.client.HTTPSConnection
. Однако http.client.HTTPSConnection
вызывает переданную функцию ssl.SSLContext.wrap_socket из переданного SSLContext. Поэтому я смог получить то, что хотел, создав оболочку для этого класса. В случае, если это будет полезно для кого-то другого, мой код теперь выглядит следующим образом:
if scheme == 'https':
if socket.client_sni:
class WrapSSSLContext(ssl.SSLContext):
'''
HTTPSConnection provides no way to specify the
server_hostname in the underlying socket. We
accomplish this by wrapping the context to
overrride the wrap_socket behavior (called later
by HTTPSConnection) to specify the
server_hostname that we want.
'''
def __new__(cls, server_hostname, *args, **kwargs):
return super().__new__(cls, *args, *kwargs)
def __init__(self, server_hostname, *args, **kwargs):
super().__init__(*args, **kwargs)
self._server_hostname = server_hostname
def wrap_socket(self, sock, *args, **kwargs):
kwargs['server_hostname'] = self._server_hostname
return super().wrap_socket(sock, *args, **kwargs)
proxy_to_server_context = WrapSSSLContext(socket.client_sni)
else:
proxy_to_server_context = ssl.SSLContext()
self.tls.conns[origin] = http.client.HTTPSConnection(
replay_server, timeout=self.timeout,
context=proxy_to_server_context, cert_file=self.cert_file)
Таким образом, если я хочу указать SNI, я использую пользовательский класс WrapSSSLContext
, который явно предоставляет имя сервера_хоста, которое я хочу. В противном случае я просто использую стандарт ssl.SSLContext
. Я подтвердил в захвате пакета, это указывает SNI, который я хочу в клиенте привет.
Спасибо Steffen!