Annotate

plugins/mod_websocket.lua @ 9117:a19fdc6e4f09

util.pubsub: Apply defaults metatable before config check (thanks pep.) Makes it so that the callback sees the default if it’s not in the form, which makes it easier to validate.
author Kim Alvefur <zash@zash.se>
date Sun, 05 Aug 2018 15:17:00 +0200
parent 8794:0e2c1c4d4f78
child 9378:a6f54df39624
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
1 -- Prosody IM
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
2 -- Copyright (C) 2012-2014 Florian Zeitz
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
3 --
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
4 -- This project is MIT/X11 licensed. Please see the
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
5 -- COPYING file in the source package for more information.
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
6 --
6894
f7203c7cb7ff mod_websocket: Silence luacheck warnings
Kim Alvefur <zash@zash.se>
parents: 6893
diff changeset
7 -- luacheck: ignore 431/log
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
8
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
9 module:set_global();
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
10
6893
861790282dda mod_websocket: Import util.timer and session close timeout config option (thanks fairuz)
Kim Alvefur <zash@zash.se>
parents: 6793
diff changeset
11 local add_task = require "util.timer".add_task;
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
12 local add_filter = require "util.filters".add_filter;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
13 local sha1 = require "util.hashes".sha1;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
14 local base64 = require "util.encodings".base64.encode;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
15 local st = require "util.stanza";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
16 local parse_xml = require "util.xml".parse;
7761
e0e1f6d6fb4f mod_websocket: Use contains_token from util.http for checking if the requested WebSocket sub-protocols include XMPP
Kim Alvefur <zash@zash.se>
parents: 7760
diff changeset
17 local contains_token = require "util.http".contains_token;
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
18 local portmanager = require "core.portmanager";
6793
2bf1b7e2149a mod_websocket: Import sessionmanager (fixes traceback)
Kim Alvefur <zash@zash.se>
parents: 6397
diff changeset
19 local sm_destroy_session = require"core.sessionmanager".destroy_session;
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
20 local log = module._log;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
21
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
22 local websocket_frames = require"net.websocket.frames";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
23 local parse_frame = websocket_frames.parse;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
24 local build_frame = websocket_frames.build;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
25 local build_close = websocket_frames.build_close;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
26 local parse_close = websocket_frames.parse_close;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
27
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
28 local t_concat = table.concat;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
29
6893
861790282dda mod_websocket: Import util.timer and session close timeout config option (thanks fairuz)
Kim Alvefur <zash@zash.se>
parents: 6793
diff changeset
30 local stream_close_timeout = module:get_option_number("c2s_close_timeout", 5);
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
31 local consider_websocket_secure = module:get_option_boolean("consider_websocket_secure");
7762
2208e6cd0d9f mod_websocket: Verify that the client-sent Origin header matches cross_domain_websocket (fixes #652)
Kim Alvefur <zash@zash.se>
parents: 7761
diff changeset
32 local cross_domain = module:get_option_set("cross_domain_websocket", {});
2208e6cd0d9f mod_websocket: Verify that the client-sent Origin header matches cross_domain_websocket (fixes #652)
Kim Alvefur <zash@zash.se>
parents: 7761
diff changeset
33 if cross_domain:contains("*") or cross_domain:contains(true) then
2208e6cd0d9f mod_websocket: Verify that the client-sent Origin header matches cross_domain_websocket (fixes #652)
Kim Alvefur <zash@zash.se>
parents: 7761
diff changeset
34 cross_domain = true;
2208e6cd0d9f mod_websocket: Verify that the client-sent Origin header matches cross_domain_websocket (fixes #652)
Kim Alvefur <zash@zash.se>
parents: 7761
diff changeset
35 end
2208e6cd0d9f mod_websocket: Verify that the client-sent Origin header matches cross_domain_websocket (fixes #652)
Kim Alvefur <zash@zash.se>
parents: 7761
diff changeset
36
2208e6cd0d9f mod_websocket: Verify that the client-sent Origin header matches cross_domain_websocket (fixes #652)
Kim Alvefur <zash@zash.se>
parents: 7761
diff changeset
37 local function check_origin(origin)
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
38 if cross_domain == true then
7762
2208e6cd0d9f mod_websocket: Verify that the client-sent Origin header matches cross_domain_websocket (fixes #652)
Kim Alvefur <zash@zash.se>
parents: 7761
diff changeset
39 return true;
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
40 end
7762
2208e6cd0d9f mod_websocket: Verify that the client-sent Origin header matches cross_domain_websocket (fixes #652)
Kim Alvefur <zash@zash.se>
parents: 7761
diff changeset
41 return cross_domain:contains(origin);
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
42 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
43
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
44 local xmlns_framing = "urn:ietf:params:xml:ns:xmpp-framing";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
45 local xmlns_streams = "http://etherx.jabber.org/streams";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
46 local xmlns_client = "jabber:client";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
47 local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'};
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
48
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
49 module:depends("c2s")
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
50 local sessions = module:shared("c2s/sessions");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
51 local c2s_listener = portmanager.get_service("c2s").listener;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
52
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
53 --- Session methods
7938
3629f03817f8 mod_websocket: Make open_stream method behave like the one from util.xmppstream
Kim Alvefur <zash@zash.se>
parents: 7937
diff changeset
54 local function session_open_stream(session, from, to)
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
55 local attr = {
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
56 xmlns = xmlns_framing,
7937
5b03a8003659 mod_websocket: Include xml:lang attribute on stream <open> (fixes #840)
Kim Alvefur <zash@zash.se>
parents: 7914
diff changeset
57 ["xml:lang"] = "en",
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
58 version = "1.0",
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
59 id = session.streamid or "",
7938
3629f03817f8 mod_websocket: Make open_stream method behave like the one from util.xmppstream
Kim Alvefur <zash@zash.se>
parents: 7937
diff changeset
60 from = from or session.host, to = to,
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
61 };
7938
3629f03817f8 mod_websocket: Make open_stream method behave like the one from util.xmppstream
Kim Alvefur <zash@zash.se>
parents: 7937
diff changeset
62 if session.stream_attrs then
3629f03817f8 mod_websocket: Make open_stream method behave like the one from util.xmppstream
Kim Alvefur <zash@zash.se>
parents: 7937
diff changeset
63 session:stream_attrs(from, to, attr)
3629f03817f8 mod_websocket: Make open_stream method behave like the one from util.xmppstream
Kim Alvefur <zash@zash.se>
parents: 7937
diff changeset
64 end
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
65 session.send(st.stanza("open", attr));
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
66 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
67
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
68 local function session_close(session, reason)
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
69 local log = session.log or log;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
70 if session.conn then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
71 if session.notopen then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
72 session:open_stream();
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
73 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
74 if reason then -- nil == no err, initiated by us, false == initiated by client
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
75 local stream_error = st.stanza("stream:error");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
76 if type(reason) == "string" then -- assume stream error
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
77 stream_error:tag(reason, {xmlns = 'urn:ietf:params:xml:ns:xmpp-streams' });
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
78 elseif type(reason) == "table" then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
79 if reason.condition then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
80 stream_error:tag(reason.condition, stream_xmlns_attr):up();
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
81 if reason.text then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
82 stream_error:tag("text", stream_xmlns_attr):text(reason.text):up();
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
83 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
84 if reason.extra then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
85 stream_error:add_child(reason.extra);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
86 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
87 elseif reason.name then -- a stanza
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
88 stream_error = reason;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
89 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
90 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
91 log("debug", "Disconnecting client, <stream:error> is: %s", tostring(stream_error));
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
92 session.send(stream_error);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
93 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
94
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
95 session.send(st.stanza("close", { xmlns = xmlns_framing }));
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
96 function session.send() return false; end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
97
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
98 local reason = (reason and (reason.name or reason.text or reason.condition)) or reason;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
99 session.log("debug", "c2s stream for %s closed: %s", session.full_jid or ("<"..session.ip..">"), reason or "session closed");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
100
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
101 -- Authenticated incoming stream may still be sending us stanzas, so wait for </stream:stream> from remote
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
102 local conn = session.conn;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
103 if reason == nil and not session.notopen and session.type == "c2s" then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
104 -- Grace time to process data from authenticated cleanly-closed stream
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
105 add_task(stream_close_timeout, function ()
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
106 if not session.destroyed then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
107 session.log("warn", "Failed to receive a stream close response, closing connection anyway...");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
108 sm_destroy_session(session, reason);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
109 conn:write(build_close(1000, "Stream closed"));
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
110 conn:close();
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
111 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
112 end);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
113 else
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
114 sm_destroy_session(session, reason);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
115 conn:write(build_close(1000, "Stream closed"));
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
116 conn:close();
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
117 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
118 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
119 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
120
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
121
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
122 --- Filters
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
123 local function filter_open_close(data)
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
124 if not data:find(xmlns_framing, 1, true) then return data; end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
125
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
126 local oc = parse_xml(data);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
127 if not oc then return data; end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
128 if oc.attr.xmlns ~= xmlns_framing then return data; end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
129 if oc.name == "close" then return "</stream:stream>"; end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
130 if oc.name == "open" then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
131 oc.name = "stream:stream";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
132 oc.attr.xmlns = nil;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
133 oc.attr["xmlns:stream"] = xmlns_streams;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
134 return oc:top_tag();
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
135 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
136
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
137 return data;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
138 end
6894
f7203c7cb7ff mod_websocket: Silence luacheck warnings
Kim Alvefur <zash@zash.se>
parents: 6893
diff changeset
139 function handle_request(event)
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
140 local request, response = event.request, event.response;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
141 local conn = response.conn;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
142
7914
a6eb3b6bf903 mod_websocket: Set connections starttls method to false to prevent mod_tls from offering starttls (fixes #837)
Kim Alvefur <zash@zash.se>
parents: 7764
diff changeset
143 conn.starttls = false; -- Prevent mod_tls from believing starttls can be done
a6eb3b6bf903 mod_websocket: Set connections starttls method to false to prevent mod_tls from offering starttls (fixes #837)
Kim Alvefur <zash@zash.se>
parents: 7764
diff changeset
144
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
145 if not request.headers.sec_websocket_key then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
146 response.headers.content_type = "text/html";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
147 return [[<!DOCTYPE html><html><head><title>Websocket</title></head><body>
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
148 <p>It works! Now point your WebSocket client to this URL to connect to Prosody.</p>
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
149 </body></html>]];
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
150 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
151
7761
e0e1f6d6fb4f mod_websocket: Use contains_token from util.http for checking if the requested WebSocket sub-protocols include XMPP
Kim Alvefur <zash@zash.se>
parents: 7760
diff changeset
152 local wants_xmpp = contains_token(request.headers.sec_websocket_protocol or "", "xmpp");
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
153
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
154 if not wants_xmpp then
7760
801d4c8e0f58 mod_websocket: Add some debug messages
Kim Alvefur <zash@zash.se>
parents: 7716
diff changeset
155 module:log("debug", "Client didn't want to talk XMPP, list of protocols was %s", request.headers.sec_websocket_protocol or "(empty)");
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
156 return 501;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
157 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
158
7762
2208e6cd0d9f mod_websocket: Verify that the client-sent Origin header matches cross_domain_websocket (fixes #652)
Kim Alvefur <zash@zash.se>
parents: 7761
diff changeset
159 if not check_origin(request.headers.origin or "") then
2208e6cd0d9f mod_websocket: Verify that the client-sent Origin header matches cross_domain_websocket (fixes #652)
Kim Alvefur <zash@zash.se>
parents: 7761
diff changeset
160 module:log("debug", "Origin %s is not allowed by 'cross_domain_websocket'", request.headers.origin or "(missing header)");
2208e6cd0d9f mod_websocket: Verify that the client-sent Origin header matches cross_domain_websocket (fixes #652)
Kim Alvefur <zash@zash.se>
parents: 7761
diff changeset
161 return 403;
2208e6cd0d9f mod_websocket: Verify that the client-sent Origin header matches cross_domain_websocket (fixes #652)
Kim Alvefur <zash@zash.se>
parents: 7761
diff changeset
162 end
2208e6cd0d9f mod_websocket: Verify that the client-sent Origin header matches cross_domain_websocket (fixes #652)
Kim Alvefur <zash@zash.se>
parents: 7761
diff changeset
163
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
164 local function websocket_close(code, message)
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
165 conn:write(build_close(code, message));
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
166 conn:close();
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
167 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
168
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
169 local dataBuffer;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
170 local function handle_frame(frame)
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
171 local opcode = frame.opcode;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
172 local length = frame.length;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
173 module:log("debug", "Websocket received frame: opcode=%0x, %i bytes", frame.opcode, #frame.data);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
174
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
175 -- Error cases
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
176 if frame.RSV1 or frame.RSV2 or frame.RSV3 then -- Reserved bits non zero
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
177 websocket_close(1002, "Reserved bits not zero");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
178 return false;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
179 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
180
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
181 if opcode == 0x8 then -- close frame
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
182 if length == 1 then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
183 websocket_close(1002, "Close frame with payload, but too short for status code");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
184 return false;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
185 elseif length >= 2 then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
186 local status_code = parse_close(frame.data)
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
187 if status_code < 1000 then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
188 websocket_close(1002, "Closed with invalid status code");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
189 return false;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
190 elseif ((status_code > 1003 and status_code < 1007) or status_code > 1011) and status_code < 3000 then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
191 websocket_close(1002, "Closed with reserved status code");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
192 return false;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
193 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
194 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
195 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
196
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
197 if opcode >= 0x8 then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
198 if length > 125 then -- Control frame with too much payload
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
199 websocket_close(1002, "Payload too large");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
200 return false;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
201 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
202
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
203 if not frame.FIN then -- Fragmented control frame
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
204 websocket_close(1002, "Fragmented control frame");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
205 return false;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
206 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
207 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
208
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
209 if (opcode > 0x2 and opcode < 0x8) or (opcode > 0xA) then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
210 websocket_close(1002, "Reserved opcode");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
211 return false;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
212 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
213
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
214 if opcode == 0x0 and not dataBuffer then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
215 websocket_close(1002, "Unexpected continuation frame");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
216 return false;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
217 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
218
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
219 if (opcode == 0x1 or opcode == 0x2) and dataBuffer then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
220 websocket_close(1002, "Continuation frame expected");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
221 return false;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
222 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
223
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
224 -- Valid cases
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
225 if opcode == 0x0 then -- Continuation frame
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
226 dataBuffer[#dataBuffer+1] = frame.data;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
227 elseif opcode == 0x1 then -- Text frame
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
228 dataBuffer = {frame.data};
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
229 elseif opcode == 0x2 then -- Binary frame
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
230 websocket_close(1003, "Only text frames are supported");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
231 return;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
232 elseif opcode == 0x8 then -- Close request
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
233 websocket_close(1000, "Goodbye");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
234 return;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
235 elseif opcode == 0x9 then -- Ping frame
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
236 frame.opcode = 0xA;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
237 conn:write(build_frame(frame));
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
238 return "";
7314
e327e5b592f5 mod_websocket: Remove warning about unsolicited pong frames "MAY be sent unsolicited" per RFC 6455 (thanks mt)
Kim Alvefur <zash@zash.se>
parents: 7294
diff changeset
239 elseif opcode == 0xA then -- Pong frame, MAY be sent unsolicited, eg as keepalive
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
240 return "";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
241 else
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
242 log("warn", "Received frame with unsupported opcode %i", opcode);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
243 return "";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
244 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
245
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
246 if frame.FIN then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
247 local data = t_concat(dataBuffer, "");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
248 dataBuffer = nil;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
249 return data;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
250 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
251 return "";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
252 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
253
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
254 conn:setlistener(c2s_listener);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
255 c2s_listener.onconnect(conn);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
256
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
257 local session = sessions[conn];
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
258
8595
d3bbff01df9d mod_websocket: Transfer IP address derived by mod_http
Kim Alvefur <zash@zash.se>
parents: 8145
diff changeset
259 -- Use upstream IP if a HTTP proxy was used
d3bbff01df9d mod_websocket: Transfer IP address derived by mod_http
Kim Alvefur <zash@zash.se>
parents: 8145
diff changeset
260 -- See mod_http and #540
d3bbff01df9d mod_websocket: Transfer IP address derived by mod_http
Kim Alvefur <zash@zash.se>
parents: 8145
diff changeset
261 session.ip = request.ip;
d3bbff01df9d mod_websocket: Transfer IP address derived by mod_http
Kim Alvefur <zash@zash.se>
parents: 8145
diff changeset
262
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
263 session.secure = consider_websocket_secure or session.secure;
8789
4ae8dd415e94 mod_websocket: Store the request object on the session for use by other modules
Matthew Wild <mwild1@gmail.com>
parents: 8145
diff changeset
264 session.websocket_request = request;
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
265
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
266 session.open_stream = session_open_stream;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
267 session.close = session_close;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
268
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
269 local frameBuffer = "";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
270 add_filter(session, "bytes/in", function(data)
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
271 local cache = {};
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
272 frameBuffer = frameBuffer .. data;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
273 local frame, length = parse_frame(frameBuffer);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
274
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
275 while frame do
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
276 frameBuffer = frameBuffer:sub(length + 1);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
277 local result = handle_frame(frame);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
278 if not result then return; end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
279 cache[#cache+1] = filter_open_close(result);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
280 frame, length = parse_frame(frameBuffer);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
281 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
282 return t_concat(cache, "");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
283 end);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
284
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
285 add_filter(session, "stanzas/out", function(stanza)
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
286 local attr = stanza.attr;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
287 attr.xmlns = attr.xmlns or xmlns_client;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
288 if stanza.name:find("^stream:") then
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
289 attr["xmlns:stream"] = attr["xmlns:stream"] or xmlns_streams;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
290 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
291 return stanza;
7294
5f4d0753c818 mod_websocket: Make sure stanza xmlns filter runs late in the chain
Kim Alvefur <zash@zash.se>
parents: 6894
diff changeset
292 end, -1000);
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
293
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
294 add_filter(session, "bytes/out", function(data)
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
295 return build_frame({ FIN = true, opcode = 0x01, data = tostring(data)});
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
296 end);
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
297
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
298 response.status_code = 101;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
299 response.headers.upgrade = "websocket";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
300 response.headers.connection = "Upgrade";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
301 response.headers.sec_webSocket_accept = base64(sha1(request.headers.sec_websocket_key .. "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
302 response.headers.sec_webSocket_protocol = "xmpp";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
303
7760
801d4c8e0f58 mod_websocket: Add some debug messages
Kim Alvefur <zash@zash.se>
parents: 7716
diff changeset
304 session.log("debug", "Sending WebSocket handshake");
801d4c8e0f58 mod_websocket: Add some debug messages
Kim Alvefur <zash@zash.se>
parents: 7716
diff changeset
305
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
306 return "";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
307 end
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
308
7315
4fd984d1e445 mod_websocket: Send a ping on read timeout
Kim Alvefur <zash@zash.se>
parents: 7314
diff changeset
309 local function keepalive(event)
7340
7dea28dafc49 mod_websocket: Fix read timeout handler (thanks mt)
Kim Alvefur <zash@zash.se>
parents: 7315
diff changeset
310 local session = event.session;
7dea28dafc49 mod_websocket: Fix read timeout handler (thanks mt)
Kim Alvefur <zash@zash.se>
parents: 7315
diff changeset
311 if session.open_stream == session_open_stream then
7716
779a9ef6b4fd mod_websocket: Set FIN flag on ping frames (fixes #773)
Kim Alvefur <zash@zash.se>
parents: 7340
diff changeset
312 return session.conn:write(build_frame({ opcode = 0x9, FIN = true }));
7340
7dea28dafc49 mod_websocket: Fix read timeout handler (thanks mt)
Kim Alvefur <zash@zash.se>
parents: 7315
diff changeset
313 end
7315
4fd984d1e445 mod_websocket: Send a ping on read timeout
Kim Alvefur <zash@zash.se>
parents: 7314
diff changeset
314 end
4fd984d1e445 mod_websocket: Send a ping on read timeout
Kim Alvefur <zash@zash.se>
parents: 7314
diff changeset
315
4fd984d1e445 mod_websocket: Send a ping on read timeout
Kim Alvefur <zash@zash.se>
parents: 7314
diff changeset
316 module:hook("c2s-read-timeout", keepalive, -0.9);
4fd984d1e445 mod_websocket: Send a ping on read timeout
Kim Alvefur <zash@zash.se>
parents: 7314
diff changeset
317
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
318 function module.add_host(module)
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
319 module:depends("http");
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
320 module:provides("http", {
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
321 name = "websocket";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
322 default_path = "xmpp-websocket";
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
323 route = {
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
324 ["GET"] = handle_request;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
325 ["GET /"] = handle_request;
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
326 };
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
327 });
7315
4fd984d1e445 mod_websocket: Send a ping on read timeout
Kim Alvefur <zash@zash.se>
parents: 7314
diff changeset
328 module:hook("c2s-read-timeout", keepalive, -0.9);
7763
c5ce14539fc4 mod_websocket: Add the base URL of each host module is enabled on to 'cross_domain_websocket'
Kim Alvefur <zash@zash.se>
parents: 7762
diff changeset
329
c5ce14539fc4 mod_websocket: Add the base URL of each host module is enabled on to 'cross_domain_websocket'
Kim Alvefur <zash@zash.se>
parents: 7762
diff changeset
330 if cross_domain ~= true then
c5ce14539fc4 mod_websocket: Add the base URL of each host module is enabled on to 'cross_domain_websocket'
Kim Alvefur <zash@zash.se>
parents: 7762
diff changeset
331 local url = require "socket.url";
c5ce14539fc4 mod_websocket: Add the base URL of each host module is enabled on to 'cross_domain_websocket'
Kim Alvefur <zash@zash.se>
parents: 7762
diff changeset
332 local ws_url = module:http_url("websocket", "xmpp-websocket");
c5ce14539fc4 mod_websocket: Add the base URL of each host module is enabled on to 'cross_domain_websocket'
Kim Alvefur <zash@zash.se>
parents: 7762
diff changeset
333 local url_components = url.parse(ws_url);
c5ce14539fc4 mod_websocket: Add the base URL of each host module is enabled on to 'cross_domain_websocket'
Kim Alvefur <zash@zash.se>
parents: 7762
diff changeset
334 -- The 'Origin' consists of the base URL without path
c5ce14539fc4 mod_websocket: Add the base URL of each host module is enabled on to 'cross_domain_websocket'
Kim Alvefur <zash@zash.se>
parents: 7762
diff changeset
335 url_components.path = nil;
c5ce14539fc4 mod_websocket: Add the base URL of each host module is enabled on to 'cross_domain_websocket'
Kim Alvefur <zash@zash.se>
parents: 7762
diff changeset
336 local this_origin = url.build(url_components);
7764
d6b96e42e8e6 mod_websocket: Allow per-host cross_domain_websocket, defaulting to the base URL of the current host
Kim Alvefur <zash@zash.se>
parents: 7763
diff changeset
337 local local_cross_domain = module:get_option_set("cross_domain_websocket", { this_origin });
d6b96e42e8e6 mod_websocket: Allow per-host cross_domain_websocket, defaulting to the base URL of the current host
Kim Alvefur <zash@zash.se>
parents: 7763
diff changeset
338 -- Don't add / remove something added by another host
d6b96e42e8e6 mod_websocket: Allow per-host cross_domain_websocket, defaulting to the base URL of the current host
Kim Alvefur <zash@zash.se>
parents: 7763
diff changeset
339 -- This might be weird with random load order
d6b96e42e8e6 mod_websocket: Allow per-host cross_domain_websocket, defaulting to the base URL of the current host
Kim Alvefur <zash@zash.se>
parents: 7763
diff changeset
340 local_cross_domain:exclude(cross_domain);
d6b96e42e8e6 mod_websocket: Allow per-host cross_domain_websocket, defaulting to the base URL of the current host
Kim Alvefur <zash@zash.se>
parents: 7763
diff changeset
341 cross_domain:include(local_cross_domain);
8145
4d0f5ea19851 mod_websocket: Convert set to string (syslog sink needs a better fix)
Kim Alvefur <zash@zash.se>
parents: 8052
diff changeset
342 module:log("debug", "cross_domain = %s", tostring(cross_domain));
7763
c5ce14539fc4 mod_websocket: Add the base URL of each host module is enabled on to 'cross_domain_websocket'
Kim Alvefur <zash@zash.se>
parents: 7762
diff changeset
343 function module.unload()
7764
d6b96e42e8e6 mod_websocket: Allow per-host cross_domain_websocket, defaulting to the base URL of the current host
Kim Alvefur <zash@zash.se>
parents: 7763
diff changeset
344 cross_domain:exclude(local_cross_domain);
7763
c5ce14539fc4 mod_websocket: Add the base URL of each host module is enabled on to 'cross_domain_websocket'
Kim Alvefur <zash@zash.se>
parents: 7762
diff changeset
345 end
c5ce14539fc4 mod_websocket: Add the base URL of each host module is enabled on to 'cross_domain_websocket'
Kim Alvefur <zash@zash.se>
parents: 7762
diff changeset
346 end
6397
6f75f8043936 mod_websocket: Initial commit (based on the prosody-modules version)
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
347 end