Beispiel #1
0
    def check_body_length(cls, data, start=0, body_end=None):
        """
        Checks the BodyLength tag (9) for the encoded message data provided.

        :param data: An encoded FIX message.
        :param start: Optimization: the position at which to start the search.
        :param body_end: Optimization: the index at which the body terminates in data. If this value
        is not provided then the data byte string will be parsed to look for the Checksum (10) tag,
        which should denote the end of the message body.

        :return: A tuple consisting of the value of the BodyLength tag in encoded byte format, and the
        index at which the tag ends.

        :raises: ParsingError if the BodyLength tag can either not be found, or if the actual body
        length does not match the check value provided by the server.
        """
        try:
            if body_end is None:
                checksum_check, body_end, _ = utils.rindex_tag(10, data)

            body_length, _, tag_end = utils.index_tag(9, data, start=start)
        except TagNotFound as e:
            raise ParsingError(
                f"BodyLength (9) not found in {utils.decode(data)}.") from e

        body_length = int(body_length)
        actual_length = body_end - tag_end - 1
        if actual_length != body_length:
            raise ParsingError(
                f"Message has wrong body length. Expected: {body_length}, actual: {actual_length}."
            )

        return body_length, tag_end
Beispiel #2
0
    def check_begin_string(cls, data, start=0):
        """
        Checks the BeginString tag (8) for the encoded message data provided.

        :param data: An encoded FIX message.
        :param start: Position at which to start the search. Usually 0.

        :return: A tuple consisting of the value of the BeginString tag in encoded byte format, and the
        index at which the tag ends.

        :raises: ParsingError if the BeginString tag can either not be found, or if it is not the first tag
        in the message.
        """
        try:
            begin_string, start, tag_end = utils.index_tag(8,
                                                           data,
                                                           start=start)
        except TagNotFound as e:
            raise ParsingError(
                f"BeginString (8) not found in {utils.decode(data)}.") from e

        if start != 0:
            # Begin string was not found at start of Message
            raise ParsingError(
                f"Message does not start with BeginString (8): {utils.decode(data)}."
            )

        return begin_string, tag_end
Beispiel #3
0
    def decode_message(cls, data: bytes) -> FIXMessage:
        """
        Constructs a GenericMessage from the provided data. Also uses the BeginString (8), BodyLength (9),
        and Checksum (10) tags to verify the message before decoding.

        :param data: The raw FIX message (probably received from a FIX server via a StreamReader) as a string of bytes.
        :return: a GenericMessage instance initialised from the raw data.
        """
        # Message MUST start with begin_string
        begin_string, begin_tag_end = cls.check_begin_string(data, start=0)

        # Optimization: Find checksum now so that we can re-use its
        # index in both the body_length and subsequent 'check_checksum' calls.
        checksum_check, checksum_tag_start, _ = utils.rindex_tag(10, data)

        # Body length must match what was sent by server
        body_length, body_length_tag_end = cls.check_body_length(
            data, start=begin_tag_end, body_end=checksum_tag_start
        )

        # MsgType must be the third field in the message
        msg_type, _, msg_type_end_tag = utils.index_tag(
            connection.protocol.Tag.MsgType, data, body_length_tag_end
        )

        # MsgSeqNum must be the fourth field in the message
        msg_seq_num, _, msg_seq_num_end_tag = utils.index_tag(
            connection.protocol.Tag.MsgSeqNum, data, msg_type_end_tag
        )

        checksum, _ = cls.check_checksum(
            data, body_start=0, body_end=checksum_tag_start
        )

        message = RawMessage(
            begin_string,
            body_length=body_length,
            message_type=msg_type,
            message_seq_num=msg_seq_num,
            encoded_body=data[msg_seq_num_end_tag + 1 : checksum_tag_start],
            checksum=checksum,
        )
        return message
Beispiel #4
0
def test_find_tag_start_of_message(simple_encoded_msg):
    assert utils.index_tag(8, simple_encoded_msg) == (b"FIX.4.4", 0, 9)
Beispiel #5
0
def test_find_tag_not_found_raises_exception(simple_encoded_msg):
    with pytest.raises(TagNotFound):
        utils.index_tag(123, simple_encoded_msg)
Beispiel #6
0
def test_find_tag(simple_encoded_msg):
    assert utils.index_tag(9, simple_encoded_msg) == (b"5", 9, 13)