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
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_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
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_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)))
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)))