diff --git a/ssm/ssm2.py b/ssm/ssm2.py index 1bbdeffa..3d5b9d2f 100644 --- a/ssm/ssm2.py +++ b/ssm/ssm2.py @@ -322,11 +322,24 @@ def _handle_msg(self, text): def _save_msg_to_queue(self, body, empaid): """Extract message contents and add to the accept or reject queue.""" - if isinstance(body, bytes): - body = body.decode('ascii') - - extracted_msg, signer, err_msg = self._handle_msg(body) try: + if isinstance(body, bytes): + try: + body = body.decode('ascii') + except UnicodeDecodeError: + err_msg = "Non-ASCII or corrupted message" + log.warning("Message rejected: %s", err_msg) + # Extract the message body replacing malformed data with backslashed + # escape sequence (hexadecimal form of byte value with format \xhh). + body = body.decode('ascii', errors='backslashreplace') + name = self._rejectq.add({'body': body, + 'signer': 'Not available.', + 'empaid': empaid, + 'error': err_msg}) + log.info("Message saved to reject queue as %s", name) + return # Return early to skip the rest of the method. + + extracted_msg, signer, err_msg = self._handle_msg(body) # If the message is empty or the error message is not empty # then reject the message. if extracted_msg is None or err_msg is not None: diff --git a/test/test_ssm.py b/test/test_ssm.py index 5f96fd78..65b02416 100644 --- a/test/test_ssm.py +++ b/test/test_ssm.py @@ -92,6 +92,8 @@ def test_on_message(self): test_ssm.on_message({'empa-id': 'ping'}, 'body') # Check that msg with ID and no real content doesn't raise exception. test_ssm.on_message({'empa-id': '012345'}, 'body') + # Check that non-ASCII messages don't crash the receiver. + test_ssm.on_message({'empa-id': '543210'}, '^LagelosÄü'.encode('utf-8')) def test_init_expired_cert(self): """Test right exception is thrown creating an SSM with expired cert."""