def data_received(self, data): """Called when incoming data is received on the socket. We feed that data to the parser and the see if this produced any XML event. This could trigger one or more event (a stanza is received, the stream is opened, etc). """ self.parser.feed(data) for event, xml in self.parser.read_events(): if event == 'start': if self.xml_depth == 0: # We have received the start of the root element. self.xml_root = xml log.debug('[33;1mRECV[0m: %s', highlight(tostring(self.xml_root, xmlns=self.default_ns, stream=self, top_level=True, open_only=True))) self.start_stream_handler(self.xml_root) self.xml_depth += 1 if event == 'end': self.xml_depth -= 1 if self.xml_depth == 0: # The stream's root element has closed, # terminating the stream. log.debug("End of stream received") self.abort() elif self.xml_depth == 1: # A stanza is an XML element that is a direct child of # the root element, hence the check of depth == 1 self.loop.idle_call(functools.partial(self.__spawn_event, xml)) if self.xml_root is not None: # Keep the root element empty of children to # save on memory use. self.xml_root.clear()
def send_raw(self, data): """Send raw data across the stream. :param string data: Any bytes or utf-8 string value. """ log.debug("[36;1mSEND[0m: %s", highlight(data)) if not self.transport: raise NotConnectedError() if isinstance(data, str): data = data.encode('utf-8') self.transport.write(data)
def data_received(self, data): """Called when incoming data is received on the socket. We feed that data to the parser and the see if this produced any XML event. This could trigger one or more event (a stanza is received, the stream is opened, etc). """ if self.parser is None: log.warning( 'Received data before the connection is established: %r', data) return self.parser.feed(data) try: for event, xml in self.parser.read_events(): if event == 'start': if self.xml_depth == 0: # We have received the start of the root element. self.xml_root = xml log.debug( '[33;1mRECV[0m: %s', highlight( tostring(self.xml_root, xmlns=self.default_ns, stream=self, top_level=True, open_only=True))) self.start_stream_handler(self.xml_root) self.xml_depth += 1 if event == 'end': self.xml_depth -= 1 if self.xml_depth == 0: # The stream's root element has closed, # terminating the stream. log.debug("End of stream received") self.abort() elif self.xml_depth == 1: # A stanza is an XML element that is a direct child of # the root element, hence the check of depth == 1 self._spawn_event(xml) if self.xml_root is not None: # Keep the root element empty of children to # save on memory use. self.xml_root.clear() except ET.ParseError: log.error('Parse error: %r', data) # Due to cyclic dependencies, this can’t be imported at the module # level. from slixmpp.stanza.stream_error import StreamError error = StreamError() error['condition'] = 'not-well-formed' error['text'] = 'Server sent: %r' % data self.send(error) self.disconnect()
def __spawn_event(self, xml): """ Analyze incoming XML stanzas and convert them into stanza objects if applicable and queue stream events to be processed by matching handlers. :param xml: The :class:`~slixmpp.xmlstream.stanzabase.ElementBase` stanza to analyze. """ # Apply any preprocessing filters. xml = self.incoming_filter(xml) # Convert the raw XML object into a stanza object. If no registered # stanza type applies, a generic StanzaBase stanza will be used. stanza = self._build_stanza(xml) for filter in self.__filters['in']: if stanza is not None: stanza = filter(stanza) if stanza is None: return log.debug("[33;1mRECV[0m: %s", highlight(stanza)) # Match the stanza against registered handlers. Handlers marked # to run "in stream" will be executed immediately; the rest will # be queued. handled = False matched_handlers = [h for h in self.__handlers if h.match(stanza)] for handler in matched_handlers: handler.prerun(stanza) try: handler.run(stanza) except Exception as e: stanza.exception(e) if handler.check_delete(): self.__handlers.remove(handler) handled = True # Some stanzas require responses, such as Iq queries. A default # handler will be executed immediately for this case. if not handled: stanza.unhandled()