Move HTTP codec

This commit is contained in:
Lonami Exo 2019-06-16 16:07:16 +02:00
parent f082a27ff8
commit ce37365bb7
9 changed files with 46 additions and 55 deletions

View File

@ -2,3 +2,4 @@ from .basecodec import BaseCodec
from .fullcodec import FullCodec
from .intermediatecodec import IntermediateCodec
from .abridgedcodec import AbridgedCodec
from .httpcodec import HttpCodec

View File

@ -17,7 +17,7 @@ class AbridgedCodec(BaseCodec):
def tag():
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
if length < 127:
length = struct.pack('B', length)

View File

@ -24,7 +24,7 @@ class BaseCodec(abc.ABC):
raise NotImplementedError
@abc.abstractmethod
def encode_packet(self, data):
def encode_packet(self, data, ip, port):
"""
Encodes the given data with the current codec instance.

View File

@ -21,7 +21,7 @@ class FullCodec(BaseCodec):
def tag():
return None
def encode_packet(self, data):
def encode_packet(self, data, ip, port):
# https://core.telegram.org/mtproto#tcp-transport
# total length, sequence number, packet and checksum (CRC32)
length = len(data) + 12

View 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)])

View File

@ -18,7 +18,7 @@ class IntermediateCodec(BaseCodec):
def 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
def decode_header(self, header):
@ -33,7 +33,7 @@ class RandomizedIntermediateCodec(IntermediateCodec):
tag = None
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)
padding = os.urandom(pad_size)
return super().encode_packet(data + padding)

View File

@ -7,6 +7,7 @@ import sys
from ...errors import InvalidChecksumError
from ... import helpers
from .baseconnection import BaseConnection
from ..codec import HttpCodec
class AsyncioConnection(BaseConnection):
@ -35,10 +36,10 @@ class AsyncioConnection(BaseConnection):
self._connected = False
self._obfuscation = None # TcpObfuscated and MTProxy
async def _connect(self, timeout=None, ssl=None):
async def _connect(self, timeout=None):
if not self._proxy:
connect_coroutine = asyncio.open_connection(
self._ip, self._port, loop=self._loop, ssl=ssl)
self._ip, self._port, loop=self._loop)
else:
import aiosocks
@ -62,8 +63,7 @@ class AsyncioConnection(BaseConnection):
proxy_auth=auth,
dst=(self._ip, self._port),
remote_resolve=self._proxy.get('remote_resolve', True),
loop=self._loop,
ssl=ssl
loop=self._loop
)
self._reader, self._writer = await asyncio.wait_for(
@ -79,11 +79,11 @@ class AsyncioConnection(BaseConnection):
def connected(self):
return self._connected
async def connect(self, timeout=None, ssl=None):
async def connect(self, timeout=None):
"""
Establishes a connection with the server.
"""
await self._connect(timeout=timeout, ssl=ssl)
await self._connect(timeout=timeout)
self._connected = True
async def disconnect(self):

View File

@ -48,7 +48,7 @@ class BaseConnection(abc.ABC):
raise ConnectionError('Not connected')
# 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:
return await self._send(data)

View File

@ -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)