Annotate

mod_websocket/mod_websocket.lua @ 737:e4ea03b060ed

mod_archive: switch from/to The XEP-0136 is not very explicit about the meening of <from> and <to> elements, but the examples are clear: <from> means it comes from the user in the 'with' attribute of the collection. That is the opposite of what is currently implemented in that module. So for better compatibility with complient clients, this switch the 'from' and 'to' fields
author Olivier Goffart <ogoffart@woboq.com>
date Wed, 04 Jul 2012 14:08:43 +0200
parent 694:02fcb102b9aa
child 839:d297d76010d4
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
1 -- Prosody IM
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
2 -- Copyright (C) 2008-2010 Matthew Wild
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
3 -- Copyright (C) 2008-2010 Waqas Hussain
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
4 -- Copyright (C) 2012 Florian Zeitz
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
5 --
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
6 -- This project is MIT/X11 licensed. Please see the
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
7 -- COPYING file in the source package for more information.
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
8 --
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
9
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
10 module:set_global();
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
11
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
12 local add_task = require "util.timer".add_task;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
13 local new_xmpp_stream = require "util.xmppstream".new;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
14 local nameprep = require "util.encodings".stringprep.nameprep;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
15 local sessionmanager = require "core.sessionmanager";
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
16 local st = require "util.stanza";
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
17 local sm_new_session, sm_destroy_session = sessionmanager.new_session, sessionmanager.destroy_session;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
18 local uuid_generate = require "util.uuid".generate;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
19 local sha1 = require "util.hashes".sha1;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
20 local base64 = require "util.encodings".base64.encode;
677
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
21 local band = require "bit".band;
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
22 local bxor = require "bit".bxor;
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
23
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
24 local xpcall, tostring, type = xpcall, tostring, type;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
25 local traceback = debug.traceback;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
26
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
27 local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams";
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
28
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
29 local log = module._log;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
30
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
31 local c2s_timeout = module:get_option_number("c2s_timeout");
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
32 local opt_keepalives = module:get_option_boolean("tcp_keepalives", false);
692
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
33 local self_closing_stream = module:get_option_boolean("websocket_self_closing_stream", true);
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
34
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
35 local sessions = module:shared("sessions");
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
36
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
37 local stream_callbacks = { default_ns = "jabber:client", handlestanza = core_process_stanza };
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
38 local listener = {};
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
39
677
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
40 -- Websocket helpers
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
41 local function parse_frame(frame)
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
42 local result = {};
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
43 local pos = 1;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
44 local length_bytes = 0;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
45 local counter = 0;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
46 local tmp_byte;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
47
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
48 tmp_byte = string.byte(frame, pos);
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
49 result.FIN = band(tmp_byte, 0x80) > 0;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
50 result.RSV1 = band(tmp_byte, 0x40) > 0;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
51 result.RSV2 = band(tmp_byte, 0x20) > 0;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
52 result.RSV3 = band(tmp_byte, 0x10) > 0;
690
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
53 result.opcode = band(tmp_byte, 0x0F);
677
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
54
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
55 pos = pos + 1;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
56 tmp_byte = string.byte(frame, pos);
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
57 result.MASK = band(tmp_byte, 0x80) > 0;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
58 result.length = band(tmp_byte, 0x7F);
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
59
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
60 if result.length == 126 then
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
61 length_bytes = 2;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
62 result.length = 0;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
63 elseif result.length == 127 then
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
64 length_bytes = 8;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
65 result.length = 0;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
66 end
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
67
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
68 for i = 1, length_bytes do
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
69 pos = pos + 1;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
70 result.length = result.length * 255 + string.byte(frame, pos);
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
71 end
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
72
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
73 if result.MASK then
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
74 result.key = {string.byte(frame, pos+1), string.byte(frame, pos+2),
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
75 string.byte(frame, pos+3), string.byte(frame, pos+4)}
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
76
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
77 pos = pos + 5;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
78 result.data = "";
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
79 for i = pos, pos + result.length - 1 do
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
80 result.data = result.data .. string.char(bxor(result.key[counter+1], string.byte(frame, i)));
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
81 counter = (counter + 1) % 4;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
82 end
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
83 else
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
84 result.data = frame:sub(pos + 1, pos + result.length);
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
85 end
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
86
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
87 return result;
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
88 end
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
89
687
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
90 local function build_frame(desc)
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
91 local length;
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
92 local result = "";
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
93
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
94 result = result .. string.char(0x80 * (desc.FIN and 1 or 0) + desc.opcode);
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
95
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
96 length = #desc.data;
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
97 if length <= 125 then -- 7-bit length
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
98 result = result .. string.char(length);
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
99 elseif length <= 0xFFFF then -- 2-byte length
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
100 result = result .. string.char(126);
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
101 result = result .. string.char(length/0x100) .. string.char(length%0x100);
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
102 else -- 8-byte length
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
103 result = result .. string.char(127);
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
104 for i = 7, 0, -1 do
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
105 result = result .. string.char(( length / (2^(8*i)) ) % 0x100);
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
106 end
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
107 end
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
108
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
109 result = result .. desc.data;
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
110
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
111 return result;
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
112 end
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
113
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
114 --- Stream events handlers
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
115 local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'};
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
116 local default_stream_attr = { ["xmlns:stream"] = "http://etherx.jabber.org/streams", xmlns = stream_callbacks.default_ns, version = "1.0", id = "" };
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
117
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
118 function stream_callbacks.streamopened(session, attr)
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
119 local send = session.send;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
120 session.host = nameprep(attr.to);
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
121 if not session.host then
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
122 session:close{ condition = "improper-addressing",
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
123 text = "A valid 'to' attribute is required on stream headers" };
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
124 return;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
125 end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
126 session.version = tonumber(attr.version) or 0;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
127 session.streamid = uuid_generate();
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
128 (session.log or session)("debug", "Client sent opening <stream:stream> to %s", session.host);
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
129
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
130 if not hosts[session.host] then
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
131 -- We don't serve this host...
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
132 session:close{ condition = "host-unknown", text = "This server does not serve "..tostring(session.host)};
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
133 return;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
134 end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
135
677
eeb41cd5e9f3 mod_websocket: Move frame handling into a separate function
Florian Zeitz <florob@babelmonkeys.de>
parents: 676
diff changeset
136 -- COMPAT: Current client implementations need this to be self-closing
692
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
137 if self_closing_stream then
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
138 send("<?xml version='1.0'?>"..tostring(st.stanza("stream:stream", {
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
139 xmlns = 'jabber:client', ["xmlns:stream"] = 'http://etherx.jabber.org/streams';
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
140 id = session.streamid, from = session.host, version = '1.0', ["xml:lang"] = 'en' })));
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
141 else
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
142 send("<?xml version='1.0'?>"..st.stanza("stream:stream", {
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
143 xmlns = 'jabber:client', ["xmlns:stream"] = 'http://etherx.jabber.org/streams';
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
144 id = session.streamid, from = session.host, version = '1.0', ["xml:lang"] = 'en' }):top_tag());
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
145 end
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
146
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
147 (session.log or log)("debug", "Sent reply <stream:stream> to client");
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
148 session.notopen = nil;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
149
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
150 -- If session.secure is *false* (not nil) then it means we /were/ encrypting
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
151 -- since we now have a new stream header, session is secured
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
152 if session.secure == false then
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
153 session.secure = true;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
154 end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
155
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
156 local features = st.stanza("stream:features");
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
157 hosts[session.host].events.fire_event("stream-features", { origin = session, features = features });
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
158 module:fire_event("stream-features", session, features);
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
159
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
160 send(features);
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
161 end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
162
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
163 function stream_callbacks.streamclosed(session)
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
164 session.log("debug", "Received </stream:stream>");
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
165 session:close();
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
166 end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
167
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
168 function stream_callbacks.error(session, error, data)
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
169 if error == "no-stream" then
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
170 session.log("debug", "Invalid opening stream header");
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
171 session:close("invalid-namespace");
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
172 elseif error == "parse-error" then
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
173 (session.log or log)("debug", "Client XML parse error: %s", tostring(data));
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
174 session:close("not-well-formed");
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
175 elseif error == "stream-error" then
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
176 local condition, text = "undefined-condition";
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
177 for child in data:children() do
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
178 if child.attr.xmlns == xmlns_xmpp_streams then
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
179 if child.name ~= "text" then
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
180 condition = child.name;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
181 else
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
182 text = child:get_text();
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
183 end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
184 if condition ~= "undefined-condition" and text then
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
185 break;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
186 end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
187 end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
188 end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
189 text = condition .. (text and (" ("..text..")") or "");
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
190 session.log("info", "Session closed by remote with error: %s", text);
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
191 session:close(nil, text);
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
192 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
193 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
194
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
195 local function handleerr(err) log("error", "Traceback[c2s]: %s: %s", tostring(err), traceback()); end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
196 function stream_callbacks.handlestanza(session, stanza)
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
197 stanza = session.filter("stanzas/in", stanza);
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
198 if stanza then
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
199 return xpcall(function () return core_process_stanza(session, stanza) end, handleerr);
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
200 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
201 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
202
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
203 --- Session methods
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
204 local function session_close(session, reason)
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
205 local log = session.log or log;
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
206 if session.conn then
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
207 if session.notopen then
692
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
208 -- COMPAT: Current client implementations need this to be self-closing
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
209 if self_closing_stream then
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
210 session.send("<?xml version='1.0'?>"..tostring(st.stanza("stream:stream", default_stream_attr)));
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
211 else
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
212 session.send("<?xml version='1.0'?>"..st.stanza("stream:stream", default_stream_attr):top_tag());
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
213 end
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
214 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
215 if reason then
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
216 if type(reason) == "string" then -- assume stream error
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
217 log("info", "Disconnecting client, <stream:error> is: %s", reason);
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
218 session.send(st.stanza("stream:error"):tag(reason, {xmlns = 'urn:ietf:params:xml:ns:xmpp-streams' }));
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
219 elseif type(reason) == "table" then
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
220 if reason.condition then
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
221 local stanza = st.stanza("stream:error"):tag(reason.condition, stream_xmlns_attr):up();
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
222 if reason.text then
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
223 stanza:tag("text", stream_xmlns_attr):text(reason.text):up();
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
224 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
225 if reason.extra then
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
226 stanza:add_child(reason.extra);
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
227 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
228 log("info", "Disconnecting client, <stream:error> is: %s", tostring(stanza));
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
229 session.send(stanza);
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
230 elseif reason.name then -- a stanza
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
231 log("info", "Disconnecting client, <stream:error> is: %s", tostring(reason));
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
232 session.send(reason);
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
233 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
234 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
235 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
236 session.send("</stream:stream>");
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
237 session.conn:close();
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
238 listener.ondisconnect(session.conn, (reason and (reason.text or reason.condition)) or reason or "session closed");
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
239 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
240 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
241
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
242 --- Port listener
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
243 function listener.onconnect(conn)
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
244 local session = sm_new_session(conn);
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
245 sessions[conn] = session;
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
246
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
247 session.log("info", "Client connected");
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
248
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
249 -- Client is using legacy SSL (otherwise mod_tls sets this flag)
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
250 if conn:ssl() then
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
251 session.secure = true;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
252 end
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
253
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
254 if opt_keepalives then
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
255 conn:setoption("keepalive", opt_keepalives);
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
256 end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
257
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
258 session.close = session_close;
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
259
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
260 local stream = new_xmpp_stream(session, stream_callbacks);
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
261 session.stream = stream;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
262 session.notopen = true;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
263
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
264 function session.reset_stream()
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
265 session.notopen = true;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
266 session.stream:reset();
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
267 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
268
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
269 local filter = session.filter;
690
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
270 local buffer = "";
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
271 function session.data(data)
690
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
272 local frame = parse_frame(data);
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
273
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
274 module:log("debug", "Websocket received: %s (%i bytes)", frame.data, #frame.data);
691
04662cc35280 mod_websocket: Answer ping frames
Florian Zeitz <florob@babelmonkeys.de>
parents: 690
diff changeset
275 if frame.opcode == 0x0 or frame.opcode == 0x1 then -- Text or continuation frame
690
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
276 buffer = buffer .. frame.data;
691
04662cc35280 mod_websocket: Answer ping frames
Florian Zeitz <florob@babelmonkeys.de>
parents: 690
diff changeset
277 elseif frame.opcode == 0x9 then -- Ping frame
04662cc35280 mod_websocket: Answer ping frames
Florian Zeitz <florob@babelmonkeys.de>
parents: 690
diff changeset
278 frame.opcode = 0xA;
04662cc35280 mod_websocket: Answer ping frames
Florian Zeitz <florob@babelmonkeys.de>
parents: 690
diff changeset
279 conn:write(build_frame(frame));
04662cc35280 mod_websocket: Answer ping frames
Florian Zeitz <florob@babelmonkeys.de>
parents: 690
diff changeset
280 return;
690
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
281 else
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
282 log("warn", "Received frame with unsupported opcode %i", frame.opcode);
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
283 return;
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
284 end
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
285
690
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
286 if frame.FIN then
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
287 data = buffer;
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
288 buffer = "";
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
289
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
290 -- COMPAT: Current client implementations send a self-closing <stream:stream>
692
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
291 if self_closing_stream then
693
7d165cd6168c mod_websocket: Only un-self-close <stream:stream>s
Florian Zeitz <florob@babelmonkeys.de>
parents: 692
diff changeset
292 data = data:gsub("(<stream:stream.*)/>$", "%1>");
692
2de21fa40382 mod_websocket: Make sending a self-closing <stream:stream> tag configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 691
diff changeset
293 end
690
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
294
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
295 data = filter("bytes/in", data);
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
296 if data then
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
297 local ok, err = stream:feed(data);
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
298 if ok then return; end
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
299 log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_"));
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
300 session:close("not-well-formed");
5acc203972f3 mod_websocket: Add fragmentation support
Florian Zeitz <florob@babelmonkeys.de>
parents: 689
diff changeset
301 end
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
302 end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
303 end
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
304
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
305 function session.send(s)
687
d141375ece4b mod_websocket: Move frame building into a function
Florian Zeitz <florob@babelmonkeys.de>
parents: 677
diff changeset
306 conn:write(build_frame({ FIN = true, opcode = 0x01, data = tostring(s)}));
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
307 end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
308
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
309 if c2s_timeout then
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
310 add_task(c2s_timeout, function ()
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
311 if session.type == "c2s_unauthed" then
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
312 session:close("connection-timeout");
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
313 end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
314 end);
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
315 end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
316
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
317 session.dispatch_stanza = stream_callbacks.handlestanza;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
318 end
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
319
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
320 function listener.onincoming(conn, data)
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
321 local session = sessions[conn];
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
322 if session then
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
323 session.data(data);
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
324 else
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
325 listener.onconnect(conn, data);
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
326 session = sessions[conn];
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
327 session.data(data);
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
328 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
329 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
330
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
331 function listener.ondisconnect(conn, err)
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
332 local session = sessions[conn];
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
333 if session then
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
334 (session.log or log)("info", "Client disconnected: %s", err);
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
335 sm_destroy_session(session, err);
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
336 sessions[conn] = nil;
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
337 session = nil;
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
338 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
339 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
340
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
341 function listener.associate_session(conn, session)
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
342 sessions[conn] = session;
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
343 end
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
344
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
345 function handle_request(event, path)
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
346 local request, response = event.request, event.response;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
347
689
4d21bd5dde49 mod_websocket: Be nice to non-websocket clients
Florian Zeitz <florob@babelmonkeys.de>
parents: 688
diff changeset
348 if not request.headers.sec_websocket_key then
4d21bd5dde49 mod_websocket: Be nice to non-websocket clients
Florian Zeitz <florob@babelmonkeys.de>
parents: 688
diff changeset
349 response.headers.content_type = "text/html";
4d21bd5dde49 mod_websocket: Be nice to non-websocket clients
Florian Zeitz <florob@babelmonkeys.de>
parents: 688
diff changeset
350 return [[<!DOCTYPE html><html><head><title>Websocket</title></head><body>
4d21bd5dde49 mod_websocket: Be nice to non-websocket clients
Florian Zeitz <florob@babelmonkeys.de>
parents: 688
diff changeset
351 <p>It works! Now point your WebSocket client to this URL to connect to Prosody.</p>
4d21bd5dde49 mod_websocket: Be nice to non-websocket clients
Florian Zeitz <florob@babelmonkeys.de>
parents: 688
diff changeset
352 </body></html>]];
4d21bd5dde49 mod_websocket: Be nice to non-websocket clients
Florian Zeitz <florob@babelmonkeys.de>
parents: 688
diff changeset
353 end
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
354
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
355 response.conn:setlistener(listener);
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
356 response.status = "101 Switching Protocols";
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
357 response.headers.Upgrade = "websocket";
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
358 response.headers.Connection = "Upgrade";
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
359 response.headers.Sec_WebSocket_Accept = base64(sha1(request.headers.sec_websocket_key .. "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
360 response.headers.Sec_WebSocket_Protocol = "xmpp";
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
361
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
362 return "";
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
363 end
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
364
688
e87678a52720 mod_websocket: Make this a shared module
Florian Zeitz <florob@babelmonkeys.de>
parents: 687
diff changeset
365 function module.add_host(module)
e87678a52720 mod_websocket: Make this a shared module
Florian Zeitz <florob@babelmonkeys.de>
parents: 687
diff changeset
366 module:depends("http");
676
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
367 module:provides("http", {
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
368 name = "xmpp-websocket";
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
369 route = {
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
370 ["GET /*"] = handle_request;
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
371 };
54fa9d6d7809 mod_websocket: New mod_c2s based version, still WIP
Florian Zeitz <florob@babelmonkeys.de>
parents: 129
diff changeset
372 });
129
5fc00a3e47b5 mod_websocket: Initial commit
Ali Sabil <ali.sabil@gmail.com>
parents:
diff changeset
373 end