X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;ds=sidebyside;f=plugins%2Fmod_bosh.lua;h=6acdc23cb749345b1d1bb4d558a0ab6dc84b8512;hb=05120c2431c0341a1d8426d5305206cd40f51815;hp=9e8354fec893ae7711806f1b6e1044006c34f75c;hpb=4a1c84c361e42ab8b1530e3e7427bf78d2384a2b;p=prosody.git diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index 9e8354fe..6acdc23c 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -22,7 +22,6 @@ local initialize_filters = require "util.filters".initialize; local math_min = math.min; local xpcall, tostring, type = xpcall, tostring, type; local traceback = debug.traceback; -local runner = require"util.async".runner; local xmlns_streams = "http://etherx.jabber.org/streams"; local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; @@ -128,9 +127,12 @@ function handle_POST(event) -- In particular, the streamopened() stream callback is where -- much of the session logic happens, because it's where we first -- get to see the 'sid' of this request. - if not stream:feed(body) then - module:log("warn", "Error parsing BOSH payload") - return 400; + local ok, err = stream:feed(body); + if not ok then + module:log("warn", "Error parsing BOSH payload; %s", err) + local close_reply = st.stanza("body", { xmlns = xmlns_bosh, type = "terminate", + ["xmlns:stream"] = xmlns_streams, condition = "bad-request" }); + return tostring(close_reply); end -- Stanzas (if any) in the request have now been processed, and @@ -140,8 +142,14 @@ function handle_POST(event) if session then -- Session was marked as inactive, since we have -- a request open now, unmark it - if inactive_sessions[session] and #session.requests > 0 then - inactive_sessions[session] = nil; + if session.inactive_timer and #session.requests > 0 then + session.inactive_timer:stop(); + session.inactive_timer = nil; + end + + if session.bosh_wait_timer then + session.bosh_wait_timer:stop(); + session.bosh_wait_timer = nil; end local r = session.requests; @@ -170,7 +178,7 @@ function handle_POST(event) -- We're keeping this request open, to respond later log("debug", "Have nothing to say, so leaving request unanswered for now"); if session.bosh_wait then - waiting_requests[response] = os_time() + session.bosh_wait; + session.bosh_wait_timer = module:add_timer(session.bosh_wait, after_bosh_wait, request, session) end end @@ -181,11 +189,20 @@ function handle_POST(event) else return true; -- Inform http server we shall reply later end + elseif response.finished then + return; -- A response has been sent already end module:log("warn", "Unable to associate request with a session (incomplete request?)"); - return 400; + local close_reply = st.stanza("body", { xmlns = xmlns_bosh, type = "terminate", + ["xmlns:stream"] = xmlns_streams, condition = "item-not-found" }); + return tostring(close_reply) .. "\n"; end +function after_bosh_wait(now, request, session) + if request.conn then + session.send(""); + end +end local function bosh_reset_stream(session) session.notopen = true; end @@ -225,7 +242,6 @@ local function bosh_close_stream(session, reason) held_request:send(response_body); end sessions[session.sid] = nil; - inactive_sessions[session] = nil; sm_destroy_session(session); end @@ -240,8 +256,16 @@ function stream_callbacks.streamopened(context, attr) -- New session request context.notopen = nil; -- Signals that we accept this opening tag - -- TODO: Sanity checks here (rid, to, known host, etc.) - if not hosts[attr.to] then + local to_host = nameprep(attr.to); + local rid = tonumber(attr.rid); + local wait = tonumber(attr.wait); + if not to_host then + log("debug", "BOSH client tried to connect to invalid host: %s", tostring(attr.to)); + local close_reply = st.stanza("body", { xmlns = xmlns_bosh, type = "terminate", + ["xmlns:stream"] = xmlns_streams, condition = "improper-addressing" }); + response:send(tostring(close_reply)); + return; + elseif not hosts[to_host] then -- Unknown host log("debug", "BOSH client tried to connect to unknown host: %s", tostring(attr.to)); local close_reply = st.stanza("body", { xmlns = xmlns_bosh, type = "terminate", @@ -249,12 +273,22 @@ function stream_callbacks.streamopened(context, attr) response:send(tostring(close_reply)); return; end + if not rid or (not wait and attr.wait or wait < 0 or wait % 1 ~= 0) then + log("debug", "BOSH client sent invalid rid or wait attributes: rid=%s, wait=%s", tostring(attr.rid), tostring(attr.wait)); + local close_reply = st.stanza("body", { xmlns = xmlns_bosh, type = "terminate", + ["xmlns:stream"] = xmlns_streams, condition = "bad-request" }); + response:send(tostring(close_reply)); + return; + end + + rid = rid - 1; + wait = math_min(wait, bosh_max_wait); -- New session sid = new_uuid(); local session = { - type = "c2s_unauthed", conn = {}, sid = sid, rid = tonumber(attr.rid)-1, host = attr.to, - bosh_version = attr.ver, bosh_wait = math_min(attr.wait, bosh_max_wait), streamid = sid, + type = "c2s_unauthed", conn = {}, sid = sid, rid = rid-1, host = attr.to, + bosh_version = attr.ver, bosh_wait = wait, streamid = sid, bosh_hold = BOSH_DEFAULT_HOLD, bosh_max_inactive = BOSH_DEFAULT_INACTIVITY, requests = { }, send_buffer = {}, reset_stream = bosh_reset_stream, close = bosh_close_stream, dispatch_stanza = core_process_stanza, notopen = true, @@ -272,6 +306,8 @@ function stream_callbacks.streamopened(context, attr) session.log("debug", "BOSH session created for request from %s", session.ip); log("info", "New BOSH session, assigned it sid '%s'", sid); + hosts[session.host].events.fire_event("bosh-session", { session = session, request = request }); + -- Send creation response local creating_session = true; @@ -284,6 +320,7 @@ function stream_callbacks.streamopened(context, attr) end s = filter("stanzas/out", s); --log("debug", "Sending BOSH data: %s", tostring(s)); + if not s then return true end t_insert(session.send_buffer, tostring(s)); local oldest_request = r[1]; @@ -394,8 +431,9 @@ function stream_callbacks.error(context, error) log("debug", "Error parsing BOSH request payload; %s", error); if not context.sid then local response = context.response; - response.status_code = 400; - response:send(); + local close_reply = st.stanza("body", { xmlns = xmlns_bosh, type = "terminate", + ["xmlns:stream"] = xmlns_streams, condition = "bad-request" }); + response:send(tostring(close_reply)); return; end @@ -407,51 +445,13 @@ function stream_callbacks.error(context, error) end end -local dead_sessions = module:shared("dead_sessions"); -function on_timer() - -- log("debug", "Checking for requests soon to timeout..."); - -- Identify requests timing out within the next few seconds - local now = os_time() + 3; - for request, reply_before in pairs(waiting_requests) do - if reply_before <= now then - log("debug", "%s was soon to timeout (at %d, now %d), sending empty response", tostring(request), reply_before, now); - -- Send empty response to let the - -- client know we're still here - if request.conn then - sessions[request.context.sid].send(""); - end - end - end - - now = now - 3; - local n_dead_sessions = 0; - for session, close_after in pairs(inactive_sessions) do - if close_after < now then - (session.log or log)("debug", "BOSH client inactive too long, destroying session at %d", now); - sessions[session.sid] = nil; - inactive_sessions[session] = nil; - n_dead_sessions = n_dead_sessions + 1; - dead_sessions[n_dead_sessions] = session; - end - end - - for i=1,n_dead_sessions do - local session = dead_sessions[i]; - dead_sessions[i] = nil; - sm_destroy_session(session, "BOSH client silent for over "..session.bosh_max_inactive.." seconds"); - end - return 1; -end -module:add_timer(1, on_timer); - - local GET_response = { headers = { content_type = "text/html"; }; body = [[

It works! Now point your BOSH client to this URL to connect to Prosody.

-

For more information see Prosody: Setting up BOSH.

+

For more information see Prosody: Setting up BOSH.

]]; };