Framework for extended message encoding
- helper classes for encoding/decoding messages - includes both old as well as new extended one (msgpack+zlib) - the classes are unused yet and are supposed to be for experimenting
This commit is contained in:
parent
6add48e036
commit
e649adbe37
|
@ -1,2 +0,0 @@
|
||||||
class BTFailure(Exception):
|
|
||||||
pass
|
|
|
@ -1,142 +0,0 @@
|
||||||
# coding: utf-8
|
|
||||||
# The contents of this file are subject to the BitTorrent Open Source License
|
|
||||||
# Version 1.1 (the License). You may not copy or use this file, in either
|
|
||||||
# source code or executable form, except in compliance with the License. You
|
|
||||||
# may obtain a copy of the License at http://www.bittorrent.com/license/.
|
|
||||||
#
|
|
||||||
# Software distributed under the License is distributed on an AS IS basis,
|
|
||||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
||||||
# for the specific language governing rights and limitations under the
|
|
||||||
# License.
|
|
||||||
|
|
||||||
# Written by Petru Paler
|
|
||||||
# Modifed by Peter Šurda
|
|
||||||
|
|
||||||
from BTL import BTFailure
|
|
||||||
|
|
||||||
|
|
||||||
def decode_int(x, f):
|
|
||||||
f += 1
|
|
||||||
newf = x.index('e', f)
|
|
||||||
n = int(x[f:newf])
|
|
||||||
if x[f] == '-':
|
|
||||||
if x[f + 1] == '0':
|
|
||||||
raise ValueError
|
|
||||||
elif x[f] == '0' and newf != f+1:
|
|
||||||
raise ValueError
|
|
||||||
return (n, newf+1)
|
|
||||||
|
|
||||||
def decode_string(x, f):
|
|
||||||
colon = x.index(':', f)
|
|
||||||
n = int(x[f:colon])
|
|
||||||
if x[f] == '0' and colon != f+1:
|
|
||||||
raise ValueError
|
|
||||||
colon += 1
|
|
||||||
return (x[colon:colon+n], colon+n)
|
|
||||||
|
|
||||||
def decode_list(x, f):
|
|
||||||
r, f = [], f+1
|
|
||||||
while x[f] != 'e':
|
|
||||||
v, f = decode_func[x[f]](x, f)
|
|
||||||
r.append(v)
|
|
||||||
return (r, f + 1)
|
|
||||||
|
|
||||||
def decode_dict(x, f):
|
|
||||||
r, f = {}, f+1
|
|
||||||
while x[f] != 'e':
|
|
||||||
k, f = decode_string(x, f)
|
|
||||||
r[k], f = decode_func[x[f]](x, f)
|
|
||||||
return (r, f + 1)
|
|
||||||
|
|
||||||
decode_func = {}
|
|
||||||
decode_func['l'] = decode_list
|
|
||||||
decode_func['d'] = decode_dict
|
|
||||||
decode_func['i'] = decode_int
|
|
||||||
decode_func['0'] = decode_string
|
|
||||||
decode_func['1'] = decode_string
|
|
||||||
decode_func['2'] = decode_string
|
|
||||||
decode_func['3'] = decode_string
|
|
||||||
decode_func['4'] = decode_string
|
|
||||||
decode_func['5'] = decode_string
|
|
||||||
decode_func['6'] = decode_string
|
|
||||||
decode_func['7'] = decode_string
|
|
||||||
decode_func['8'] = decode_string
|
|
||||||
decode_func['9'] = decode_string
|
|
||||||
|
|
||||||
def bdecode(x):
|
|
||||||
try:
|
|
||||||
r, l = decode_func[x[0]](x, 0)
|
|
||||||
except (IndexError, KeyError, ValueError):
|
|
||||||
raise BTFailure("not a valid bencoded string")
|
|
||||||
if l != len(x):
|
|
||||||
raise BTFailure("invalid bencoded value (data after valid prefix)")
|
|
||||||
return r
|
|
||||||
|
|
||||||
from types import StringType, IntType, LongType, DictType, ListType, TupleType, UnicodeType, NoneType
|
|
||||||
|
|
||||||
|
|
||||||
class Bencached(object):
|
|
||||||
|
|
||||||
__slots__ = ['bencoded']
|
|
||||||
|
|
||||||
def __init__(self, s):
|
|
||||||
self.bencoded = s
|
|
||||||
|
|
||||||
def encode_bencached(x,r):
|
|
||||||
r.append(x.bencoded)
|
|
||||||
|
|
||||||
def encode_int(x, r):
|
|
||||||
r.extend(('i', str(x), 'e'))
|
|
||||||
|
|
||||||
def encode_bool(x, r):
|
|
||||||
if x:
|
|
||||||
encode_int(1, r)
|
|
||||||
else:
|
|
||||||
encode_int(0, r)
|
|
||||||
|
|
||||||
def encode_string(x, r):
|
|
||||||
r.extend((str(len(x)), ':', x))
|
|
||||||
|
|
||||||
def encode_unicode(x, r):
|
|
||||||
raw = x.encode('utf8')
|
|
||||||
r.extend((str(len(raw)), ':', raw))
|
|
||||||
|
|
||||||
def encode_none(x, r):
|
|
||||||
r.extend('0:')
|
|
||||||
|
|
||||||
def encode_list(x, r):
|
|
||||||
r.append('l')
|
|
||||||
for i in x:
|
|
||||||
encode_func[type(i)](i, r)
|
|
||||||
r.append('e')
|
|
||||||
|
|
||||||
def encode_dict(x,r):
|
|
||||||
r.append('d')
|
|
||||||
ilist = x.items()
|
|
||||||
ilist.sort()
|
|
||||||
for k, v in ilist:
|
|
||||||
r.extend((str(len(k)), ':', k))
|
|
||||||
encode_func[type(v)](v, r)
|
|
||||||
r.append('e')
|
|
||||||
|
|
||||||
encode_func = {}
|
|
||||||
encode_func[Bencached] = encode_bencached
|
|
||||||
encode_func[IntType] = encode_int
|
|
||||||
encode_func[LongType] = encode_int
|
|
||||||
encode_func[StringType] = encode_string
|
|
||||||
encode_func[ListType] = encode_list
|
|
||||||
encode_func[TupleType] = encode_list
|
|
||||||
encode_func[DictType] = encode_dict
|
|
||||||
encode_func[UnicodeType] = encode_unicode
|
|
||||||
encode_func[NoneType] = encode_none
|
|
||||||
|
|
||||||
try:
|
|
||||||
from types import BooleanType
|
|
||||||
encode_func[BooleanType] = encode_bool
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def bencode(x):
|
|
||||||
r = []
|
|
||||||
encode_func[type(x)](x, r)
|
|
||||||
return ''.join(r)
|
|
86
src/helper_msgcoding.py
Normal file
86
src/helper_msgcoding.py
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#!/usr/bin/python2.7
|
||||||
|
|
||||||
|
import msgpack
|
||||||
|
import zlib
|
||||||
|
|
||||||
|
from debug import logger
|
||||||
|
|
||||||
|
BITMESSAGE_ENCODING_IGNORE = 0
|
||||||
|
BITMESSAGE_ENCODING_TRIVIAL = 1
|
||||||
|
BITMESSAGE_ENCODING_SIMPLE = 2
|
||||||
|
BITMESSAGE.ENCODING_EXTENDED = 3
|
||||||
|
|
||||||
|
class MsgEncode(object):
|
||||||
|
def __init__(self, message, encoding = BITMESSAGE_ENCODING_SIMPLE):
|
||||||
|
self.data = None
|
||||||
|
self.encoding = encoding
|
||||||
|
self.length = 0
|
||||||
|
if self.encoding == BITMESSAGE_ENCODING_EXTENDED:
|
||||||
|
self.encodeExtended(message)
|
||||||
|
elif self.encoding == BITMESSAGE_ENCODING_SIMPLE:
|
||||||
|
self.encodeSimple(message)
|
||||||
|
elif self.encoding == BITMESSAGE_ENCODING_TRIVIAL:
|
||||||
|
self.encodeTrivial(message)
|
||||||
|
|
||||||
|
def encodeExtended(self, message):
|
||||||
|
try:
|
||||||
|
self.data = zlib.compress(msgpack.dumps({"": "message", "subject": message['subject'], "message": ['body']}), 9)
|
||||||
|
except zlib.error:
|
||||||
|
logger.error ("Error compressing message")
|
||||||
|
raise
|
||||||
|
except msgpack.exceptions.PackException:
|
||||||
|
logger.error ("Error msgpacking message")
|
||||||
|
raise
|
||||||
|
self.length = len(self.data)
|
||||||
|
|
||||||
|
def encodeSimple(self, message):
|
||||||
|
self.data = 'Subject:' + message['subject'] + '\n' + 'Body:' + message['body']
|
||||||
|
self.length = len(self.data)
|
||||||
|
|
||||||
|
def encodeTrivial(self, message):
|
||||||
|
self.data = message['body']
|
||||||
|
self.length = len(self.data)
|
||||||
|
|
||||||
|
class MsgDecode(object):
|
||||||
|
def __init__(self, encoding, data):
|
||||||
|
self.encoding = encoding
|
||||||
|
if self.encoding == BITMESSAGE_ENCODING_EXTENDED:
|
||||||
|
self.decodeExtended(data)
|
||||||
|
elif self.encoding in [BITMESSAGE_ENCODING_SIMPLE, BITMESSAGE_ENCODING_TRIVIAL]:
|
||||||
|
self.decodeSimple(data)
|
||||||
|
return
|
||||||
|
|
||||||
|
def decodeExtended(self, data):
|
||||||
|
try:
|
||||||
|
tmp = msgpack.loads(zlib.decompress(data))
|
||||||
|
except zlib.error:
|
||||||
|
logger.error ("Error decompressing message")
|
||||||
|
raise
|
||||||
|
except (msgpack.exceptions.UnpackException,
|
||||||
|
msgpack.exceptions.ExtraData):
|
||||||
|
logger.error ("Error msgunpacking message")
|
||||||
|
raise
|
||||||
|
try:
|
||||||
|
if tmp[""] == "message":
|
||||||
|
self.body = tmp["body"]
|
||||||
|
self.subject = tmp["subject"]
|
||||||
|
except:
|
||||||
|
logger.error ("Malformed message")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def decodeSimple(self, data):
|
||||||
|
bodyPositionIndex = string.find(data, '\nBody:')
|
||||||
|
if bodyPositionIndex > 1:
|
||||||
|
subject = message[8:bodyPositionIndex]
|
||||||
|
# Only save and show the first 500 characters of the subject.
|
||||||
|
# Any more is probably an attack.
|
||||||
|
subject = subject[:500]
|
||||||
|
body = message[bodyPositionIndex + 6:]
|
||||||
|
else:
|
||||||
|
subject = ''
|
||||||
|
body = message
|
||||||
|
# Throw away any extra lines (headers) after the subject.
|
||||||
|
if subject:
|
||||||
|
subject = subject.splitlines()[0]
|
||||||
|
self.subject = subject
|
||||||
|
self.message = body
|
Reference in New Issue
Block a user