From 22a7b64e4e94bc8351e29e1904156fedf7ac6da5 Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Sun, 8 Jul 2018 17:39:06 +0200 Subject: [PATCH] Support HTTPS --- telethon/extensions/tcpclient.py | 9 +++++- telethon/network/connection/http.py | 44 +++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/telethon/extensions/tcpclient.py b/telethon/extensions/tcpclient.py index ace0d38c..2b9ee03d 100644 --- a/telethon/extensions/tcpclient.py +++ b/telethon/extensions/tcpclient.py @@ -11,6 +11,7 @@ import asyncio import errno import logging import socket +import ssl from io import BytesIO CONN_RESET_ERRNOS = { @@ -28,6 +29,7 @@ try: except ImportError: socks = None +SSL_PORT = 443 __log__ = logging.getLogger(__name__) @@ -37,15 +39,18 @@ class TcpClient: class SocketClosed(ConnectionError): pass - def __init__(self, *, loop, timeout, proxy=None): + def __init__(self, *, loop, timeout, ssl=None, proxy=None): """ Initializes the TCP client. :param proxy: the proxy to be used, if any. :param timeout: the timeout for connect, read and write operations. + :param ssl: ssl.wrap_socket keyword arguments to use when connecting + if port == SSL_PORT, or do nothing if not present. """ self._loop = loop self.proxy = proxy + self.ssl = ssl self._socket = None self._closed = asyncio.Event(loop=self._loop) self._closed.set() @@ -87,6 +92,8 @@ class TcpClient: try: if self._socket is None: self._socket = self._create_socket(mode, self.proxy) + if self.ssl and port == SSL_PORT: + self._socket = ssl.wrap_socket(self._socket, **self.ssl) await asyncio.wait_for( self._loop.sock_connect(self._socket, address), diff --git a/telethon/network/connection/http.py b/telethon/network/connection/http.py index 9fe52504..63717543 100644 --- a/telethon/network/connection/http.py +++ b/telethon/network/connection/http.py @@ -1,17 +1,49 @@ -from .tcpfull import ConnectionTcpFull +import errno +import ssl + +try: + import aiohttp +except ImportError: + aiohttp = None -class ConnectionHttp(ConnectionTcpFull): +from .common import Connection +from ...extensions import TcpClient + + +class ConnectionHttp(Connection): def __init__(self, *, loop, timeout, proxy=None): + if aiohttp is None: + raise RuntimeError('HTTP(S) mode requires the aiohttp ' + 'package, which is not installed') + super().__init__(loop=loop, timeout=timeout, proxy=proxy) + self.conn = TcpClient( + timeout=self._timeout, loop=self._loop, proxy=self._proxy, + ssl=dict(ssl_version=ssl.PROTOCOL_SSLv23, ciphers='ADH-AES256-SHA') + ) + self.read = self.conn.read + self.write = self.conn.write self._host = None async def connect(self, ip, port): - if port != 80: - port = 80 # HTTP without TLS needs port 80 - self._host = '{}:{}'.format(ip, port) - return await super().connect(ip, port) + try: + await self.conn.connect(ip, port) + except OSError as e: + if e.errno == errno.EISCONN: + return # Already connected, no need to re-set everything up + else: + raise + + def get_timeout(self): + return self.conn.timeout + + def is_connected(self): + return self.conn.is_connected + + async def close(self): + self.conn.close() async def recv(self): while True: