mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-03-12 23:48:02 +03:00
Move HTTP codec
This commit is contained in:
parent
f082a27ff8
commit
ce37365bb7
|
@ -2,3 +2,4 @@ from .basecodec import BaseCodec
|
||||||
from .fullcodec import FullCodec
|
from .fullcodec import FullCodec
|
||||||
from .intermediatecodec import IntermediateCodec
|
from .intermediatecodec import IntermediateCodec
|
||||||
from .abridgedcodec import AbridgedCodec
|
from .abridgedcodec import AbridgedCodec
|
||||||
|
from .httpcodec import HttpCodec
|
||||||
|
|
|
@ -17,7 +17,7 @@ class AbridgedCodec(BaseCodec):
|
||||||
def tag():
|
def tag():
|
||||||
return b'\xef' # note: obfuscated tag is this 4 times
|
return b'\xef' # note: obfuscated tag is this 4 times
|
||||||
|
|
||||||
def encode_packet(self, data):
|
def encode_packet(self, data, ip, port):
|
||||||
length = len(data) >> 2
|
length = len(data) >> 2
|
||||||
if length < 127:
|
if length < 127:
|
||||||
length = struct.pack('B', length)
|
length = struct.pack('B', length)
|
||||||
|
|
|
@ -24,7 +24,7 @@ class BaseCodec(abc.ABC):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def encode_packet(self, data):
|
def encode_packet(self, data, ip, port):
|
||||||
"""
|
"""
|
||||||
Encodes the given data with the current codec instance.
|
Encodes the given data with the current codec instance.
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ class FullCodec(BaseCodec):
|
||||||
def tag():
|
def tag():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def encode_packet(self, data):
|
def encode_packet(self, data, ip, port):
|
||||||
# https://core.telegram.org/mtproto#tcp-transport
|
# https://core.telegram.org/mtproto#tcp-transport
|
||||||
# total length, sequence number, packet and checksum (CRC32)
|
# total length, sequence number, packet and checksum (CRC32)
|
||||||
length = len(data) + 12
|
length = len(data) + 12
|
||||||
|
|
33
telethon/network/codec/httpcodec.py
Normal file
33
telethon/network/codec/httpcodec.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
from .basecodec import BaseCodec
|
||||||
|
|
||||||
|
|
||||||
|
SSL_PORT = 443
|
||||||
|
|
||||||
|
|
||||||
|
class HttpCodec(BaseCodec):
|
||||||
|
@staticmethod
|
||||||
|
def header_length():
|
||||||
|
return 4
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def tag():
|
||||||
|
return None
|
||||||
|
|
||||||
|
def encode_packet(self, data, ip, port):
|
||||||
|
return ('POST /api HTTP/1.1\r\n'
|
||||||
|
'Host: {}:{}\r\n'
|
||||||
|
'Content-Type: application/x-www-form-urlencoded\r\n'
|
||||||
|
'Connection: keep-alive\r\n'
|
||||||
|
'Keep-Alive: timeout=100000, max=10000000\r\n'
|
||||||
|
'Content-Length: {}\r\n\r\n'
|
||||||
|
.format(ip, port, len(data))
|
||||||
|
.encode('ascii') + data)
|
||||||
|
|
||||||
|
def decode_header(self, header):
|
||||||
|
if not header.endswith(b'\r\n\r\n'):
|
||||||
|
return -1
|
||||||
|
|
||||||
|
header = header.lower()
|
||||||
|
start = header.index(b'content-length: ') + 16
|
||||||
|
print(header)
|
||||||
|
return int(header[start:header.index(b'\r', start)])
|
|
@ -18,7 +18,7 @@ class IntermediateCodec(BaseCodec):
|
||||||
def tag():
|
def tag():
|
||||||
return b'\xee\xee\xee\xee' # same as obfuscate tag
|
return b'\xee\xee\xee\xee' # same as obfuscate tag
|
||||||
|
|
||||||
def encode_packet(self, data):
|
def encode_packet(self, data, ip, port):
|
||||||
return struct.pack('<i', len(data)) + data
|
return struct.pack('<i', len(data)) + data
|
||||||
|
|
||||||
def decode_header(self, header):
|
def decode_header(self, header):
|
||||||
|
@ -33,7 +33,7 @@ class RandomizedIntermediateCodec(IntermediateCodec):
|
||||||
tag = None
|
tag = None
|
||||||
obfuscate_tag = b'\xdd\xdd\xdd\xdd'
|
obfuscate_tag = b'\xdd\xdd\xdd\xdd'
|
||||||
|
|
||||||
def encode_packet(self, data):
|
def encode_packet(self, data, ip, port):
|
||||||
pad_size = random.randint(0, 3)
|
pad_size = random.randint(0, 3)
|
||||||
padding = os.urandom(pad_size)
|
padding = os.urandom(pad_size)
|
||||||
return super().encode_packet(data + padding)
|
return super().encode_packet(data + padding)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import sys
|
||||||
from ...errors import InvalidChecksumError
|
from ...errors import InvalidChecksumError
|
||||||
from ... import helpers
|
from ... import helpers
|
||||||
from .baseconnection import BaseConnection
|
from .baseconnection import BaseConnection
|
||||||
|
from ..codec import HttpCodec
|
||||||
|
|
||||||
|
|
||||||
class AsyncioConnection(BaseConnection):
|
class AsyncioConnection(BaseConnection):
|
||||||
|
@ -35,10 +36,10 @@ class AsyncioConnection(BaseConnection):
|
||||||
self._connected = False
|
self._connected = False
|
||||||
self._obfuscation = None # TcpObfuscated and MTProxy
|
self._obfuscation = None # TcpObfuscated and MTProxy
|
||||||
|
|
||||||
async def _connect(self, timeout=None, ssl=None):
|
async def _connect(self, timeout=None):
|
||||||
if not self._proxy:
|
if not self._proxy:
|
||||||
connect_coroutine = asyncio.open_connection(
|
connect_coroutine = asyncio.open_connection(
|
||||||
self._ip, self._port, loop=self._loop, ssl=ssl)
|
self._ip, self._port, loop=self._loop)
|
||||||
else:
|
else:
|
||||||
import aiosocks
|
import aiosocks
|
||||||
|
|
||||||
|
@ -62,8 +63,7 @@ class AsyncioConnection(BaseConnection):
|
||||||
proxy_auth=auth,
|
proxy_auth=auth,
|
||||||
dst=(self._ip, self._port),
|
dst=(self._ip, self._port),
|
||||||
remote_resolve=self._proxy.get('remote_resolve', True),
|
remote_resolve=self._proxy.get('remote_resolve', True),
|
||||||
loop=self._loop,
|
loop=self._loop
|
||||||
ssl=ssl
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self._reader, self._writer = await asyncio.wait_for(
|
self._reader, self._writer = await asyncio.wait_for(
|
||||||
|
@ -79,11 +79,11 @@ class AsyncioConnection(BaseConnection):
|
||||||
def connected(self):
|
def connected(self):
|
||||||
return self._connected
|
return self._connected
|
||||||
|
|
||||||
async def connect(self, timeout=None, ssl=None):
|
async def connect(self, timeout=None):
|
||||||
"""
|
"""
|
||||||
Establishes a connection with the server.
|
Establishes a connection with the server.
|
||||||
"""
|
"""
|
||||||
await self._connect(timeout=timeout, ssl=ssl)
|
await self._connect(timeout=timeout)
|
||||||
self._connected = True
|
self._connected = True
|
||||||
|
|
||||||
async def disconnect(self):
|
async def disconnect(self):
|
||||||
|
|
|
@ -48,7 +48,7 @@ class BaseConnection(abc.ABC):
|
||||||
raise ConnectionError('Not connected')
|
raise ConnectionError('Not connected')
|
||||||
|
|
||||||
# TODO Handle asyncio.CancelledError, IOError, Exception
|
# TODO Handle asyncio.CancelledError, IOError, Exception
|
||||||
data = self._codec.encode_packet(data)
|
data = self._codec.encode_packet(data, self._ip, self._port)
|
||||||
async with self._send_lock:
|
async with self._send_lock:
|
||||||
return await self._send(data)
|
return await self._send(data)
|
||||||
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
import asyncio
|
|
||||||
|
|
||||||
|
|
||||||
SSL_PORT = 443
|
|
||||||
|
|
||||||
|
|
||||||
class HttpPacketCodec:
|
|
||||||
tag = None
|
|
||||||
obfuscate_tag = None
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
raise NotImplementedError('Not migrated yet')
|
|
||||||
|
|
||||||
def encode_packet(self, data):
|
|
||||||
return ('POST /api HTTP/1.1\r\n'
|
|
||||||
'Host: {}:{}\r\n'
|
|
||||||
'Content-Type: application/x-www-form-urlencoded\r\n'
|
|
||||||
'Connection: keep-alive\r\n'
|
|
||||||
'Keep-Alive: timeout=100000, max=10000000\r\n'
|
|
||||||
'Content-Length: {}\r\n\r\n'
|
|
||||||
.format(self._conn._ip, self._conn._port, len(data))
|
|
||||||
.encode('ascii') + data)
|
|
||||||
|
|
||||||
async def read_packet(self, reader):
|
|
||||||
while True:
|
|
||||||
line = await reader.readline()
|
|
||||||
if not line or line[-1] != b'\n':
|
|
||||||
raise asyncio.IncompleteReadError(line, None)
|
|
||||||
|
|
||||||
if line.lower().startswith(b'content-length: '):
|
|
||||||
await reader.readexactly(2)
|
|
||||||
length = int(line[16:-2])
|
|
||||||
return await reader.readexactly(length)
|
|
||||||
|
|
||||||
|
|
||||||
class ConnectionHttp:
|
|
||||||
packet_codec = HttpPacketCodec
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
raise NotImplementedError('Not migrated yet')
|
|
||||||
|
|
||||||
async def connect(self, timeout=None, ssl=None):
|
|
||||||
await super().connect(timeout=timeout, ssl=self._port == SSL_PORT)
|
|
Loading…
Reference in New Issue
Block a user