/usr/lib/prosody/util/xmppstream.lua is in prosody 0.9.10-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | -- Prosody IM
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
local lxp = require "lxp";
local st = require "util.stanza";
local stanza_mt = st.stanza_mt;
local error = error;
local tostring = tostring;
local t_insert = table.insert;
local t_concat = table.concat;
local t_remove = table.remove;
local setmetatable = setmetatable;
-- COMPAT: w/LuaExpat 1.1.0
local lxp_supports_doctype = pcall(lxp.new, { StartDoctypeDecl = false });
local lxp_supports_xmldecl = pcall(lxp.new, { XmlDecl = false });
local lxp_supports_bytecount = not not lxp.new({}).getcurrentbytecount;
local default_stanza_size_limit = 1024*1024*10; -- 10MB
module "xmppstream"
local new_parser = lxp.new;
local xml_namespace = {
["http://www.w3.org/XML/1998/namespace\1lang"] = "xml:lang";
["http://www.w3.org/XML/1998/namespace\1space"] = "xml:space";
["http://www.w3.org/XML/1998/namespace\1base"] = "xml:base";
["http://www.w3.org/XML/1998/namespace\1id"] = "xml:id";
};
local xmlns_streams = "http://etherx.jabber.org/streams";
local ns_separator = "\1";
local ns_pattern = "^([^"..ns_separator.."]*)"..ns_separator.."?(.*)$";
_M.ns_separator = ns_separator;
_M.ns_pattern = ns_pattern;
local function dummy_cb() end
function new_sax_handlers(session, stream_callbacks, cb_handleprogress)
local xml_handlers = {};
local cb_streamopened = stream_callbacks.streamopened;
local cb_streamclosed = stream_callbacks.streamclosed;
local cb_error = stream_callbacks.error or function(session, e, stanza) error("XML stream error: "..tostring(e)..(stanza and ": "..tostring(stanza) or ""),2); end;
local cb_handlestanza = stream_callbacks.handlestanza;
cb_handleprogress = cb_handleprogress or dummy_cb;
local stream_ns = stream_callbacks.stream_ns or xmlns_streams;
local stream_tag = stream_callbacks.stream_tag or "stream";
if stream_ns ~= "" then
stream_tag = stream_ns..ns_separator..stream_tag;
end
local stream_error_tag = stream_ns..ns_separator..(stream_callbacks.error_tag or "error");
local stream_default_ns = stream_callbacks.default_ns;
local stack = {};
local chardata, stanza = {};
local stanza_size = 0;
local non_streamns_depth = 0;
function xml_handlers:StartElement(tagname, attr)
if stanza and #chardata > 0 then
-- We have some character data in the buffer
t_insert(stanza, t_concat(chardata));
chardata = {};
end
local curr_ns,name = tagname:match(ns_pattern);
if name == "" then
curr_ns, name = "", curr_ns;
end
if curr_ns ~= stream_default_ns or non_streamns_depth > 0 then
attr.xmlns = curr_ns;
non_streamns_depth = non_streamns_depth + 1;
end
for i=1,#attr do
local k = attr[i];
attr[i] = nil;
local xmlk = xml_namespace[k];
if xmlk then
attr[xmlk] = attr[k];
attr[k] = nil;
end
end
if not stanza then --if we are not currently inside a stanza
if lxp_supports_bytecount then
stanza_size = self:getcurrentbytecount();
end
if session.notopen then
if tagname == stream_tag then
non_streamns_depth = 0;
if cb_streamopened then
if lxp_supports_bytecount then
cb_handleprogress(stanza_size);
stanza_size = 0;
end
cb_streamopened(session, attr);
end
else
-- Garbage before stream?
cb_error(session, "no-stream", tagname);
end
return;
end
if curr_ns == "jabber:client" and name ~= "iq" and name ~= "presence" and name ~= "message" then
cb_error(session, "invalid-top-level-element");
end
stanza = setmetatable({ name = name, attr = attr, tags = {} }, stanza_mt);
else -- we are inside a stanza, so add a tag
if lxp_supports_bytecount then
stanza_size = stanza_size + self:getcurrentbytecount();
end
t_insert(stack, stanza);
local oldstanza = stanza;
stanza = setmetatable({ name = name, attr = attr, tags = {} }, stanza_mt);
t_insert(oldstanza, stanza);
t_insert(oldstanza.tags, stanza);
end
end
if lxp_supports_xmldecl then
function xml_handlers:XmlDecl(version, encoding, standalone)
if lxp_supports_bytecount then
cb_handleprogress(self:getcurrentbytecount());
end
end
end
function xml_handlers:StartCdataSection()
if lxp_supports_bytecount then
if stanza then
stanza_size = stanza_size + self:getcurrentbytecount();
else
cb_handleprogress(self:getcurrentbytecount());
end
end
end
function xml_handlers:EndCdataSection()
if lxp_supports_bytecount then
if stanza then
stanza_size = stanza_size + self:getcurrentbytecount();
else
cb_handleprogress(self:getcurrentbytecount());
end
end
end
function xml_handlers:CharacterData(data)
if stanza then
if lxp_supports_bytecount then
stanza_size = stanza_size + self:getcurrentbytecount();
end
t_insert(chardata, data);
elseif lxp_supports_bytecount then
cb_handleprogress(self:getcurrentbytecount());
end
end
function xml_handlers:EndElement(tagname)
if lxp_supports_bytecount then
stanza_size = stanza_size + self:getcurrentbytecount()
end
if non_streamns_depth > 0 then
non_streamns_depth = non_streamns_depth - 1;
end
if stanza then
if #chardata > 0 then
-- We have some character data in the buffer
t_insert(stanza, t_concat(chardata));
chardata = {};
end
-- Complete stanza
if #stack == 0 then
if lxp_supports_bytecount then
cb_handleprogress(stanza_size);
end
stanza_size = 0;
if tagname ~= stream_error_tag then
cb_handlestanza(session, stanza);
else
cb_error(session, "stream-error", stanza);
end
stanza = nil;
else
stanza = t_remove(stack);
end
else
if cb_streamclosed then
cb_streamclosed(session);
end
end
end
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
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;
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;
};
end
return _M;
|