core/xmlhandlers.lua

changeset 2492
b5e2d1919ec3
parent 2468
68bb1cc1a8b0
child 2493
ec09d16a51e1
equal deleted inserted replaced
2491:4be6810914eb 2492:b5e2d1919ec3
22 local error = error; 22 local error = error;
23 23
24 module "xmlhandlers" 24 module "xmlhandlers"
25 25
26 local ns_prefixes = { 26 local ns_prefixes = {
27 ["http://www.w3.org/XML/1998/namespace"] = "xml"; 27 ["http://www.w3.org/XML/1998/namespace"] = "xml";
28 } 28 };
29 29
30 local xmlns_streams = "http://etherx.jabber.org/streams"; 30 local xmlns_streams = "http://etherx.jabber.org/streams";
31 31
32 local ns_separator = "\1"; 32 local ns_separator = "\1";
33 local ns_pattern = "^([^"..ns_separator.."]*)"..ns_separator.."?(.*)$"; 33 local ns_pattern = "^([^"..ns_separator.."]*)"..ns_separator.."?(.*)$";
34 34
35 function init_xmlhandlers(session, stream_callbacks) 35 function init_xmlhandlers(session, stream_callbacks)
36 local ns_stack = { "" }; 36 local ns_stack = { "" };
37 local curr_tag; 37 local curr_tag;
38 local chardata = {}; 38 local chardata = {};
39 local xml_handlers = {}; 39 local xml_handlers = {};
40 local log = session.log or default_log; 40 local log = session.log or default_log;
41
42 local cb_streamopened = stream_callbacks.streamopened;
43 local cb_streamclosed = stream_callbacks.streamclosed;
44 local cb_error = stream_callbacks.error or function(session, e) error("XML stream error: "..tostring(e)); end;
45 local cb_handlestanza = stream_callbacks.handlestanza;
46
47 local stream_ns = stream_callbacks.stream_ns or xmlns_streams;
48 local stream_tag = stream_ns..ns_separator..(stream_callbacks.stream_tag or "stream");
49 local stream_error_tag = stream_ns..ns_separator..(stream_callbacks.error_tag or "error");
50
51 local stream_default_ns = stream_callbacks.default_ns;
52
53 local stanza;
54 function xml_handlers:StartElement(tagname, attr)
55 if stanza and #chardata > 0 then
56 -- We have some character data in the buffer
57 stanza:text(t_concat(chardata));
58 chardata = {};
59 end
60 local curr_ns,name = tagname:match(ns_pattern);
61 if name == "" then
62 curr_ns, name = "", curr_ns;
63 end
64
65 if curr_ns ~= stream_default_ns then
66 attr.xmlns = curr_ns;
67 end
41 68
42 local cb_streamopened = stream_callbacks.streamopened; 69 -- FIXME !!!!!
43 local cb_streamclosed = stream_callbacks.streamclosed; 70 for i=1,#attr do
44 local cb_error = stream_callbacks.error or function (session, e) error("XML stream error: "..tostring(e)); end; 71 local k = attr[i];
45 local cb_handlestanza = stream_callbacks.handlestanza; 72 attr[i] = nil;
73 local ns, nm = k:match(ns_pattern);
74 if nm ~= "" then
75 ns = ns_prefixes[ns];
76 if ns then
77 attr[ns..":"..nm] = attr[k];
78 attr[k] = nil;
79 end
80 end
81 end
46 82
47 local stream_ns = stream_callbacks.stream_ns or xmlns_streams; 83 if not stanza then --if we are not currently inside a stanza
48 local stream_tag = stream_ns..ns_separator..(stream_callbacks.stream_tag or "stream"); 84 if session.notopen then
49 local stream_error_tag = stream_ns..ns_separator..(stream_callbacks.error_tag or "error"); 85 if tagname == stream_tag then
50 86 if cb_streamopened then
51 local stream_default_ns = stream_callbacks.default_ns; 87 cb_streamopened(session, attr);
52 88 end
53 local stanza 89 else
54 function xml_handlers:StartElement(tagname, attr) 90 -- Garbage before stream?
55 if stanza and #chardata > 0 then 91 cb_error(session, "no-stream");
56 -- We have some character data in the buffer 92 end
57 stanza:text(t_concat(chardata)); 93 return;
58 chardata = {};
59 end 94 end
60 local curr_ns,name = tagname:match(ns_pattern); 95 if curr_ns == "jabber:client" and name ~= "iq" and name ~= "presence" and name ~= "message" then
61 if name == "" then 96 cb_error(session, "invalid-top-level-element");
62 curr_ns, name = "", curr_ns;
63 end 97 end
64 98
99 stanza = st.stanza(name, attr);
100 curr_tag = stanza;
101 else -- we are inside a stanza, so add a tag
102 attr.xmlns = nil;
65 if curr_ns ~= stream_default_ns then 103 if curr_ns ~= stream_default_ns then
66 attr.xmlns = curr_ns; 104 attr.xmlns = curr_ns;
67 end 105 end
68 106 stanza:tag(name, attr);
69 -- FIXME !!!!! 107 end
70 for i=1,#attr do 108 end
71 local k = attr[i]; 109 function xml_handlers:CharacterData(data)
72 attr[i] = nil; 110 if stanza then
73 local ns, nm = k:match(ns_pattern); 111 t_insert(chardata, data);
74 if nm ~= "" then 112 end
75 ns = ns_prefixes[ns]; 113 end
76 if ns then 114 function xml_handlers:EndElement(tagname)
77 attr[ns..":"..nm] = attr[k]; 115 local curr_ns,name = tagname:match(ns_pattern);
78 attr[k] = nil; 116 if name == "" then
79 end 117 curr_ns, name = "", curr_ns;
118 end
119 if not stanza then
120 if tagname == stream_tag then
121 if cb_streamclosed then
122 cb_streamclosed(session);
80 end 123 end
124 else
125 cb_error(session, "parse-error", "unexpected-element-close", name);
81 end 126 end
82 127 stanza, chardata = nil, {};
83 if not stanza then --if we are not currently inside a stanza 128 return;
84 if session.notopen then 129 end
85 if tagname == stream_tag then 130 if #chardata > 0 then
86 if cb_streamopened then 131 -- We have some character data in the buffer
87 cb_streamopened(session, attr); 132 stanza:text(t_concat(chardata));
88 end 133 chardata = {};
89 else 134 end
90 -- Garbage before stream? 135 -- Complete stanza
91 cb_error(session, "no-stream"); 136 if #stanza.last_add == 0 then
92 end 137 if tagname ~= stream_error_tag then
93 return; 138 cb_handlestanza(session, stanza);
94 end 139 else
95 if curr_ns == "jabber:client" and name ~= "iq" and name ~= "presence" and name ~= "message" then 140 cb_error(session, "stream-error", stanza);
96 cb_error(session, "invalid-top-level-element");
97 end
98
99 stanza = st.stanza(name, attr);
100 curr_tag = stanza;
101 else -- we are inside a stanza, so add a tag
102 attr.xmlns = nil;
103 if curr_ns ~= stream_default_ns then
104 attr.xmlns = curr_ns;
105 end
106 stanza:tag(name, attr);
107 end 141 end
142 stanza = nil;
143 else
144 stanza:up();
108 end 145 end
109 function xml_handlers:CharacterData(data) 146 end
110 if stanza then
111 t_insert(chardata, data);
112 end
113 end
114 function xml_handlers:EndElement(tagname)
115 local curr_ns,name = tagname:match(ns_pattern);
116 if name == "" then
117 curr_ns, name = "", curr_ns;
118 end
119 if not stanza then
120 if tagname == stream_tag then
121 if cb_streamclosed then
122 cb_streamclosed(session);
123 end
124 else
125 cb_error(session, "parse-error", "unexpected-element-close", name);
126 end
127 stanza, chardata = nil, {};
128 return;
129 end
130 if #chardata > 0 then
131 -- We have some character data in the buffer
132 stanza:text(t_concat(chardata));
133 chardata = {};
134 end
135 -- Complete stanza
136 if #stanza.last_add == 0 then
137 if tagname ~= stream_error_tag then
138 cb_handlestanza(session, stanza);
139 else
140 cb_error(session, "stream-error", stanza);
141 end
142 stanza = nil;
143 else
144 stanza:up();
145 end
146 end
147 return xml_handlers; 147 return xml_handlers;
148 end 148 end
149 149
150 return init_xmlhandlers; 150 return init_xmlhandlers;

mercurial