+
+ local function restricted_handler(parser)
+ cb_error(session, "parse-error", "restricted-xml", "Restricted XML, see RFC 6120 section 11.1.");
+ if not parser.stop or not parser:stop() then
+ error("Failed to abort parsing");
+ end
+ end
+
+ if lxp_supports_doctype then
+ xml_handlers.StartDoctypeDecl = restricted_handler;
+ end
+ xml_handlers.Comment = restricted_handler;
+ xml_handlers.ProcessingInstruction = restricted_handler;
+
+ local function reset()
+ stanza, chardata, stanza_size = nil, {}, 0;
+ stack = {};
+ end
+
+ local function set_session(stream, new_session)
+ session = new_session;
+ end
+
+ return xml_handlers, { reset = reset, set_session = set_session };
+end
+
+local function new(session, stream_callbacks, stanza_size_limit)
+ -- Used to track parser progress (e.g. to enforce size limits)
+ local n_outstanding_bytes = 0;
+ local handle_progress;
+ if lxp_supports_bytecount then
+ function handle_progress(n_parsed_bytes)
+ n_outstanding_bytes = n_outstanding_bytes - n_parsed_bytes;
+ end
+ stanza_size_limit = stanza_size_limit or default_stanza_size_limit;
+ elseif stanza_size_limit then
+ error("Stanza size limits are not supported on this version of LuaExpat")
+ end
+
+ local handlers, meta = new_sax_handlers(session, stream_callbacks, handle_progress);
+ local parser = new_parser(handlers, ns_separator, false);
+ local parse = parser.parse;
+
+ function session.open_stream(session, from, to)
+ local send = session.sends2s or session.send;
+
+ local attr = {
+ ["xmlns:stream"] = "http://etherx.jabber.org/streams",
+ ["xml:lang"] = "en",
+ xmlns = stream_callbacks.default_ns,
+ version = session.version and (session.version > 0 and "1.0" or nil),
+ id = session.streamid,
+ from = from or session.host, to = to,
+ };
+ if session.stream_attrs then
+ session:stream_attrs(from, to, attr)
+ end
+ send("<?xml version='1.0'?>");
+ send(st.stanza("stream:stream", attr):top_tag());
+ return true;
+ end
+
+ return {
+ reset = function ()
+ parser = new_parser(handlers, ns_separator, false);
+ parse = parser.parse;
+ n_outstanding_bytes = 0;
+ meta.reset();
+ end,
+ feed = function (self, data)
+ if lxp_supports_bytecount then
+ n_outstanding_bytes = n_outstanding_bytes + #data;
+ end
+ local ok, err = parse(parser, data);
+ if lxp_supports_bytecount and n_outstanding_bytes > stanza_size_limit then
+ return nil, "stanza-too-large";
+ end
+ return ok, err;
+ end,
+ set_session = meta.set_session;
+ };