blob: b8f572303481df2536cdd7543e0f3f8de123f2bb [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Alex Vakulenkobf71f702015-05-18 14:30:56 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Vitaly Buka912b6982015-07-06 11:13:03 -07005#ifndef LIBWEAVE_SRC_NOTIFICATION_XMPP_STREAM_PARSER_H_
6#define LIBWEAVE_SRC_NOTIFICATION_XMPP_STREAM_PARSER_H_
Alex Vakulenkobf71f702015-05-18 14:30:56 -07007
8#include <expat.h>
9
10#include <map>
11#include <memory>
12#include <stack>
13#include <string>
14
15#include <base/macros.h>
16
Vitaly Bukab6f015a2015-07-09 14:59:23 -070017namespace weave {
Alex Vakulenkobf71f702015-05-18 14:30:56 -070018
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;
Alex Vakulenko534a3122015-05-22 15:48:53 -070050
51 protected:
Vitaly Buka3bfb13d2015-11-24 14:46:13 -080052 virtual ~Delegate() {}
Alex Vakulenkobf71f702015-05-18 14:30:56 -070053 };
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
Vitaly Bukab6f015a2015-07-09 14:59:23 -070086} // namespace weave
Alex Vakulenkobf71f702015-05-18 14:30:56 -070087
Vitaly Buka912b6982015-07-06 11:13:03 -070088#endif // LIBWEAVE_SRC_NOTIFICATION_XMPP_STREAM_PARSER_H_