summaryrefslogtreecommitdiff
path: root/paramiko/message.py
diff options
context:
space:
mode:
authorSebastian Deiss <s.deiss@science-computing.de>2014-03-26 11:39:26 +0100
committerSebastian Deiss <s.deiss@science-computing.de>2014-03-26 11:39:26 +0100
commita23d9bc654b5278f1ab43df825ed559e4f9a2332 (patch)
tree593ae35cd2b7f550f5b9ff3d4babac57f072e741 /paramiko/message.py
parent5407b1a27468d5abedde93b51aad5bd97bd046c4 (diff)
parentbd8f96d33a3e1ee6162540a6f230ef93e435528a (diff)
downloadparamiko-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.py146
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)