def _register_service(self, endpoint): # type: (beans.ExportEndpoint) -> None """ Register a local endpoint :param endpoint: A local endpoint """ # Prepare node content path = self._endpoint_path(self._fw_uid, endpoint.uid) data = to_bytes( EDEFWriter().to_string( [beans.EndpointDescription.from_export(endpoint)] ) ) try: try: # Create an ephemeral node self._zk.create(path, data, True) except NodeExistsError: # Service already exists: update it self._zk.set(path, data) except KazooException as ex: _logger.warning( "Error registering local service: %s", type(ex).__name__ )
def _register_framework(self): """ Registers the framework and its current services in Redis """ # The framework key fw_node = self._framework_path(self._fw_uid) # The host name hostname = socket.gethostname() if hostname == "localhost": logging.warning( "Hostname is '%s': this will be a problem for " "multi-host remote services", hostname, ) # Prepare an ephemeral Z-Node self._zk.create(fw_node, to_bytes(hostname), True) # Load existing services self._load_existing_endpoints() # Register all already exported services for endpoint in self._dispatcher.get_endpoints(): self._register_service(endpoint)
def make_heartbeat(port, path, peer_uid, app_id): """ Prepares the heart beat UDP packet Format : Little endian * Kind of beat (1 byte) * Herald HTTP server port (2 bytes) * Herald HTTP servlet path length (2 bytes) * Herald HTTP servlet path (variable, UTF-8) * Peer UID length (2 bytes) * Peer UID (variable, UTF-8) * Application ID length (2 bytes) * Application ID (variable, UTF-8) :param port: The port to access the Herald HTTP server :param path: The path to the Herald HTTP servlet :param peer_uid: The UID of the peer :param app_id: Application ID :return: The heart beat packet content (byte array) """ # Type and port... packet = struct.pack("<BH", PACKET_TYPE_HEARTBEAT, port) for string in (path, peer_uid, app_id): # Strings... string_bytes = to_bytes(string) packet += struct.pack("<H", len(string_bytes)) packet += string_bytes return packet
def make_heartbeat(port, path, peer_uid, node_uid, app_id): """ Prepares the heart beat UDP packet Format : Little endian * Kind of beat (1 byte) * Herald HTTP server port (2 bytes) * Herald HTTP servlet path length (2 bytes) * Herald HTTP servlet path (variable, UTF-8) * Peer UID length (2 bytes) * Peer UID (variable, UTF-8) * Node UID length (2 bytes) * Node UID (variable, UTF-8) * Application ID length (2 bytes) * Application ID (variable, UTF-8) :param port: The port to access the Herald HTTP server :param path: The path to the Herald HTTP servlet :param peer_uid: The UID of the peer :param node_uid: The UID of the node :param app_id: Application ID :return: The heart beat packet content (byte array) """ # Type and port... packet = struct.pack("<BBH", PACKET_FORMAT_VERSION, PACKET_TYPE_HEARTBEAT, port) for string in (path, peer_uid, node_uid, app_id): # Strings... string_bytes = to_bytes(string) packet += struct.pack("<H", len(string_bytes)) packet += string_bytes return packet
def _write_bytes(self, data): """ Converts the given data then writes it :param data: Data to be written :return: The result of ``self.output.write()`` """ self.output.write(to_bytes(data, self.encoding))
def test_remote_main(self): """ Tests the remote shell 'main' method """ # Get shell PS1 (static method) import pelix.shell.core ps1 = pelix.shell.core._ShellService.get_ps1() # Start the remote shell process port = 9000 process = subprocess.Popen([ sys.executable, '-m', 'coverage', 'run', '-m', 'pelix.shell.remote', '-a', '127.0.0.1', '-p', str(port) ], stdin=subprocess.PIPE, stdout=subprocess.PIPE) # Wait a little to ensure that the socket is here time.sleep(1) try: # Check if the remote shell port has been opened client = ShellClient(None, ps1, self.fail) client.connect(("127.0.0.1", port)) test_string = "running" self.assertEqual( client.run_command("echo {0}".format(test_string)), test_string) # Good enough: stop there client.close() # Avoid being blocked... timer = threading.Timer(5, process.terminate) timer.start() # Stop the interpreter with a result code rc_code = 42 stop_line = "import sys; sys.exit({0})".format(rc_code) process.communicate(to_bytes(stop_line)) # We're should be good timer.cancel() # Check result code self.assertEqual(process.returncode, rc_code) # The ShellClient must fail a new connection self.assertRaises(IOError, client.connect, ("localhost", port)) finally: try: # Kill it in any case process.terminate() except OSError: # Process was already stopped pass
def test_remote_main(self): """ Tests the remote shell 'main' method """ # Get shell PS1 (static method) import pelix.shell.core ps1 = pelix.shell.core._ShellService.get_ps1() # Start the remote shell process port = 9000 process = subprocess.Popen( [sys.executable, '-m', 'coverage', 'run', '-m', 'pelix.shell.remote', '-a', '127.0.0.1', '-p', str(port)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Wait a little to ensure that the socket is here time.sleep(1) try: # Check if the remote shell port has been opened client = ShellClient(None, ps1, self.fail) client.connect(("127.0.0.1", port)) test_string = "running" self.assertEqual( client.run_command("echo {0}".format(test_string)), test_string) # Good enough: stop there client.close() # Avoid being blocked... timer = threading.Timer(5, process.terminate) timer.start() # Stop the interpreter with a result code rc_code = 42 stop_line = "import sys; sys.exit({0})".format(rc_code) process.communicate(to_bytes(stop_line)) # We should be good timer.cancel() # Check result code self.assertEqual(process.returncode, rc_code) # The ShellClient must fail a new connection self.assertRaises(IOError, client.connect, ("localhost", port)) finally: try: # Kill it in any case process.terminate() except OSError: # Process was already stopped pass
def pton(family, address): """ Calls inet_pton :param family: Socket family :param address: A string address :return: The binary form of the given address """ if family == socket.AF_INET: return socket.inet_aton(address) elif family == socket.AF_INET6: # Do it using WinSocks import ctypes winsock = ctypes.windll.ws2_32 # Prepare structure class sockaddr_in6(ctypes.Structure): # pylint: disable=C0103, R0903 """ Definition of the C structure 'sockaddr_in6' """ _fields_ = [ ("sin6_family", ctypes.c_short), ("sin6_port", ctypes.c_ushort), ("sin6_flowinfo", ctypes.c_ulong), ("sin6_addr", ctypes.c_ubyte * 16), ("sin6_scope_id", ctypes.c_ulong), ] # Prepare pointers addr_ptr = ctypes.c_char_p(to_bytes(address)) out_address = sockaddr_in6() size = len(sockaddr_in6) size_ptr = ctypes.pointer(size) # Second call winsock.WSAStringToAddressA( addr_ptr, family, 0, out_address, size_ptr ) # Convert the array... bin_addr = 0 for part in out_address.sin6_addr: bin_addr = bin_addr * 16 + part return bin_addr else: raise ValueError("Unhandled socket family: {0}".format(family))
def pton(family, address): """ Calls inet_pton :param family: Socket family :param address: A string address :return: The binary form of the given address """ if family == socket.AF_INET: return socket.inet_aton(address) elif family == socket.AF_INET6: # Do it using WinSocks import ctypes winsock = ctypes.windll.ws2_32 # Prepare structure class sockaddr_in6(ctypes.Structure): """ Definition of the C structure sockaddr_in6 """ # pylint: disable=C0103 _fields_ = [("sin6_family", ctypes.c_short), ("sin6_port", ctypes.c_ushort), ("sin6_flowinfo", ctypes.c_ulong), ("sin6_addr", ctypes.c_ubyte * 16), ("sin6_scope_id", ctypes.c_ulong)] # Prepare pointers addr_ptr = ctypes.c_char_p(to_bytes(address)) out_address = sockaddr_in6() size = len(sockaddr_in6) size_ptr = ctypes.pointer(size) # Second call winsock.WSAStringToAddressA(addr_ptr, family, 0, out_address, size_ptr) # Convert the array... bin_addr = 0 for part in out_address.sin6_addr: bin_addr = bin_addr * 16 + part return bin_addr else: raise ValueError("Unhandled socket family: {0}".format(family))
def __send_packet(self, data, target=None): """ Sends a UDP datagram to the given target, if given, or to the multicast group. :param data: The content of the datagram :param target: The packet target (can be None) """ if target is None: # Use the multicast target by default target = self._target # Converts data to bytes data = to_bytes(data) # Send the data self._socket.sendto(data, 0, target)
def send_content( self, http_code, content, mime_type="text/html", http_message=None, content_length=-1, ): # type: (int, str, str, str, int) -> None """ Utility method to send the given content as an answer. You can still use get_wfile or write afterwards, if you forced the content length. If content_length is negative (default), it will be computed as the length of the content; if it is positive, the given value will be used; if it is None, the content-length header won't be sent. :param http_code: HTTP result code :param content: Data to be sent (must be a string) :param mime_type: Content MIME type (content-type) :param http_message: HTTP code description :param content_length: Forced content length """ self.set_response(http_code, http_message) if mime_type and not self.is_header_set("content-type"): self.set_header("content-type", mime_type) # Convert the content raw_content = to_bytes(content) if content_length is not None and not self.is_header_set( "content-length" ): if content_length < 0: # Compute the length content_length = len(raw_content) # Send the length self.set_header("content-length", content_length) self.end_headers() # Send the content self.write(raw_content)
def room_jid(self, room_name): """ Prepares a JID object for the given room in the current MUC domain :param room_name: The short name of a room :return: A JID object """ if self.__muc_service == "groupchat.google.com": # Special case: Google Talk requires a specific room name format # Make a MD5 hash of the full room name app_id = self._directory.get_local_peer().app_id full_name = "cohorte-{0}-{1}".format(app_id, room_name) md5 = hashlib.md5(to_bytes(full_name)).hexdigest() # Format the room name to be Google Talk-compatible room_name = "private-chat-{0}".format(str(uuid.UUID(md5))) return sleekxmpp.JID(local=room_name, domain=self.__muc_service)
def run_command(self, command, disconnect=False): """ Runs a command on the remote shell """ # Wait for the first prompt if self.__wait_prompt: self.wait_prompt() self.__wait_prompt = False # Run the command self._socket.send(to_bytes(command + "\n")) # Disconnect if required if disconnect: self.close() return # Get its result data = self.wait_prompt(False) return data.strip()
def make_lastbeat(peer_uid, app_id): """ Prepares the last beat UDP packet (when the peer is going away) Format : Little endian * Kind of beat (1 byte) * Peer UID length (2 bytes) * Peer UID (variable, UTF-8) * Application ID length (2 bytes) * Application ID (variable, UTF-8) :param peer_uid: Peer UID :param app_id: Application ID :return: The last beat packet content (byte array) """ packet = struct.pack("<B", PACKET_TYPE_LASTBEAT) for string in (peer_uid, app_id): string_bytes = to_bytes(string) packet += struct.pack("<H", len(string_bytes)) packet += string_bytes return packet
def make_lastbeat(peer_uid, app_id): """ Prepares the last beat UDP packet (when the peer is going away) Format : Little endian * Kind of beat (1 byte) * Peer UID length (2 bytes) * Peer UID (variable, UTF-8) * Application ID length (2 bytes) * Application ID (variable, UTF-8) :param peer_uid: Peer UID :param app_id: Application ID :return: The last beat packet content (byte array) """ packet = struct.pack("<BB", PACKET_FORMAT_VERSION, PACKET_TYPE_LASTBEAT) for string in (peer_uid, app_id): string_bytes = to_bytes(string) packet += struct.pack("<H", len(string_bytes)) packet += string_bytes return packet
def test_properties(self): """ Tests the console shell properties parameter """ # Prepare some properties key1 = self.random_str()[:5] key2 = self.random_str()[:5] val1 = self.random_str() val2 = self.random_str() # Start the shell process process = subprocess.Popen( [sys.executable, '-m', 'pelix.shell', '-D', '{}={}'.format(key1, val1), '{}={}'.format(key2, val2)], stdin=subprocess.PIPE, stdout=subprocess.PIPE) try: # List properties, stop and get output output = to_str(process.communicate(to_bytes("properties"))[0]) found = 0 for line in output.splitlines(False): if key1 in line: self.assertIn(val1, line) found += 1 elif key2 in line: self.assertIn(val2, line) found += 1 self.assertEqual(found, 2, "Wrong number of properties") finally: try: # Kill it in any case process.terminate() except OSError: # Process was already stopped pass
def do_POST(self, request, response): """ Handles a POST request, i.e. the reception of a message :param request: The HTTP request bean :param response: The HTTP response handler """ # pylint: disable=C0103 # Default code and content code = 200 content = "" # Extract headers content_type = request.get_header('content-type') subject = request.get_header('herald-subject') uid = request.get_header('herald-uid') reply_to = request.get_header('herald-reply-to') timestamp = request.get_header('herald-timestamp') sender_uid = request.get_header('herald-sender-uid') raw_content = to_unicode(request.read_data()) # Client information host = utils.normalize_ip(request.get_client_address()[0]) if not uid or not subject or content_type != CONTENT_TYPE_JSON: # Raw message uid = str(uuid.uuid4()) subject = herald.SUBJECT_RAW msg_content = raw_content port = -1 extra = {'host': host, 'raw': True} else: # Herald message msg_content = jabsorb.from_jabsorb(json.loads(raw_content)) # Store sender information port = int(request.get_header('herald-port', 80)) extra = {'host': host, 'port': port, 'path': request.get_header('herald-path'), 'parent_uid': uid} try: # Check the sender UID port # (not perfect, but can avoid spoofing) if not self._http_directory.check_access( sender_uid, host, port): # Port doesn't match: invalid UID sender_uid = "<invalid>" except ValueError: # Unknown peer UID: keep it as is pass # Prepare the bean message = herald.beans.MessageReceived(uid, subject, msg_content, sender_uid, reply_to, ACCESS_ID, timestamp, extra) # Log before giving message to Herald self._probe.store( herald.PROBE_CHANNEL_MSG_RECV, {"uid": message.uid, "timestamp": time.time(), "transport": ACCESS_ID, "subject": message.subject, "source": sender_uid, "repliesTo": reply_to or "", "transportSource": "[{0}]:{1}".format(host, port)}) if subject.startswith(peer_contact.SUBJECT_DISCOVERY_PREFIX): # Handle discovery message self.__contact.herald_message(self._core, message) else: # All other messages are given to Herald Core self._core.handle_message(message) # Convert content (Python 3) if content: content = jabsorb.to_jabsorb(content) content = to_bytes(content) # Send response response.send_content(code, content, CONTENT_TYPE_JSON)
def test_remote_main(self): """ Tests the remote shell 'main' method """ # Prepare certificates certs_dir = tempfile.mkdtemp(prefix="ipopo-tests-shell-tls") make_certs(certs_dir, PASSWORD) ca_chain = os.path.join(certs_dir, "ca.crt") srv_cert = os.path.join(certs_dir, "server.crt") srv_key = os.path.join(certs_dir, "server.key") client_cert = os.path.join(certs_dir, "client.crt") client_key = os.path.join(certs_dir, "client.key") # Get shell PS1 (static method) import pelix.shell.core ps1 = pelix.shell.core._ShellService.get_ps1() # Start the remote shell process port = 9000 process = subprocess.Popen( [sys.executable, '-m', 'coverage', 'run', '-m', 'pelix.shell.remote', '-a', '127.0.0.1', '-p', str(port), '--cert', srv_cert, '--key', srv_key, '--ca-chain', ca_chain], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Wait a little to ensure that the socket is here time.sleep(1) try: # Check if the remote shell port has been opened client = TLSShellClient( ps1, self.fail, client_cert, client_key) client.connect(("127.0.0.1", port)) test_string = "running" self.assertEqual( client.run_command("echo {0}".format(test_string)), test_string) # Good enough: stop there client.close() # Avoid being blocked... timer = threading.Timer(5, process.terminate) timer.start() # Stop the interpreter with a result code rc_code = 42 stop_line = "import sys; sys.exit({0})".format(rc_code) process.communicate(to_bytes(stop_line)) # We should be good timer.cancel() # Check result code self.assertEqual(process.returncode, rc_code) # The ShellClient must fail a new connection self.assertRaises(IOError, client.connect, ("localhost", port)) finally: try: # Kill it in any case process.terminate() except OSError: # Process was already stopped pass
def do_POST(self, request, response): """ Handles a POST request, i.e. the reception of a message :param request: The HTTP request bean :param response: The HTTP response handler """ # pylint: disable=C0103 # Default code and content code = 200 content = "" # Check content type content_type = request.get_header('content-type') if content_type not in (None, CONTENT_TYPE_JSON): # Unknown content type -> Error 412 "Precondition failed" _logger.critical("Bad content type: %s", content_type) code, content = _make_json_result(412, "Unknown content type") else: # Extract headers subject = request.get_header('herald-subject') uid = request.get_header('herald-uid') reply_to = request.get_header('herald-reply-to') timestamp = request.get_header('herald-timestamp') sender_uid = request.get_header('herald-sender-uid') json_content = to_unicode(request.read_data()) msg_content = jabsorb.from_jabsorb(json.loads(json_content)) # Store sender information host = request.get_client_address()[0] port = int(request.get_header('herald-port', 80)) extra = {'host': host, 'port': port, 'path': request.get_header('herald-path'), 'parent_uid': uid} try: # Check the sender UID port # (not perfect, but can avoid spoofing) if not self._http_directory.check_access(sender_uid, host, port): # Port doesn't match: invalid UID sender_uid = "<invalid>" except ValueError as ex: # Unknown peer UID: keep it as is pass # Let Herald handle the message message = herald.beans.MessageReceived(uid, subject, msg_content, sender_uid, reply_to, ACCESS_ID, timestamp, extra) self._core.handle_message(message) # Convert content (Python 3) if content: content = jabsorb.to_jabsorb(content) content = to_bytes(content) # Send response response.send_content(code, content, CONTENT_TYPE_JSON)
def do_POST(self, request, response): """ Handles a POST request, i.e. the reception of a message :param request: The HTTP request bean :param response: The HTTP response handler """ # pylint: disable=C0103 # Default code and content code = 200 content = "" # Check content type content_type = request.get_header('content-type') if content_type not in (None, CONTENT_TYPE_JSON): # Unknown content type -> Error 412 "Precondition failed" _logger.critical("Bad content type: %s", content_type) code, content = _make_json_result(412, "Unknown content type") else: # Extract headers subject = request.get_header('herald-subject') uid = request.get_header('herald-uid') reply_to = request.get_header('herald-reply-to') timestamp = request.get_header('herald-timestamp') sender_uid = request.get_header('herald-sender-uid') json_content = to_unicode(request.read_data()) msg_content = jabsorb.from_jabsorb(json.loads(json_content)) # Store sender information host = request.get_client_address()[0] port = int(request.get_header('herald-port', 80)) extra = { 'host': host, 'port': port, 'path': request.get_header('herald-path'), 'parent_uid': uid } try: # Check the sender UID port # (not perfect, but can avoid spoofing) if not self._http_directory.check_access( sender_uid, host, port): # Port doesn't match: invalid UID sender_uid = "<invalid>" except ValueError as ex: # Unknown peer UID: keep it as is pass # Let Herald handle the message message = herald.beans.MessageReceived(uid, subject, msg_content, sender_uid, reply_to, ACCESS_ID, timestamp, extra) self._core.handle_message(message) # Convert content (Python 3) if content: content = jabsorb.to_jabsorb(content) content = to_bytes(content) # Send response response.send_content(code, content, CONTENT_TYPE_JSON)
def do_POST(self, request, response): """ Handles a POST request, i.e. the reception of a message :param request: The HTTP request bean :param response: The HTTP response handler """ # pylint: disable=C0103 # Default code and content code = 200 content = "" # Extract headers """ content_type = request.get_header('content-type') subject = request.get_header('herald-subject') uid = request.get_header('herald-uid') reply_to = request.get_header('herald-reply-to') timestamp = request.get_header('herald-timestamp') sender_uid = request.get_header('herald-sender-uid') """ content_type = request.get_header('content-type') subject = None uid = None reply_to = None timestamp = None sender_uid = None raw_content = to_unicode(request.read_data()) # Client information host = utils.normalize_ip(request.get_client_address()[0]) message = None if content_type != CONTENT_TYPE_JSON: # Raw message uid = str(uuid.uuid4()) subject = herald.SUBJECT_RAW #msg_content = raw_content msg_content = raw_content port = -1 extra = {'host': host, 'raw': True} # construct a new Message bean message = herald.beans.MessageReceived(uid, subject, msg_content, None, None, ACCESS_ID, None, extra) else: # Herald message try: received_msg = utils.from_json(raw_content) except Exception as ex: _logger.exception("DoPOST ERROR:: %s", ex) msg_content = received_msg.content subject = received_msg.subject uid = received_msg.uid reply_to = received_msg.reply_to timestamp = received_msg.timestamp sender_uid = received_msg.sender if not uid or not subject: # Raw message uid = str(uuid.uuid4()) subject = herald.SUBJECT_RAW #msg_content = raw_content msg_content = raw_content port = -1 extra = {'host': host, 'raw': True} # construct a new Message bean message = herald.beans.MessageReceived(uid, subject, msg_content, None, None, ACCESS_ID, None, extra) else: # Store sender information try: port = int(received_msg.get_header(herald.transports.http.MESSAGE_HEADER_PORT)) except (KeyError, ValueError, TypeError): port = 80 path = None if herald.transports.http.MESSAGE_HEADER_PATH in received_msg.headers: path = received_msg.get_header(herald.transports.http.MESSAGE_HEADER_PATH) extra = {'host': host, 'port': port, 'path': path, 'parent_uid': uid} try: # Check the sender UID port # (not perfect, but can avoid spoofing) if not self._http_directory.check_access( sender_uid, host, port): # Port doesn't match: invalid UID sender_uid = "<invalid>" except ValueError: # Unknown peer UID: keep it as is pass # Prepare the bean received_msg.add_header(herald.MESSAGE_HEADER_SENDER_UID, sender_uid) received_msg.set_access(ACCESS_ID) received_msg.set_extra(extra) message = received_msg # Log before giving message to Herald self._probe.store( herald.PROBE_CHANNEL_MSG_RECV, {"uid": message.uid, "timestamp": time.time(), "transport": ACCESS_ID, "subject": message.subject, "source": sender_uid, "repliesTo": reply_to or "", "transportSource": "[{0}]:{1}".format(host, port)}) if subject.startswith(peer_contact.SUBJECT_DISCOVERY_PREFIX): # Handle discovery message self.__contact.herald_message(self._core, message) else: # All other messages are given to Herald Core self._core.handle_message(message) # Convert content (Python 3) if content: content = jabsorb.to_jabsorb(content) content = to_bytes(content) # Send response response.send_content(code, content, CONTENT_TYPE_JSON)
def test_echo(self): """ Tests the console shell 'echo' method """ # Get shell PS1 (static method) import pelix.shell.core ps1 = pelix.shell.core._ShellService.get_ps1() # Start the shell process process = subprocess.Popen( [sys.executable, '-m', 'pelix.shell'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # Avoid being blocked... timer = threading.Timer(5, process.terminate) timer.start() # Wait for prompt got = "" while ps1 not in got: char = to_str(process.stdout.read(1)) if not char: if sys.version_info[0] == 2: self.skipTest("Shell console test doesn't work on " "Python 2.7 with Travis") else: if process.poll(): output = to_str(process.stdout.read()) else: output = "<no output>" self.fail("Can't read from stdout (rc={})\n{}" .format(process.returncode, output)) else: got += char # We should be good timer.cancel() try: # Try echoing data = self.random_str() # Write command process.stdin.write(to_bytes("echo {}\n".format(data))) process.stdin.flush() # Read result last_line = to_str(process.stdout.readline()).rstrip() self.assertEqual(last_line, data, "Wrong output") # Stop the process process.stdin.write(to_bytes("exit\n")) process.stdin.flush() # Wait for the process to stop (1 second max) delta = 0 start = time.time() while delta <= 1: delta = time.time() - start if process.poll() is not None: break time.sleep(.1) else: self.fail("Process took too long to stop") finally: try: # Kill it in any case process.terminate() except OSError: # Process was already stopped pass
def do_POST(self, request, response): """ Handles a POST request, i.e. the reception of a message :param request: The HTTP request bean :param response: The HTTP response handler """ # pylint: disable=C0103 # Default code and content code = 200 content = "" # Extract headers """ content_type = request.get_header('content-type') subject = request.get_header('herald-subject') uid = request.get_header('herald-uid') reply_to = request.get_header('herald-reply-to') timestamp = request.get_header('herald-timestamp') sender_uid = request.get_header('herald-sender-uid') """ content_type = request.get_header('content-type') subject = None uid = None reply_to = None timestamp = None sender_uid = None raw_content = to_unicode(request.read_data()) # Client information host = utils.normalize_ip(request.get_client_address()[0]) message = None if content_type != CONTENT_TYPE_JSON: # Raw message uid = str(uuid.uuid4()) subject = herald.SUBJECT_RAW #msg_content = raw_content msg_content = raw_content port = -1 extra = {'host': host, 'raw': True} # construct a new Message bean message = herald.beans.MessageReceived(uid, subject, msg_content, None, None, ACCESS_ID, None, extra) else: # Herald message try: received_msg = utils.from_json(raw_content) except Exception as ex: _logger.exception("DoPOST ERROR:: %s", ex) msg_content = received_msg.content subject = received_msg.subject uid = received_msg.uid reply_to = received_msg.reply_to timestamp = received_msg.timestamp sender_uid = received_msg.sender if not uid or not subject: # Raw message uid = str(uuid.uuid4()) subject = herald.SUBJECT_RAW #msg_content = raw_content msg_content = raw_content port = -1 extra = {'host': host, 'raw': True} # construct a new Message bean message = herald.beans.MessageReceived(uid, subject, msg_content, None, None, ACCESS_ID, None, extra) else: # Store sender information try: port = int( received_msg.get_header( herald.transports.http.MESSAGE_HEADER_PORT)) except (KeyError, ValueError, TypeError): port = 80 path = None if herald.transports.http.MESSAGE_HEADER_PATH in received_msg.headers: path = received_msg.get_header( herald.transports.http.MESSAGE_HEADER_PATH) extra = { 'host': host, 'port': port, 'path': path, 'parent_uid': uid } try: # Check the sender UID port # (not perfect, but can avoid spoofing) if not self._http_directory.check_access( sender_uid, host, port): # Port doesn't match: invalid UID sender_uid = "<invalid>" except ValueError: # Unknown peer UID: keep it as is pass # Prepare the bean received_msg.add_header(herald.MESSAGE_HEADER_SENDER_UID, sender_uid) received_msg.set_access(ACCESS_ID) received_msg.set_extra(extra) message = received_msg # Log before giving message to Herald self._probe.store( herald.PROBE_CHANNEL_MSG_RECV, { "uid": message.uid, "timestamp": time.time(), "transport": ACCESS_ID, "subject": message.subject, "source": sender_uid, "repliesTo": reply_to or "", "transportSource": "[{0}]:{1}".format(host, port) }) if subject.startswith(peer_contact.SUBJECT_DISCOVERY_PREFIX): # Handle discovery message self.__contact.herald_message(self._core, message) else: # All other messages are given to Herald Core self._core.handle_message(message) # Convert content (Python 3) if content: content = jabsorb.to_jabsorb(content) content = to_bytes(content) # Send response response.send_content(code, content, CONTENT_TYPE_JSON)