def send_message(self, header, payload): """ Send the message to the partner""" logger.info(f'Sending message {self.message_id} from organization "{self.organization}" ' f'to partner "{self.partner}".') # Set up the http auth if specified in the partner profile auth = None if self.partner.http_auth: auth = (self.partner.http_auth_user, self.partner.http_auth_pass) # Send the message to the partner try: response = requests.post( self.partner.target_url, auth=auth, headers=header, data=payload, verify=self.partner.https_verify_ssl) response.raise_for_status() except requests.exceptions.RequestException as e: self.status = 'R' self.detailed_status = f'Failed to send message, error:\n{traceback.format_exc()}' self.save() return # Process the MDN based on the partner profile settings if self.partner.mdn: if self.partner.mdn_mode == 'ASYNC': self.status = 'P' else: # Process the synchronous MDN received as response # Get the response headers, convert key to lower case # for normalization mdn_headers = dict( (k.lower().replace('_', '-'), response.headers[k]) for k in response.headers) # create the mdn content with message-id and content-type # header and response content mdn_content = f'message-id: {mdn_headers.get("message-id", self.message_id)}\n' mdn_content += f'content-type: {mdn_headers["content-type"]}\n\n' mdn_content = mdn_content.encode('utf-8') + response.content # Parse the as2 mdn received logger.debug(f'Received MDN response for message {self.message_id} ' f'with content: {mdn_content}') as2mdn = As2Mdn() status, detailed_status = as2mdn.parse(mdn_content, lambda x, y: self.as2message) # Update the message status and return the response if status == 'processed': self.status = 'S' run_post_send(self) else: self.status = 'E' self.detailed_status = f'Partner failed to process message: {detailed_status}' Mdn.objects.create_from_as2mdn(as2mdn=as2mdn, message=self, status='R') else: # No MDN requested mark message as success and run command self.status = 'S' run_post_send(self) self.save()
def test_run_post_send_triggers_signal(self, message): callback = Mock() post_send.connect(callback) run_post_send(message) post_send.disconnect(callback) callback.assert_called_once_with(message=message, sender=Message, signal=post_send)
def post(self, request, *args, **kwargs): # extract the headers from the http request as2headers = "" for key in request.META: if key.startswith("HTTP") or key.startswith("CONTENT"): as2headers += ( f'{key.replace("HTTP_", "").replace("_", "-").lower()}: ' f"{request.META[key]}\n") # build the body along with the headers request_body = as2headers.encode() + b"\r\n" + request.body logger.debug( f'Received an HTTP POST from {request.META["REMOTE_ADDR"]} ' f"with payload :\n{request_body}") # First try to see if this is an MDN logger.debug("Check to see if payload is an Asynchronous MDN.") as2mdn = As2Mdn() # Parse the mdn and get the message status status, detailed_status = as2mdn.parse(request_body, self.find_message) if not detailed_status == "mdn-not-found": message = Message.objects.get(message_id=as2mdn.orig_message_id, direction="OUT") logger.info( f"Asynchronous MDN received for AS2 message {as2mdn.message_id} to organization " f"{message.organization.as2_name} from partner {message.partner.as2_name}" ) # Update the message status and return the response if status == "processed": message.status = "S" run_post_send(message) else: message.status = "E" message.detailed_status = ( f"Partner failed to process message: {detailed_status}") # Save the message and create the mdn message.save() Mdn.objects.create_from_as2mdn(as2mdn=as2mdn, message=message, status="R") return HttpResponse(_("AS2 ASYNC MDN has been received")) else: logger.debug("Payload is not an MDN parse it as an AS2 Message") as2message = As2Message() status, exception, as2mdn = as2message.parse( request_body, self.find_organization, self.find_partner, self.check_message_exists, ) logger.info( f'Received an AS2 message with id {as2message.headers.get("message-id")} for ' f'organization {as2message.headers.get("as2-to")} from ' f'partner {as2message.headers.get("as2-from")}.') # In case of duplicates update message id if isinstance(exception[0], DuplicateDocument): as2message.message_id += "_duplicate" # Create the Message and MDN objects message, full_fn = Message.objects.create_from_as2message( as2message=as2message, filename=as2message.payload.get_filename(), payload=as2message.content, direction="IN", status="S" if status == "processed" else "E", detailed_status=exception[1], ) # run post receive command on success if status == "processed": run_post_receive(message, full_fn) # Return the mdn in case of sync else return text message if as2mdn and as2mdn.mdn_mode == "SYNC": message.mdn = Mdn.objects.create_from_as2mdn(as2mdn=as2mdn, message=message, status="S") response = HttpResponse(as2mdn.content) for key, value in as2mdn.headers.items(): response[key] = value return response elif as2mdn and as2mdn.mdn_mode == "ASYNC": Mdn.objects.create_from_as2mdn( as2mdn=as2mdn, message=message, status="P", return_url=as2mdn.mdn_url, ) return HttpResponse(_("AS2 message has been received"))
def send_message(self, header, payload): """ Send the message to the partner""" # Set up the http auth if specified in the partner profile auth = None if self.partner.http_auth: auth = (self.partner.http_auth_user, self.partner.http_auth_pass) # Send the message to the partner try: response = requests.post(self.partner.target_url, auth=auth, headers=header, data=payload) response.raise_for_status() except requests.exceptions.RequestException as e: self.status = 'R' self.detailed_status = \ 'Failed to send message, error:\n%s' % traceback.format_exc() self.save() return # Process the MDN based on the partner profile settings if self.partner.mdn: if self.partner.mdn_mode == 'ASYNC': self.status = 'P' else: # Process the synchronous MDN received as response # Get the response headers, convert key to lower case # for normalization mdn_headers = dict( (k.lower().replace('_', '-'), response.headers[k]) for k in response.headers) # create the mdn content with message-id and content-type # header and response content mdn_content = '%s: %s\n' % ('message-id', mdn_headers.get( 'message-id', self.message_id)) mdn_content += '%s: %s\n\n' % ('content-type', mdn_headers['content-type']) mdn_content = mdn_content.encode('utf-8') + response.content # Parse the as2 mdn received as2mdn = As2Mdn() status, detailed_status = as2mdn.parse( mdn_content, lambda x, y: self.as2message) # Update the message status and return the response if status == 'processed': self.status = 'S' run_post_send(self) else: self.status = 'E' self.detailed_status = \ 'Partner failed to process message: %s' % detailed_status Mdn.objects.create_from_as2mdn(as2mdn=as2mdn, message=self, status='R') else: # No MDN requested mark message as success and run command self.status = 'S' run_post_send(self) self.save()
def post(self, request, *args, **kwargs): # extract the headers from the http request as2headers = '' for key in request.META: if key.startswith('HTTP') or key.startswith('CONTENT'): as2headers += f'{key.replace("HTTP_", "").replace("_", "-").lower()}: ' \ f'{request.META[key]}\n' # build the body along with the headers request_body = as2headers.encode() + b'\r\n' + request.body logger.debug( f'Received an HTTP POST from {request.META["REMOTE_ADDR"]} ' f'with payload :\n{request_body}' ) # First try to see if this is an MDN logger.debug('Check to see if payload is an Asynchronous MDN.') as2mdn = As2Mdn() # Parse the mdn and get the message status status, detailed_status = as2mdn.parse(request_body, self.find_message) if not detailed_status == 'mdn-not-found': message = Message.objects.get(message_id=as2mdn.orig_message_id, direction='OUT') logger.info( f'Asynchronous MDN received for AS2 message {as2mdn.message_id} to organization ' f'{message.organization.as2_name} from partner {message.partner.as2_name}') # Update the message status and return the response if status == 'processed': message.status = 'S' run_post_send(message) else: message.status = 'E' message.detailed_status = f'Partner failed to process message: {detailed_status}' run_post_failure(message) # Save the message and create the mdn message.save() Mdn.objects.create_from_as2mdn(as2mdn=as2mdn, message=message, status='R') return HttpResponse(_('AS2 ASYNC MDN has been received')) else: logger.debug('Payload is not an MDN parse it as an AS2 Message') as2message = As2Message() status, exception, as2mdn = as2message.parse( request_body, self.find_organization, self.find_partner, self.check_message_exists) logger.info( f'Received an AS2 message with id {as2message.headers.get("message-id")} for ' f'organization {as2message.headers.get("as2-to")} from ' f'partner {as2message.headers.get("as2-from")}.' ) # In case of duplicates update message id if isinstance(exception[0], DuplicateDocument): as2message.message_id += '_duplicate' # Create the Message and MDN objects message, full_fn = Message.objects.create_from_as2message( as2message=as2message, filename=as2message.payload.get_filename(), payload=as2message.content, direction='IN', status='S' if status == 'processed' else 'E', detailed_status=exception[1] ) # run post receive command on success if status == 'processed': run_post_receive(message, full_fn) # Return the mdn in case of sync else return text message if as2mdn and as2mdn.mdn_mode == 'SYNC': message.mdn = Mdn.objects.create_from_as2mdn( as2mdn=as2mdn, message=message, status='S') response = HttpResponse(as2mdn.content) for key, value in as2mdn.headers.items(): response[key] = value return response elif as2mdn and as2mdn.mdn_mode == 'ASYNC': Mdn.objects.create_from_as2mdn( as2mdn=as2mdn, message=message, status='P', return_url=as2mdn.mdn_url) return HttpResponse(_('AS2 message has been received'))