summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorRafael H. Schloming <rhs@apache.org>2007-07-23 14:34:45 +0000
committerRafael H. Schloming <rhs@apache.org>2007-07-23 14:34:45 +0000
commit09e0292f2be2c7bf4efe69df7254ba17d342eb32 (patch)
tree65ab9e4ab25f56d2aab9909bbc534a5abc33874b /python
parentbd22eec7032ebbd62bc8e59ff2f3f059adc652fc (diff)
downloadqpid-python-09e0292f2be2c7bf4efe69df7254ba17d342eb32.tar.gz
Applied a modified version of the range checking patch from QPID-498.
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@558741 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'python')
-rw-r--r--python/qpid/codec.py158
-rw-r--r--python/qpid/testlib.py2
2 files changed, 142 insertions, 18 deletions
diff --git a/python/qpid/codec.py b/python/qpid/codec.py
index b0b596b89c..b615a0f6ed 100644
--- a/python/qpid/codec.py
+++ b/python/qpid/codec.py
@@ -22,8 +22,11 @@
"""
Utility code to translate between python objects and AMQP encoded data
fields.
+
+The unit test for this module is located in tests/codec.py
"""
+import re
from cStringIO import StringIO
from struct import *
from reference import ReferenceId
@@ -33,7 +36,14 @@ class EOF(Exception):
class Codec:
+ """
+ class that handles encoding/decoding of AMQP primitives
+ """
+
def __init__(self, stream):
+ """
+ initializing the stream/fields used
+ """
self.stream = stream
self.nwrote = 0
self.nread = 0
@@ -41,6 +51,9 @@ class Codec:
self.outgoing_bits = []
def read(self, n):
+ """
+ reads in 'n' bytes from the stream. Can raise EFO exception
+ """
data = self.stream.read(n)
if n > 0 and len(data) == 0:
raise EOF()
@@ -48,15 +61,24 @@ class Codec:
return data
def write(self, s):
+ """
+ writes data 's' to the stream
+ """
self.flushbits()
self.stream.write(s)
self.nwrote += len(s)
def flush(self):
+ """
+ flushes the bits and data present in the stream
+ """
self.flushbits()
self.stream.flush()
def flushbits(self):
+ """
+ flushes the bits(compressed into octets) onto the stream
+ """
if len(self.outgoing_bits) > 0:
bytes = []
index = 0
@@ -69,9 +91,15 @@ class Codec:
self.encode_octet(byte)
def pack(self, fmt, *args):
+ """
+ packs the data 'args' as per the format 'fmt' and writes it to the stream
+ """
self.write(pack(fmt, *args))
def unpack(self, fmt):
+ """
+ reads data from the stream and unpacks it as per the format 'fmt'
+ """
size = calcsize(fmt)
data = self.read(size)
values = unpack(fmt, data)
@@ -81,85 +109,166 @@ class Codec:
return values
def encode(self, type, value):
+ """
+ calls the appropriate encode function e.g. encode_octet, encode_short etc.
+ """
getattr(self, "encode_" + type)(value)
def decode(self, type):
+ """
+ calls the appropriate decode function e.g. decode_octet, decode_short etc.
+ """
return getattr(self, "decode_" + type)()
- # bit
def encode_bit(self, o):
+ """
+ encodes a bit
+ """
if o:
self.outgoing_bits.append(True)
else:
self.outgoing_bits.append(False)
def decode_bit(self):
+ """
+ decodes a bit
+ """
if len(self.incoming_bits) == 0:
bits = self.decode_octet()
for i in range(8):
self.incoming_bits.append(bits >> i & 1 != 0)
return self.incoming_bits.pop(0)
- # octet
def encode_octet(self, o):
+ """
+ encodes octet (8 bits) data 'o' in network byte order
+ """
+
+ # octet's valid range is [0,255]
+ if (o < 0 or o > 255):
+ raise ValueError('Valid range of octet is [0,255]')
+
self.pack("!B", o)
def decode_octet(self):
+ """
+ decodes a octet (8 bits) encoded in network byte order
+ """
return self.unpack("!B")
- # short
def encode_short(self, o):
+ """
+ encodes short (16 bits) data 'o' in network byte order
+ """
+
+ # short int's valid range is [0,65535]
+ if (o < 0 or o > 65535):
+ raise ValueError('Valid range of short int is [0,65535]')
+
self.pack("!H", o)
def decode_short(self):
+ """
+ decodes a short (16 bits) in network byte order
+ """
return self.unpack("!H")
- # long
def encode_long(self, o):
+ """
+ encodes long (32 bits) data 'o' in network byte order
+ """
+
+ if (o < 0):
+ raise ValueError('unsinged long int cannot be less than 0')
+
self.pack("!L", o)
def decode_long(self):
+ """
+ decodes a long (32 bits) in network byte order
+ """
return self.unpack("!L")
- # longlong
def encode_longlong(self, o):
+ """
+ encodes long long (64 bits) data 'o' in network byte order
+ """
self.pack("!Q", o)
def decode_longlong(self):
+ """
+ decodes a long long (64 bits) in network byte order
+ """
return self.unpack("!Q")
def enc_str(self, fmt, s):
+ """
+ encodes a string 's' in network byte order as per format 'fmt'
+ """
size = len(s)
self.pack(fmt, size)
self.write(s)
def dec_str(self, fmt):
+ """
+ decodes a string in network byte order as per format 'fmt'
+ """
size = self.unpack(fmt)
return self.read(size)
- # shortstr
def encode_shortstr(self, s):
+ """
+ encodes a short string 's' in network byte order
+ """
+
+ # short strings are limited to 255 octets
+ if len(s) > 255:
+ raise ValueError('Short strings are limited to 255 octets')
+
self.enc_str("!B", s)
def decode_shortstr(self):
+ """
+ decodes a short string in network byte order
+ """
return self.dec_str("!B")
- # longstr
def encode_longstr(self, s):
+ """
+ encodes a long string 's' in network byte order
+ """
if isinstance(s, dict):
self.encode_table(s)
else:
self.enc_str("!L", s)
def decode_longstr(self):
+ """
+ decodes a long string 's' in network byte order
+ """
return self.dec_str("!L")
- # table
+ KEY_CHECK = re.compile(r"[\$#A-Za-z][\$#A-Za-z0-9_]*")
+
def encode_table(self, tbl):
+ """
+ encodes a table data structure in network byte order
+ """
enc = StringIO()
codec = Codec(enc)
if tbl:
for key, value in tbl.items():
+ # Field names MUST start with a letter, '$' or '#' and may
+ # continue with letters, '$' or '#', digits, or underlines, to
+ # a maximum length of 128 characters.
+
+ if len(key) > 128:
+ raise ValueError("field table key too long: '%s'" % key)
+
+ m = Codec.KEY_CHECK.match(key)
+ if m == None or m.end() != len(key):
+ raise ValueError("invalid field table key: '%s'" % key)
+
codec.encode_shortstr(key)
if isinstance(value, basestring):
codec.write("S")
@@ -172,6 +281,9 @@ class Codec:
self.write(s)
def decode_table(self):
+ """
+ decodes a table data structure in network byte order
+ """
size = self.decode_long()
start = self.nread
result = {}
@@ -188,27 +300,39 @@ class Codec:
return result
def encode_timestamp(self, t):
- # XXX
+ """
+ encodes a timestamp data structure in network byte order
+ """
self.encode_longlong(t)
def decode_timestamp(self):
- # XXX
+ """
+ decodes a timestamp data structure in network byte order
+ """
return self.decode_longlong()
def encode_content(self, s):
- # content can be passed as a string in which case it is assumed to
- # be inline data, or as an instance of ReferenceId indicating it is
- # a reference id
+ """
+ encodes a content data structure in network byte order
+
+ content can be passed as a string in which case it is assumed to
+ be inline data, or as an instance of ReferenceId indicating it is
+ a reference id
+ """
if isinstance(s, ReferenceId):
self.encode_octet(1)
self.encode_longstr(s.id)
- else:
+ else:
self.encode_octet(0)
self.encode_longstr(s)
- def decode_content(self):
- # return a string for inline data and a ReferenceId instance for
- # references
+ def decode_content(self):
+ """
+ decodes a content data structure in network byte order
+
+ return a string for inline data and a ReferenceId instance for
+ references
+ """
type = self.decode_octet()
if type == 0:
return self.decode_longstr()
diff --git a/python/qpid/testlib.py b/python/qpid/testlib.py
index fa904ff029..4467a1f4cd 100644
--- a/python/qpid/testlib.py
+++ b/python/qpid/testlib.py
@@ -122,7 +122,7 @@ Options:
print "Using specification from:", self.specfile
self.spec = qpid.spec.load(self.specfile, *self.errata)
if len(self.tests) == 0:
-# self.tests=findmodules("tests")
+ self.tests=findmodules("tests")
if self.use08spec():
self.tests+=findmodules("tests_0-8")
else: