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 17namespace weave { 18 19class 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(). 39class 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