diff options
| author | Rafael H. Schloming <rhs@apache.org> | 2007-07-23 14:34:45 +0000 |
|---|---|---|
| committer | Rafael H. Schloming <rhs@apache.org> | 2007-07-23 14:34:45 +0000 |
| commit | 09e0292f2be2c7bf4efe69df7254ba17d342eb32 (patch) | |
| tree | 65ab9e4ab25f56d2aab9909bbc534a5abc33874b /python | |
| parent | bd22eec7032ebbd62bc8e59ff2f3f059adc652fc (diff) | |
| download | qpid-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.py | 158 | ||||
| -rw-r--r-- | python/qpid/testlib.py | 2 |
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: |
