def applyAttributes(self, obj, attrs, **kwargs):
        """
        Applies C{attrs} to C{obj}. Since C{blobstore.BlobInfo} objects are
        read-only entities, we only care about the C{key} attribute.
        """
        assert type(obj) is BlobInfoStub

        key = attrs.pop('key', None)

        if not key:
            raise pyamf.DecodeError(
                "Unable to build blobstore.BlobInfo instance. Missing 'key' "
                "attribute."
            )

        try:
            key = blobstore.BlobKey(key)
        except:
            raise pyamf.DecodeError(
                "Unable to build a valid blobstore.BlobKey instance. Key "
                "supplied was %r" % (key,)
            )

        obj.__class__ = blobstore.BlobInfo

        obj.__init__(key)
Example #2
0
def decode(stream, strict=True):
    """
    Decodes a SOL stream. L{strict} mode ensures that the sol stream is as spec
    compatible as possible.

    @return: A C{tuple} containing the C{root_name} and a C{dict} of name,
        value pairs.
    """
    if not isinstance(stream, util.BufferedByteStream):
        stream = util.BufferedByteStream(stream)

    # read the version
    version = stream.read(2)
    if version != HEADER_VERSION:
        raise pyamf.DecodeError('Unknown SOL version in header')

    # read the length
    length = stream.read_ulong()

    if strict and stream.remaining() != length:
        raise pyamf.DecodeError('Inconsistent stream header length')

    # read the signature
    signature = stream.read(10)

    if signature != HEADER_SIGNATURE:
        raise pyamf.DecodeError('Invalid signature')

    length = stream.read_ushort()
    root_name = stream.read_utf8_string(length)

    # read padding
    if stream.read(3) != PADDING_BYTE * 3:
        raise pyamf.DecodeError('Invalid padding read')

    decoder = pyamf.get_decoder(stream.read_uchar())
    decoder.stream = stream

    values = {}

    while True:
        if stream.at_eof():
            break

        name = decoder.readString()
        value = decoder.readElement()

        # read the padding
        t = stream.read(1) 
        while t != PADDING_BYTE:
        #    raise pyamf.DecodeError('Missing padding byte')
            sys.stderr.write('Bad padding byte: 0x02%x\n' % ord(t))
            t = stream.read(1) 

        values[name] = value

    return (root_name, values)
Example #3
0
def _read_header(stream, decoder, strict=False):
    """
    Read AMF L{Message} header from the stream.

    @type stream: L{BufferedByteStream<pyamf.util.BufferedByteStream>}
    @param decoder: An AMF0 decoder.
    @param strict: Use strict decoding policy. Default is C{False}. Will raise
        a L{pyamf.DecodeError} if the data that was read from the stream does
        not match the header length.
    @type strict: C{boolean}
    @return: A C{tuple} containing the name of the header, a C{bool}
        determining if understanding this header is required and the decoded
        data.
    @note: Quite what understanding required headers actually means is unknown.
    @raise DecodeError: Data read from stream does not match header length.
    """
    name_len = stream.read_ushort()
    name = stream.read_utf8_string(name_len)

    required = bool(stream.read_uchar())

    data_len = stream.read_ulong()
    pos = stream.tell()

    data = decoder.readElement()

    if strict and pos + data_len != stream.tell():
        raise pyamf.DecodeError(
            "Data read from stream does not match header length")

    return (name, required, data)
Example #4
0
    def readElement(self):
        """
        Reads an AMF3 element from the data stream.

        @raise DecodeError: The ActionScript type is unsupported.
        @raise EOStream: No more data left to decode.
        """
        pos = self.stream.tell()

        try:
            t = self.stream.read(1)
        except IOError:
            raise pyamf.EOStream

        try:
            func = self._func_cache[t]
        except KeyError:
            func = self.getTypeFunc(t)

            if not func:
                raise pyamf.DecodeError("Unsupported ActionScript type %s" %
                                        (hex(ord(t)), ))

            self._func_cache[t] = func

        try:
            return func()
        except IOError:
            self.stream.seek(pos)

            raise
Example #5
0
def decode(stream, context=None, strict=False):
    """
    Decodes the incoming stream.

    @type   stream: L{BufferedByteStream<pyamf.util.BufferedByteStream>}
    @param  stream: AMF data.
    @type   context: L{amf0.Context<pyamf.amf0.Context>} or
    L{amf3.Context<pyamf.amf3.Context>}
    @param  context: Context.
    @type strict: C{bool}
    @param strict: Enforce strict encoding. Default is C{False}.

    @raise DecodeError: Malformed stream.
    @raise RuntimeError: Decoder is unable to fully consume the
    stream buffer.

    @return: Message envelope.
    @rtype: L{Envelope}
    """
    if not isinstance(stream, util.BufferedByteStream):
        stream = util.BufferedByteStream(stream)

    msg = Envelope()
    msg.amfVersion = stream.read_uchar()

    # see http://osflash.org/documentation/amf/envelopes/remoting#preamble
    # why we are doing this...
    if msg.amfVersion > 0x09:
        raise pyamf.DecodeError("Malformed stream (amfVersion=%d)" %
            msg.amfVersion)

    if context is None:
        context = pyamf.get_context(pyamf.AMF0)
    else:
        context = copy.copy(context)

    decoder = pyamf._get_decoder_class(pyamf.AMF0)(stream, context=context, strict=strict)
    msg.clientType = stream.read_uchar()

    header_count = stream.read_ushort()

    for i in xrange(header_count):
        name, required, data = _read_header(stream, decoder, strict)
        msg.headers[name] = data

        if required:
            msg.headers.set_required(name)

    body_count = stream.read_short()

    for i in range(body_count):
        context.reset()

        target, payload = _read_body(stream, decoder, strict)
        msg[target] = payload

    if strict and stream.remaining() > 0:
        raise RuntimeError("Unable to fully consume the buffer")

    return msg
Example #6
0
def _read_header(stream, decoder, strict=False):
    """
    Read AMF L{Message} header.

    @type   stream: L{BufferedByteStream<pyamf.util.BufferedByteStream>}
    @param  stream: AMF data.
    @type   decoder: L{amf0.Decoder<pyamf.amf0.Decoder>}
    @param  decoder: AMF decoder instance
    @type strict: C{bool}
    @param strict: Use strict decoding policy. Default is C{False}.
    @raise DecodeError: The data that was read from the stream
    does not match the header length.

    @rtype: C{tuple}
    @return:
     - Name of the header.
     - A C{bool} determining if understanding this header is
     required.
     - Value of the header.
    """
    name_len = stream.read_ushort()
    name = stream.read_utf8_string(name_len)

    required = bool(stream.read_uchar())

    data_len = stream.read_ulong()
    pos = stream.tell()

    data = decoder.readElement()

    if strict and pos + data_len != stream.tell():
        raise pyamf.DecodeError(
            "Data read from stream does not match header length")

    return (name, required, data)
Example #7
0
def _read_body(stream, decoder, strict=False):
    """
    Read AMF message body.

    @type   stream: L{BufferedByteStream<pyamf.util.BufferedByteStream>}
    @param  stream: AMF data.
    @type   decoder: L{amf0.Decoder<pyamf.amf0.Decoder>}
    @param  decoder: AMF decoder instance.
    @type strict: C{bool}
    @param strict: Use strict decoding policy. Default is C{False}.
    @raise DecodeError: Data read from stream does not match body length.

    @rtype: C{tuple}
    @return: A C{tuple} containing:
        - ID of the request
        - L{Request} or L{Response}
    """
    def _read_args():
        """
        @raise pyamf.DecodeError: Array type required for request body.
        """
        if stream.read(1) != '\x0a':
            raise pyamf.DecodeError("Array type required for request body")

        x = stream.read_ulong()

        return [decoder.readElement() for i in xrange(x)]

    target = stream.read_utf8_string(stream.read_ushort())
    response = stream.read_utf8_string(stream.read_ushort())

    status = STATUS_OK
    is_request = True

    for (code, s) in STATUS_CODES.iteritems():
        if target.endswith(s):
            is_request = False
            status = code
            target = target[:0 - len(s)]

    data_len = stream.read_ulong()
    pos = stream.tell()

    if is_request:
        data = _read_args()
    else:
        data = decoder.readElement()

    if strict and pos + data_len != stream.tell():
        raise pyamf.DecodeError("Data read from stream does not match body "
            "length (%d != %d)" % (pos + data_len, stream.tell(),))

    if is_request:
        return (response, Request(target, body=data))
    else:
        if status == STATUS_ERROR and isinstance(data, pyamf.ASObject):
            data = get_fault(data)

        return (target, Response(data, status))
Example #8
0
    def __readamf__(self, input):
        data = input.readObject()

        if not hasattr(data, '__iter__'):
            raise pyamf.DecodeError(
                'Unable to read a list when decoding ArrayCollection')

        self.extend(data)
Example #9
0
    def _read_args():
        # we have to go through this insanity because it seems that amf0
        # does not keep the array of args in the object references lookup
        type_byte = stream.peek(1)

        if type_byte == '\x11':
            if not decoder.use_amf3:
                raise pyamf.DecodeError(
                    "Unexpected AMF3 type with incorrect message type")

            return decoder.readElement()

        if type_byte != '\x0a':
            raise pyamf.DecodeError("Array type required for request body")

        stream.read(1)
        x = stream.read_ulong()

        return [decoder.readElement() for i in xrange(x)]
Example #10
0
    def _read_args():
        """
        @raise pyamf.DecodeError: Array type required for request body.
        """
        if stream.read(1) != '\x0a':
            raise pyamf.DecodeError("Array type required for request body")

        x = stream.read_ulong()

        return [decoder.readElement() for i in xrange(x)]
Example #11
0
    def readObject(self):
        """
        Reads an object from the stream.

        @raise ReferenceError: Unknown reference found.
        @raise DecodeError: Unknown object encoding detected.
        """
        ref = self.readInteger(False)

        if ref & REFERENCE_BIT == 0:
            obj = self.context.getObject(ref >> 1)

            if obj is None:
                raise pyamf.ReferenceError(
                    'Unknown reference %d' % (ref >> 1,)
                )

            if self.use_proxies is True:
                obj = self.readProxy(obj)

            return obj

        ref >>= 1

        class_def = self._getClassDefinition(ref)
        alias = class_def.alias

        obj = alias.createInstance(codec=self)
        obj_attrs = dict()

        self.context.addObject(obj)

        if class_def.encoding in (
                ObjectEncoding.EXTERNAL,
                ObjectEncoding.PROXY):
            obj.__readamf__(DataInput(self))

            if self.use_proxies is True:
                obj = self.readProxy(obj)

            return obj
        elif class_def.encoding == ObjectEncoding.DYNAMIC:
            self._readStatic(class_def, obj_attrs)
            self._readDynamic(class_def, obj_attrs)
        elif class_def.encoding == ObjectEncoding.STATIC:
            self._readStatic(class_def, obj_attrs)
        else:
            raise pyamf.DecodeError("Unknown object encoding")

        alias.applyAttributes(obj, obj_attrs, codec=self)

        if self.use_proxies is True:
            obj = self.readProxy(obj)

        return obj
Example #12
0
    def readType(self):
        """
        Read and returns the next byte in the stream and determine its type.

        @raise DecodeError: AMF0 type not recognized.
        @return: AMF0 type.
        """
        type = self.stream.read_uchar()

        if type not in ACTIONSCRIPT_TYPES:
            raise pyamf.DecodeError("Unknown AMF0 type 0x%02x at %d" %
                                    (type, self.stream.tell() - 1))

        return type
Example #13
0
def decode(stream, strict=False, logger=None, timezone_offset=None):
    """
    Decodes the incoming stream as a remoting message.

    @type stream: L{BufferedByteStream<pyamf.util.BufferedByteStream>}
    @param strict: Enforce strict decoding. Default is C{False}.
    @type strict: C{boolean}
    @param logger: Used to log interesting events whilst decoding a remoting
        message.
    @type logger: U{logging.Logger<http://
        docs.python.org/library/logging.html#loggers>}
    @param timezone_offset: The difference between the current timezone and
        UTC. Date/times should always be handled in UTC to avoid confusion but
        this is required for legacy systems.
    @type timezone_offset: U{datetime.datetime.timedelta<http://
        docs.python.org/library/datetime.html#datetime.timedelta>}

    @return: Message L{envelope<Envelope>}.
    @rtype: L{Envelope}
    """
    if not isinstance(stream, util.BufferedByteStream):
        stream = util.BufferedByteStream(stream)

    msg = Envelope()
    msg.amfVersion = stream.read_ushort()

    # see http://osflash.org/documentation/amf/envelopes/remoting#preamble
    # why we are doing this...
    if msg.amfVersion > 0x09:
        raise pyamf.DecodeError(
            "Malformed stream (amfVersion=%d)" % (
                msg.amfVersion,
            )
        )

    decoder = pyamf.get_decoder(
        pyamf.AMF0,
        stream,
        strict=strict,
        timezone_offset=timezone_offset
    )
    context = decoder.context

    decoder.use_amf3 = msg.amfVersion == pyamf.AMF3
    header_count = stream.read_ushort()

    for i in xrange(header_count):
        name, required, data = _read_header(stream, decoder, strict)
        msg.headers[name] = data

        if required:
            msg.headers.set_required(name)

    body_count = stream.read_short()

    for i in xrange(body_count):
        context.clear()

        target, payload = _read_body(stream, decoder, strict, logger)
        msg[target] = payload

    if strict and stream.remaining() > 0:
        raise RuntimeError("Unable to fully consume the buffer")

    return msg
Example #14
0
def _read_body(stream, decoder, strict=False, logger=None):
    """
    Read an AMF message body from the stream.

    @type stream: L{BufferedByteStream<pyamf.util.BufferedByteStream>}
    @param decoder: An AMF0 decoder.
    @param strict: Use strict decoding policy. Default is C{False}.
    @type strict: C{boolean}
    @param logger: Used to log interesting events whilst reading a remoting
        body.
    @type logger: A C{logging.Logger} instance or C{None}
    @return: A C{tuple} containing the C{id} of the request and the L{Request}
        or L{Response}
    """
    def _read_args():
        # we have to go through this insanity because it seems that amf0
        # does not keep the array of args in the object references lookup
        type_byte = stream.peek(1)

        if type_byte == '\x11':
            if not decoder.use_amf3:
                raise pyamf.DecodeError(
                    "Unexpected AMF3 type with incorrect message type")

            return decoder.readElement()

        if type_byte != '\x0a':
            raise pyamf.DecodeError("Array type required for request body")

        stream.read(1)
        x = stream.read_ulong()

        return [decoder.readElement() for i in xrange(x)]

    target = stream.read_utf8_string(stream.read_ushort())
    response = stream.read_utf8_string(stream.read_ushort())

    status = STATUS_OK
    is_request = True

    for code, s in STATUS_CODES.iteritems():
        if not target.endswith(s):
            continue

        is_request = False
        status = code
        target = target[:0 - len(s)]

    data_len = stream.read_ulong()
    pos = stream.tell()

    if is_request:
        data = _read_args()
    else:
        data = decoder.readElement()

    if strict and pos + data_len != stream.tell():
        raise pyamf.DecodeError(
            "Data read from stream does not match body length (%d != %d)" % (
                pos + data_len, stream.tell(),
            )
        )

    if is_request:
        return response, Request(target, body=data)

    if status == STATUS_ERROR and isinstance(data, pyamf.ASObject):
        data = get_fault(data)

    return target, Response(data, status)
Example #15
0
def decode(stream,
           context=None,
           strict=False,
           logger=None,
           timezone_offset=None):
    """
    Decodes the incoming stream as a remoting message.

    @param stream: AMF data.
    @type stream: L{BufferedByteStream<pyamf.util.BufferedByteStream>}
    @param context: Context.
    @type context: L{amf0.Context<pyamf.amf0.Context>} or
    L{amf3.Context<pyamf.amf3.Context>}
    @param strict: Enforce strict decoding. Default is C{False}.
    @type strict: C{bool}
    @param logger: Used to log interesting events whilst decoding a remoting
        message.
    @type logger: A L{logging.Logger} instance or C{None}.
    @param timezone_offset: The difference between the current timezone and
        UTC. Date/times should always be handled in UTC to avoid confusion but
        this is required for legacy systems.
    @type timezone_offset: L{datetime.timedelta}

    @raise DecodeError: Malformed stream.
    @raise RuntimeError: Decoder is unable to fully consume the
        stream buffer.

    @return: Message envelope.
    @rtype: L{Envelope}
    """
    if not isinstance(stream, util.BufferedByteStream):
        stream = util.BufferedByteStream(stream)

    if logger is not None:
        logger.debug('remoting.decode start')

    msg = Envelope()
    msg.amfVersion = stream.read_uchar()

    # see http://osflash.org/documentation/amf/envelopes/remoting#preamble
    # why we are doing this...
    if msg.amfVersion > 0x09:
        raise pyamf.DecodeError("Malformed stream (amfVersion=%d)" %
                                msg.amfVersion)

    if context is None:
        context = pyamf.get_context(pyamf.AMF0, exceptions=False)

    decoder = pyamf.get_decoder(pyamf.AMF0,
                                stream,
                                context=context,
                                strict=strict,
                                timezone_offset=timezone_offset)
    msg.clientType = stream.read_uchar()

    header_count = stream.read_ushort()

    for i in xrange(header_count):
        name, required, data = _read_header(stream, decoder, strict)
        msg.headers[name] = data

        if required:
            msg.headers.set_required(name)

    body_count = stream.read_short()

    for i in range(body_count):
        context.clear()

        target, payload = _read_body(stream, decoder, strict, logger)
        msg[target] = payload

    if strict and stream.remaining() > 0:
        raise RuntimeError("Unable to fully consume the buffer")

    if logger is not None:
        logger.debug('remoting.decode end')

    return msg