1 // Copyright 2015 The Weave Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef LIBWEAVE_SRC_NOTIFICATION_XMPP_STREAM_PARSER_H_ 6 #define LIBWEAVE_SRC_NOTIFICATION_XMPP_STREAM_PARSER_H_ 7 8 #include <expat.h> 9 10 #include <map> 11 #include <memory> 12 #include <stack> 13 #include <string> 14 15 #include <base/macros.h> 16 17 namespace weave { 18 19 class XmlNode; 20 21 // A simple XML stream parser. As the XML data is being read from a data source 22 // (for example, a socket), XmppStreamParser::ParseData() should be called. 23 // This method parses the provided XML data chunk and if it finds complete 24 // XML elements, it will call internal OnOpenElement(), OnCloseElement() and 25 // OnCharData() member functions. These will track the element nesting level. 26 // When a top-level element starts, the parser will call Delegate::OnStreamStart 27 // method. Once this happens, every complete XML element (including its children 28 // if they are present) will trigger Delegate::OnStanze() callback. 29 // Finally, when top-level element is closed, Delegate::OnStreamEnd() is called. 30 // This class is specifically tailored to XMPP streams which look like this: 31 // B: <stream:stream to='example.com' xmlns='jabber:client' version='1.0'> 32 // S: <presence><show/></presence> 33 // S: <message to='foo'><body/></message> 34 // S: <iq to='bar'><query/></iq> 35 // S: ... 36 // E: </stream:stream> 37 // Here, "B:" will trigger OnStreamStart(), "S:" will result in OnStanza() and 38 // "E:" will result in OnStreamEnd(). 39 class XmppStreamParser final { 40 public: 41 // Delegate interface that interested parties implement to receive 42 // notifications of stream opening/closing and on new stanzas arriving. 43 class Delegate { 44 public: 45 virtual void OnStreamStart( 46 const std::string& node_name, 47 std::map<std::string, std::string> attributes) = 0; 48 virtual void OnStreamEnd(const std::string& node_name) = 0; 49 virtual void OnStanza(std::unique_ptr<XmlNode> stanza) = 0; 50 51 protected: 52 virtual ~Delegate() {} 53 }; 54 55 explicit XmppStreamParser(Delegate* delegate); 56 ~XmppStreamParser(); 57 58 // Parses additional XML data received from an input stream. 59 void ParseData(const std::string& data); 60 61 // Resets the parser to expect the top-level stream node again. 62 void Reset(); 63 64 private: 65 // Raw expat callbacks. 66 static void HandleElementStart(void* user_data, 67 const XML_Char* element, 68 const XML_Char** attr); 69 static void HandleElementEnd(void* user_data, const XML_Char* element); 70 static void HandleCharData(void* user_data, const char* content, int length); 71 72 // Reinterpreted callbacks from expat with some data pre-processed. 73 void OnOpenElement(const std::string& node_name, 74 std::map<std::string, std::string> attributes); 75 void OnCloseElement(const std::string& node_name); 76 void OnCharData(const std::string& text); 77 78 Delegate* delegate_; 79 XML_Parser parser_{nullptr}; 80 bool started_{false}; 81 std::stack<std::unique_ptr<XmlNode>> node_stack_; 82 83 DISALLOW_COPY_AND_ASSIGN(XmppStreamParser); 84 }; 85 86 } // namespace weave 87 88 #endif // LIBWEAVE_SRC_NOTIFICATION_XMPP_STREAM_PARSER_H_ 89