diff options
author | Sebastian Deiss <s.deiss@science-computing.de> | 2014-03-26 11:39:26 +0100 |
---|---|---|
committer | Sebastian Deiss <s.deiss@science-computing.de> | 2014-03-26 11:39:26 +0100 |
commit | a23d9bc654b5278f1ab43df825ed559e4f9a2332 (patch) | |
tree | 593ae35cd2b7f550f5b9ff3d4babac57f072e741 /paramiko/message.py | |
parent | 5407b1a27468d5abedde93b51aad5bd97bd046c4 (diff) | |
parent | bd8f96d33a3e1ee6162540a6f230ef93e435528a (diff) | |
download | paramiko-a23d9bc654b5278f1ab43df825ed559e4f9a2332.tar.gz |
Merge branch 'master' into gssapi-py3-support
Conflicts:
.gitignore
README
demos/demo_simple.py
dev-requirements.txt
paramiko/__init__.py
paramiko/_winapi.py
paramiko/agent.py
paramiko/auth_handler.py
paramiko/ber.py
paramiko/buffered_pipe.py
paramiko/channel.py
paramiko/client.py
paramiko/common.py
paramiko/dsskey.py
paramiko/ecdsakey.py
paramiko/file.py
paramiko/hostkeys.py
paramiko/kex_gex.py
paramiko/kex_group1.py
paramiko/message.py
paramiko/packet.py
paramiko/pkey.py
paramiko/primes.py
paramiko/proxy.py
paramiko/py3compat.py
paramiko/server.py
paramiko/sftp_client.py
paramiko/transport.py
paramiko/util.py
paramiko/win_pageant.py
setup.py
sites/shared_conf.py
sites/www/changelog.rst
sites/www/conf.py
sites/www/index.rst
sites/www/installing.rst
test.py
tests/loop.py
tests/stub_sftp.py
tests/test_auth.py
tests/test_client.py
tests/test_file.py
tests/test_hostkeys.py
tests/test_kex.py
tests/test_message.py
tests/test_packetizer.py
tests/test_pkey.py
tests/test_sftp.py
tests/test_sftp_big.py
tests/test_transport.py
tests/test_util.py
Diffstat (limited to 'paramiko/message.py')
-rw-r--r-- | paramiko/message.py | 146 |
1 files changed, 72 insertions, 74 deletions
diff --git a/paramiko/message.py b/paramiko/message.py index 45086213..b893e76d 100644 --- a/paramiko/message.py +++ b/paramiko/message.py @@ -23,14 +23,15 @@ Implementation of an SSH2 "message". import struct from paramiko import util -from paramiko.common import * +from paramiko.common import zero_byte, max_byte, one_byte, asbytes +from paramiko.py3compat import long, BytesIO, u, integer_types class Message (object): """ - An SSH2 I{Message} is a stream of bytes that encodes some combination of - strings, integers, bools, and infinite-precision integers (known in python - as I{long}s). This class builds or breaks down such a byte stream. + An SSH2 message is a stream of bytes that encodes some combination of + strings, integers, bools, and infinite-precision integers (known in Python + as longs). This class builds or breaks down such a byte stream. Normally you don't need to deal with anything this low-level, but it's exposed for people implementing custom extensions, or features that @@ -41,34 +42,32 @@ class Message (object): def __init__(self, content=None): """ - Create a new SSH2 Message. + Create a new SSH2 message. - @param content: the byte stream to use as the Message content (passed - in only when decomposing a Message). - @type content: string + :param str content: + the byte stream to use as the message content (passed in only when + decomposing a message). """ - if content != None: + if content is not None: self.packet = BytesIO(content) else: self.packet = BytesIO() def __str__(self): + """ + Return the byte stream content of this message, as a string/bytes obj. + """ return self.asbytes() def __repr__(self): """ Returns a string representation of this object, for debugging. - - @rtype: string """ return 'paramiko.Message(' + repr(self.packet.getvalue()) + ')' def asbytes(self): """ Return the byte stream content of this Message, as bytes. - - @return: the contents of this Message. - @rtype: bytes """ return self.packet.getvalue() @@ -81,11 +80,8 @@ class Message (object): def get_remainder(self): """ - Return the bytes of this Message that haven't already been parsed and - returned. - - @return: a string of the bytes not parsed yet. - @rtype: string + Return the bytes (as a `str`) of this message that haven't already been + parsed and returned. """ position = self.packet.tell() remainder = self.packet.read() @@ -94,12 +90,9 @@ class Message (object): def get_so_far(self): """ - Returns the bytes of this Message that have been parsed and returned. - The string passed into a Message's constructor can be regenerated by - concatenating C{get_so_far} and L{get_remainder}. - - @return: a string of the bytes parsed so far. - @rtype: string + Returns the `str` bytes of this message that have been parsed and + returned. The string passed into a message's constructor can be + regenerated by concatenating ``get_so_far`` and `get_remainder`. """ position = self.packet.tell() self.rewind() @@ -107,36 +100,31 @@ class Message (object): def get_bytes(self, n): """ - Return the next C{n} bytes of the Message, without decomposing into - an int, string, etc. Just the raw bytes are returned. - - @return: a string of the next C{n} bytes of the Message, or a string - of C{n} zero bytes, if there aren't C{n} bytes remaining. - @rtype: string + Return the next ``n`` bytes of the message (as a `str`), without + decomposing into an int, decoded string, etc. Just the raw bytes are + returned. Returns a string of ``n`` zero bytes if there weren't ``n`` + bytes remaining in the message. """ b = self.packet.read(n) - max_pad_size = 1<<20 # Limit padding to 1 MB - if len(b) < n and n < max_pad_size: + max_pad_size = 1 << 20 # Limit padding to 1 MB + if len(b) < n < max_pad_size: return b + zero_byte * (n - len(b)) return b def get_byte(self): """ - Return the next byte of the Message, without decomposing it. This - is equivalent to L{get_bytes(1)<get_bytes>}. + Return the next byte of the message, without decomposing it. This + is equivalent to `get_bytes(1) <get_bytes>`. - @return: the next byte of the Message, or C{'\000'} if there aren't + :return: + the next (`str`) byte of the message, or ``'\000'`` if there aren't any bytes remaining. - @rtype: string """ return self.get_bytes(1) def get_boolean(self): """ Fetch a boolean from the stream. - - @return: C{True} or C{False} (from the Message). - @rtype: bool """ b = self.get_bytes(1) return b != zero_byte @@ -145,6 +133,18 @@ class Message (object): """ Fetch an int from the stream. + :return: a 32-bit unsigned `int`. + """ + byte = self.get_bytes(1) + if byte == max_byte: + return util.inflate_long(self.get_binary()) + byte += self.get_bytes(3) + return struct.unpack('>I', byte)[0] + + def get_size(self): + """ + Fetch an int from the stream. + @return: a 32-bit unsigned integer. @rtype: int """ @@ -167,8 +167,7 @@ class Message (object): """ Fetch a 64-bit int from the stream. - @return: a 64-bit unsigned integer. - @rtype: long + :return: a 64-bit unsigned integer (`long`). """ return struct.unpack('>Q', self.get_bytes(8))[0] @@ -176,19 +175,15 @@ class Message (object): """ Fetch a long int (mpint) from the stream. - @return: an arbitrary-length integer. - @rtype: long + :return: an arbitrary-length integer (`long`). """ return util.inflate_long(self.get_binary()) def get_string(self): """ - Fetch a string from the stream. This could be a byte string and may + Fetch a `str` from the stream. This could be a byte string and may contain unprintable characters. (It's not unheard of for a string to - contain another byte-stream Message.) - - @return: a string. - @rtype: string + contain another byte-stream message.) """ return self.get_bytes(self.get_size()) @@ -217,11 +212,9 @@ class Message (object): def get_list(self): """ - Fetch a list of strings from the stream. These are trivially encoded - as comma-separated values in a string. - - @return: a list of strings. - @rtype: list of strings + Fetch a `list` of `strings <str>` from the stream. + + These are trivially encoded as comma-separated values in a string. """ return self.get_text().split(',') @@ -229,8 +222,7 @@ class Message (object): """ Write bytes to the stream, without any formatting. - @param b: bytes to add - @type b: str + :param str b: bytes to add """ self.packet.write(b) return self @@ -239,8 +231,7 @@ class Message (object): """ Write a single byte to the stream, without any formatting. - @param b: byte to add - @type b: str + :param str b: byte to add """ self.packet.write(b) return self @@ -249,8 +240,7 @@ class Message (object): """ Add a boolean value to the stream. - @param b: boolean value to add - @type b: bool + :param bool b: boolean value to add """ if b: self.packet.write(one_byte) @@ -262,11 +252,23 @@ class Message (object): """ Add an integer to the stream. - @param n: integer to add - @type n: int + :param int n: integer to add """ self.packet.write(struct.pack('>I', n)) return self + + def add_int(self, n): + """ + Add an integer to the stream. + + :param int n: integer to add + """ + if n >= Message.big_int: + self.packet.write(max_byte) + self.add_string(util.deflate_long(n)) + else: + self.packet.write(struct.pack('>I', n)) + return self def add_int(self, n): """ @@ -286,8 +288,7 @@ class Message (object): """ Add a 64-bit int to the stream. - @param n: long int to add - @type n: long + :param long n: long int to add """ self.packet.write(struct.pack('>Q', n)) return self @@ -297,8 +298,7 @@ class Message (object): Add a long int to the stream, encoded as an infinite-precision integer. This method only works on positive numbers. - @param z: long int to add - @type z: long + :param long z: long int to add """ self.add_string(util.deflate_long(z)) return self @@ -307,8 +307,7 @@ class Message (object): """ Add a string to the stream. - @param s: string to add - @type s: str + :param str s: string to add """ s = asbytes(s) self.add_size(len(s)) @@ -321,8 +320,7 @@ class Message (object): a single string of values separated by commas. (Yes, really, that's how SSH2 does it.) - @param l: list of strings to add - @type l: list(str) + :param list l: list of strings to add """ self.add_string(','.join(l)) return self @@ -341,11 +339,11 @@ class Message (object): """ Add a sequence of items to the stream. The values are encoded based on their type: str, int, bool, list, or long. + + .. warning:: + Longs are encoded non-deterministically. Don't use this method. - @param seq: the sequence of items - @type seq: sequence - - @bug: longs are encoded non-deterministically. Don't use this method. + :param seq: the sequence of items """ for item in seq: self._add(item) |