Software /
code /
prosody
Comparison
plugins/mod_websocket.lua @ 11120:b2331f3dfeea
Merge 0.11->trunk
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Wed, 30 Sep 2020 09:50:33 +0100 |
parent | 11114:6a608ecb3471 |
child | 11384:f9edf26c66fc |
comparison
equal
deleted
inserted
replaced
11119:68df52bf08d5 | 11120:b2331f3dfeea |
---|---|
31 local stanza_size_limit = module:get_option_number("c2s_stanza_size_limit", 10 * 1024 * 1024); | 31 local stanza_size_limit = module:get_option_number("c2s_stanza_size_limit", 10 * 1024 * 1024); |
32 local frame_buffer_limit = module:get_option_number("websocket_frame_buffer_limit", 2 * stanza_size_limit); | 32 local frame_buffer_limit = module:get_option_number("websocket_frame_buffer_limit", 2 * stanza_size_limit); |
33 local frame_fragment_limit = module:get_option_number("websocket_frame_fragment_limit", 8); | 33 local frame_fragment_limit = module:get_option_number("websocket_frame_fragment_limit", 8); |
34 local stream_close_timeout = module:get_option_number("c2s_close_timeout", 5); | 34 local stream_close_timeout = module:get_option_number("c2s_close_timeout", 5); |
35 local consider_websocket_secure = module:get_option_boolean("consider_websocket_secure"); | 35 local consider_websocket_secure = module:get_option_boolean("consider_websocket_secure"); |
36 local cross_domain = module:get_option_set("cross_domain_websocket", {}); | 36 local cross_domain = module:get_option("cross_domain_websocket"); |
37 if cross_domain:contains("*") or cross_domain:contains(true) then | 37 if cross_domain ~= nil then |
38 cross_domain = true; | 38 module:log("info", "The 'cross_domain_websocket' option has been deprecated"); |
39 end | 39 end |
40 | |
41 local function check_origin(origin) | |
42 if cross_domain == true then | |
43 return true; | |
44 end | |
45 return cross_domain:contains(origin); | |
46 end | |
47 | |
48 local xmlns_framing = "urn:ietf:params:xml:ns:xmpp-framing"; | 40 local xmlns_framing = "urn:ietf:params:xml:ns:xmpp-framing"; |
49 local xmlns_streams = "http://etherx.jabber.org/streams"; | 41 local xmlns_streams = "http://etherx.jabber.org/streams"; |
50 local xmlns_client = "jabber:client"; | 42 local xmlns_client = "jabber:client"; |
51 local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'}; | 43 local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'}; |
52 | 44 |
90 end | 82 end |
91 elseif reason.name then -- a stanza | 83 elseif reason.name then -- a stanza |
92 stream_error = reason; | 84 stream_error = reason; |
93 end | 85 end |
94 end | 86 end |
95 log("debug", "Disconnecting client, <stream:error> is: %s", tostring(stream_error)); | 87 log("debug", "Disconnecting client, <stream:error> is: %s", stream_error); |
96 session.send(stream_error); | 88 session.send(stream_error); |
97 end | 89 end |
98 | 90 |
99 session.send(st.stanza("close", { xmlns = xmlns_framing })); | 91 session.send(st.stanza("close", { xmlns = xmlns_framing })); |
100 function session.send() return false; end | 92 function session.send() return false; end |
141 end | 133 end |
142 | 134 |
143 return data; | 135 return data; |
144 end | 136 end |
145 | 137 |
138 local default_get_response_body = [[<!DOCTYPE html><html><head><title>Websocket</title></head><body> | |
139 <p>It works! Now point your WebSocket client to this URL to connect to Prosody.</p> | |
140 </body></html>]] | |
141 local websocket_get_response_body = module:get_option_string("websocket_get_response_body", default_get_response_body) | |
142 | |
146 local function validate_frame(frame, max_length) | 143 local function validate_frame(frame, max_length) |
147 local opcode, length = frame.opcode, frame.length; | 144 local opcode, length = frame.opcode, frame.length; |
148 | 145 |
149 if max_length and length > max_length then | 146 if max_length and length > max_length then |
150 return false, 1009, "Payload too large"; | 147 return false, 1009, "Payload too large"; |
205 local request, response = event.request, event.response; | 202 local request, response = event.request, event.response; |
206 local conn = response.conn; | 203 local conn = response.conn; |
207 | 204 |
208 conn.starttls = false; -- Prevent mod_tls from believing starttls can be done | 205 conn.starttls = false; -- Prevent mod_tls from believing starttls can be done |
209 | 206 |
210 if not request.headers.sec_websocket_key then | 207 if not request.headers.sec_websocket_key or request.method ~= "GET" then |
211 response.headers.content_type = "text/html"; | 208 response.headers.content_type = "text/html"; |
212 return [[<!DOCTYPE html><html><head><title>Websocket</title></head><body> | 209 return websocket_get_response_body; |
213 <p>It works! Now point your WebSocket client to this URL to connect to Prosody.</p> | |
214 </body></html>]]; | |
215 end | 210 end |
216 | 211 |
217 local wants_xmpp = contains_token(request.headers.sec_websocket_protocol or "", "xmpp"); | 212 local wants_xmpp = contains_token(request.headers.sec_websocket_protocol or "", "xmpp"); |
218 | 213 |
219 if not wants_xmpp then | 214 if not wants_xmpp then |
220 module:log("debug", "Client didn't want to talk XMPP, list of protocols was %s", request.headers.sec_websocket_protocol or "(empty)"); | 215 module:log("debug", "Client didn't want to talk XMPP, list of protocols was %s", request.headers.sec_websocket_protocol or "(empty)"); |
221 return 501; | 216 return 501; |
222 end | |
223 | |
224 if not check_origin(request.headers.origin or "") then | |
225 module:log("debug", "Origin %s is not allowed by 'cross_domain_websocket' [ %s ]", request.headers.origin or "(missing header)", cross_domain); | |
226 return 403; | |
227 end | 217 end |
228 | 218 |
229 local function websocket_close(code, message) | 219 local function websocket_close(code, message) |
230 conn:write(build_close(code, message)); | 220 conn:write(build_close(code, message)); |
231 conn:close(); | 221 conn:close(); |
362 }; | 352 }; |
363 }); | 353 }); |
364 | 354 |
365 function module.add_host(module) | 355 function module.add_host(module) |
366 module:hook("c2s-read-timeout", keepalive, -0.9); | 356 module:hook("c2s-read-timeout", keepalive, -0.9); |
367 | 357 end |
368 if cross_domain ~= true then | |
369 local url = require "socket.url"; | |
370 local ws_url = module:http_url("websocket", "xmpp-websocket"); | |
371 local url_components = url.parse(ws_url); | |
372 -- The 'Origin' consists of the base URL without path | |
373 url_components.path = nil; | |
374 local this_origin = url.build(url_components); | |
375 local local_cross_domain = module:get_option_set("cross_domain_websocket", { this_origin }); | |
376 if local_cross_domain:contains(true) then | |
377 module:log("error", "cross_domain_websocket = true only works in the global section"); | |
378 return; | |
379 end | |
380 | |
381 -- Don't add / remove something added by another host | |
382 -- This might be weird with random load order | |
383 local_cross_domain:exclude(cross_domain); | |
384 cross_domain:include(local_cross_domain); | |
385 module:log("debug", "cross_domain = %s", tostring(cross_domain)); | |
386 function module.unload() | |
387 cross_domain:exclude(local_cross_domain); | |
388 end | |
389 end | |
390 end |