コード例 #1
0
    def _handle_error_response(self, response: httpclient.HTTPResponse,
                               num_of_retries: int,
                               retries_remaining: List[int]):
        try:
            parsed_body = ET.fromstring(response.body)

            if EbxmlErrorEnvelope.is_ebxml_error(parsed_body):
                _, parsed_response = ebxml_handler.handle_ebxml_error(
                    response.code, response.headers, response.body)
                logger.warning(
                    '0007',
                    'Received ebxml errors from Spine. {HTTPStatus} {Errors}',
                    {
                        'HTTPStatus': response.code,
                        'Errors': parsed_response
                    })

            elif SOAPFault.is_soap_fault(parsed_body):
                _, parsed_response, soap_fault_codes = handle_soap_error(
                    response.code, response.headers, response.body)
                logger.warning(
                    '0008',
                    'Received soap errors from Spine. {HTTPStatus} {Errors}', {
                        'HTTPStatus': response.code,
                        'Errors': parsed_response
                    })

                if SOAPFault.is_soap_fault_retriable(soap_fault_codes):
                    logger.warning(
                        "0015",
                        "A retriable error was encountered {error} {retries_remaining} "
                        "{max_retries}", {
                            "error": parsed_response,
                            "retries_remaining": retries_remaining[0],
                            "max_retries": num_of_retries
                        })
                    if retries_remaining[0] <= 0:
                        # exceeded the number of retries so return the SOAP error response
                        logger.error(
                            "0016",
                            "A request has exceeded the maximum number of retries, {max_retries} "
                            "retries", {"max_retries": num_of_retries})
                    else:
                        raise _NeedToRetryException()
            else:
                logger.warning('0017',
                               "Received an unexpected response from Spine",
                               {'HTTPStatus': response.code})
                parsed_response = "Didn't get expected response from Spine"

        except ET.ParseError as pe:
            logger.warning('0010',
                           'Unable to parse response from Spine. {Exception}',
                           {'Exception': repr(pe)})
            parsed_response = 'Unable to handle response returned from Spine'

        return 500, parsed_response, None
    def _handle_error_response(self, response: httpclient.HTTPResponse):
        try:
            parsed_body = ET.fromstring(response.body)

            if EbxmlErrorEnvelope.is_ebxml_error(parsed_body):
                _, parsed_response = ebxml_handler.handle_ebxml_error(response.code,
                                                                      response.headers,
                                                                      response.body)
                logger.warning('Received ebxml errors from Spine. {HTTPStatus} {Errors}',
                               fparams={'HTTPStatus': response.code, 'Errors': parsed_response})
            elif SOAPFault.is_soap_fault(parsed_body):
                _, parsed_response, _ = handle_soap_error(response.code,
                                                          response.headers,
                                                          response.body)
                logger.warning('Received soap errors from Spine. {HTTPStatus} {Errors}',
                               fparams={'HTTPStatus': response.code, 'Errors': parsed_response})
            else:
                logger.warning("Received an unexpected response from Spine",
                               fparams={'HTTPStatus': response.code})
                parsed_response = "Didn't get expected response from Spine"

        except ET.ParseError:
            logger.exception('Unable to parse response from Spine.')
            parsed_response = 'Unable to handle response returned from Spine'

        return 500, parsed_response, None
コード例 #3
0
def handle_soap_error(code: int, headers: Dict, body: AnyStr) -> Tuple[int, AnyStr, list]:
    """
    Analyzes response from NHS which works in as web service mode
    and returns result of interpretation to external client

    :param code: HTTP response code
    :param headers: HTTP response headers
    :param body: HTTP response body
    :return: Response to external client represented as HTTP status code and body
    """
    soap_fault_codes = []

    if code != 500:
        logger.warning('Not HTTP 500 response. {Code} {Body}', fparams={'Code': code, 'Body': body})
        return code, body, soap_fault_codes

    if HttpHeaders.CONTENT_TYPE not in headers:
        raise ValueError('No Content-Type header in Spine response, response cannot be handled!')

    if headers[HttpHeaders.CONTENT_TYPE] != 'text/xml':
        raise ValueError('Unexpected Content-Type {}!'.format(headers['Content-Type']))

    try:
        parsed_body = ElementTree.fromstring(body)
    except ElementTree.ParseError:
        raise ValueError('Unable to parse response body')

    assert SOAPFault.is_soap_fault(parsed_body), 'Not SOAP Fault response!'
    fault: SOAPFault = SOAPFault.from_parsed(headers, parsed_body)

    error_data_response = {'error_message': 'Error(s) received from Spine. Contact system administrator.',
                           'process_key': 'SOAP_ERROR_HANDLER0002',
                           'errors': []}

    for idx, error_fields in enumerate(fault.error_list):
        all_fields = {**error_fields, **ERROR_RESPONSE_DEFAULTS}
        if all_fields.get('errorCode'):
            soap_fault_codes.append(int(all_fields['errorCode']))
        error_data_response['errors'].append(all_fields)
        logger.error('SOAP Fault returned: {}'.format(' '.join(f'{{{i}}}' for i in all_fields.keys())),
                     fparams=all_fields)

    return 500, json.dumps(error_data_response), soap_fault_codes
コード例 #4
0
def handle_soap_error(code: int, headers: Dict, body: AnyStr) -> Tuple[int, AnyStr, list]:
    """
    Analyzes response from NHS which works in as web service mode
    and returns result of interpretation to external client

    :param code: HTTP response code
    :param headers: HTTP response headers
    :param body: HTTP response body
    :return: Response to external client represented as HTTP status code and body
    """
    soap_fault_codes = []

    if code != 500:
        logger.warning('0001', 'Not HTTP 500 response. {Code} {Body}', {'Code': code, 'Body': body})
        return code, body, soap_fault_codes

    if 'Content-Type' not in headers:
        raise ValueError('No Content-Type header in Spine response, response cannot be handled!')

    if headers['Content-Type'] != 'text/xml':
        raise ValueError('Unexpected Content-Type {}!'.format(headers['Content-Type']))

    try:
        parsed_body = ElementTree.fromstring(body)
    except ElementTree.ParseError:
        raise ValueError('Unable to parse response body')

    assert SOAPFault.is_soap_fault(parsed_body), 'Not SOAP Fault response!'
    fault: SOAPFault = SOAPFault.from_parsed(headers, parsed_body)

    errors_text = ''
    for idx, error_fields in enumerate(fault.error_list):
        all_fields = {**error_fields, **ERROR_RESPONSE_DEFAULTS}
        if all_fields.get('errorCode'):
            soap_fault_codes.append(int(all_fields['errorCode']))
        errors_text += '{}: {}\n'.format(idx, ' '.join([f'{k}={v}' for k, v in all_fields.items()]))
        logger.error('0002',
                     'SOAP Fault returned: {}'.format(' '.join(f'{{{i}}}' for i in all_fields.keys())),
                     all_fields)

    return code, f'Error(s) received from Spine. Contact system administrator.\n{errors_text}', soap_fault_codes
    def test_from_string_single(self):
        message = FileUtilities.get_file_string(
            Path(self.message_dir) / 'soapfault_response_single_error.xml')
        fault: SOAPFault = SOAPFault.from_string({}, message)
        self.assertEqual(fault.fault_code, 'SOAP:Server')
        self.assertEqual(fault.fault_string, 'Application Exception')
        self.assertEqual(len(fault.error_list), 1)

        self.assertEqual(fault.error_list[0]['codeContext'],
                         'urn:nhs:names:error:tms')
        self.assertEqual(fault.error_list[0]['errorCode'], '200')
        self.assertEqual(fault.error_list[0]['severity'], 'Error')
        self.assertEqual(fault.error_list[0]['location'], 'Not Supported')
        self.assertEqual(fault.error_list[0]['description'],
                         'System failure to process message - default')
    def test_soap_error_codes_are_retriable_or_not(self):
        errors_and_expected = [
            ("a retriable failure to process message error code 200",
             [200], True),
            ("a retriable routing failure error code 206", [206], True),
            ("a retriable failure storing memo error code 208", [208], True),
            ("a NON retriable error code 300", [300], False),
            ("a NON retriable set of error codes 300, 207", [300, 207], False),
            ("a mix of retriable and NON retriable error codes 300, 206",
             [300, 206], False),
            ("a mix of retriable and NON retriable error codes 206, 300",
             [206, 300], False),
            ("a set of retriable error codes 208, 206", [208, 206], True)
        ]
        for description, error, expected_result in errors_and_expected:
            with self.subTest(description):
                result = SOAPFault.is_soap_fault_retriable(error)

                self.assertEqual(result, expected_result)
 def test_soap_fault_empty(self):
     self.assertFalse(SOAPFault.is_soap_fault(None))
 def test_soap_fault_multiple(self):
     message = FileUtilities.get_file_string(
         Path(self.message_dir) / 'soapfault_response_multiple_errors.xml')
     self.assertTrue(
         SOAPFault.is_soap_fault(ElementTree.fromstring(message)))
 def test_is_soap_negative(self):
     message = FileUtilities.get_file_string(
         Path(self.message_dir) / 'ebxml_header.xml')
     self.assertFalse(
         SOAPFault.is_soap_fault(ElementTree.fromstring(message)))
コード例 #10
0
 def test_is_soap_empty(self):
     message = file_utilities.get_file_string(
         Path(self.message_dir) / 'soapfault_response_empty.xml')
     self.assertTrue(
         SOAPFault.is_soap_fault(ElementTree.fromstring(message)))