Annotate

net/websocket/frames.lua @ 11106:76f46c2579a2 0.11

net.websocket.frames: Allow all methods to work on non-string objects Instead of using the string library, use methods from the passed object, which are assumed to be equivalent. This provides compatibility with objects from util.ringbuffer and util.dbuffer, for example.
author Matthew Wild <mwild1@gmail.com>
date Thu, 17 Sep 2020 13:00:19 +0100
parent 8728:41c959c5c84b
child 11107:ddd0007e0f1b
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
1 -- Prosody IM
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
2 -- Copyright (C) 2012 Florian Zeitz
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
3 -- Copyright (C) 2014 Daurnimator
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
4 --
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
5 -- This project is MIT/X11 licensed. Please see the
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
6 -- COPYING file in the source package for more information.
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
7 --
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
8
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
9 local softreq = require "util.dependencies".softreq;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
10 local random_bytes = require "util.random".bytes;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
11
6896
c11776f85552 net.websocket.frames: Throw an error if no bit lib is found
Kim Alvefur <zash@zash.se>
parents: 6895
diff changeset
12 local bit = assert(softreq"bit" or softreq"bit32",
6897
8972b1a96526 net.websocket.frames: Link to documentation when bitop is missing
Kim Alvefur <zash@zash.se>
parents: 6896
diff changeset
13 "No bit module found. See https://prosody.im/doc/depends#bitop");
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
14 local band = bit.band;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
15 local bor = bit.bor;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
16 local bxor = bit.bxor;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
17 local lshift = bit.lshift;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
18 local rshift = bit.rshift;
11106
76f46c2579a2 net.websocket.frames: Allow all methods to work on non-string objects
Matthew Wild <mwild1@gmail.com>
parents: 8728
diff changeset
19 local unpack = table.unpack or unpack; -- luacheck: ignore 113
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
20
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
21 local t_concat = table.concat;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
22 local s_char= string.char;
11106
76f46c2579a2 net.websocket.frames: Allow all methods to work on non-string objects
Matthew Wild <mwild1@gmail.com>
parents: 8728
diff changeset
23 local s_pack = string.pack;
76f46c2579a2 net.websocket.frames: Allow all methods to work on non-string objects
Matthew Wild <mwild1@gmail.com>
parents: 8728
diff changeset
24 local s_unpack = string.unpack;
6899
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
25
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
26 if not s_pack and softreq"struct" then
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
27 s_pack = softreq"struct".pack;
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
28 s_unpack = softreq"struct".unpack;
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
29 end
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
30
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
31 local function read_uint16be(str, pos)
11106
76f46c2579a2 net.websocket.frames: Allow all methods to work on non-string objects
Matthew Wild <mwild1@gmail.com>
parents: 8728
diff changeset
32 local l1, l2 = str:byte(pos, pos+1);
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
33 return l1*256 + l2;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
34 end
6395
e0164b0fcafd net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
35 -- FIXME: this may lose precision
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
36 local function read_uint64be(str, pos)
11106
76f46c2579a2 net.websocket.frames: Allow all methods to work on non-string objects
Matthew Wild <mwild1@gmail.com>
parents: 8728
diff changeset
37 local l1, l2, l3, l4, l5, l6, l7, l8 = str:byte(pos, pos+7);
6898
d01254d5a825 net.websocket.frames: Pack and unpack 64bit ints without overflows (lua-bitop/bit32 are 32bit)
Kim Alvefur <zash@zash.se>
parents: 6897
diff changeset
38 local h = lshift(l1, 24) + lshift(l2, 16) + lshift(l3, 8) + l4;
d01254d5a825 net.websocket.frames: Pack and unpack 64bit ints without overflows (lua-bitop/bit32 are 32bit)
Kim Alvefur <zash@zash.se>
parents: 6897
diff changeset
39 local l = lshift(l5, 24) + lshift(l6, 16) + lshift(l7, 8) + l8;
d01254d5a825 net.websocket.frames: Pack and unpack 64bit ints without overflows (lua-bitop/bit32 are 32bit)
Kim Alvefur <zash@zash.se>
parents: 6897
diff changeset
40 return h * 2^32 + l;
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
41 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
42 local function pack_uint16be(x)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
43 return s_char(rshift(x, 8), band(x, 0xFF));
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
44 end
6395
e0164b0fcafd net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
45 local function get_byte(x, n)
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
46 return band(rshift(x, n), 0xFF);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
47 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
48 local function pack_uint64be(x)
6898
d01254d5a825 net.websocket.frames: Pack and unpack 64bit ints without overflows (lua-bitop/bit32 are 32bit)
Kim Alvefur <zash@zash.se>
parents: 6897
diff changeset
49 local h = band(x / 2^32, 2^32-1);
6900
44a7e9152b9a net.websocket.frames: Fix syntax error due to code copy pasting
Kim Alvefur <zash@zash.se>
parents: 6899
diff changeset
50 return s_char(get_byte(h, 24), get_byte(h, 16), get_byte(h, 8), band(h, 0xFF),
44a7e9152b9a net.websocket.frames: Fix syntax error due to code copy pasting
Kim Alvefur <zash@zash.se>
parents: 6899
diff changeset
51 get_byte(x, 24), get_byte(x, 16), get_byte(x, 8), band(x, 0xFF));
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
52 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
53
6899
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
54 if s_pack then
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
55 function pack_uint16be(x)
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
56 return s_pack(">I2", x);
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
57 end
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
58 function pack_uint64be(x)
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
59 return s_pack(">I8", x);
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
60 end
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
61 end
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
62
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
63 if s_unpack then
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
64 function read_uint16be(str, pos)
11106
76f46c2579a2 net.websocket.frames: Allow all methods to work on non-string objects
Matthew Wild <mwild1@gmail.com>
parents: 8728
diff changeset
65 if type(str) ~= "string" then
76f46c2579a2 net.websocket.frames: Allow all methods to work on non-string objects
Matthew Wild <mwild1@gmail.com>
parents: 8728
diff changeset
66 str, pos = str:sub(pos, pos+1), 1;
76f46c2579a2 net.websocket.frames: Allow all methods to work on non-string objects
Matthew Wild <mwild1@gmail.com>
parents: 8728
diff changeset
67 end
6899
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
68 return s_unpack(">I2", str, pos);
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
69 end
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
70 function read_uint64be(str, pos)
11106
76f46c2579a2 net.websocket.frames: Allow all methods to work on non-string objects
Matthew Wild <mwild1@gmail.com>
parents: 8728
diff changeset
71 if type(str) ~= "string" then
76f46c2579a2 net.websocket.frames: Allow all methods to work on non-string objects
Matthew Wild <mwild1@gmail.com>
parents: 8728
diff changeset
72 str, pos = str:sub(pos, pos+7), 1;
76f46c2579a2 net.websocket.frames: Allow all methods to work on non-string objects
Matthew Wild <mwild1@gmail.com>
parents: 8728
diff changeset
73 end
6899
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
74 return s_unpack(">I8", str, pos);
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
75 end
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
76 end
5f3da8b00b9b net.websocket.frames: Use struct packing in Lua 5.3 or struct lib if available
Kim Alvefur <zash@zash.se>
parents: 6898
diff changeset
77
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
78 local function parse_frame_header(frame)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
79 if #frame < 2 then return; end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
80
11106
76f46c2579a2 net.websocket.frames: Allow all methods to work on non-string objects
Matthew Wild <mwild1@gmail.com>
parents: 8728
diff changeset
81 local byte1, byte2 = frame:byte(1, 2);
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
82 local result = {
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
83 FIN = band(byte1, 0x80) > 0;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
84 RSV1 = band(byte1, 0x40) > 0;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
85 RSV2 = band(byte1, 0x20) > 0;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
86 RSV3 = band(byte1, 0x10) > 0;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
87 opcode = band(byte1, 0x0F);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
88
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
89 MASK = band(byte2, 0x80) > 0;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
90 length = band(byte2, 0x7F);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
91 };
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
92
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
93 local length_bytes = 0;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
94 if result.length == 126 then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
95 length_bytes = 2;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
96 elseif result.length == 127 then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
97 length_bytes = 8;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
98 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
99
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
100 local header_length = 2 + length_bytes + (result.MASK and 4 or 0);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
101 if #frame < header_length then return; end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
102
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
103 if length_bytes == 2 then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
104 result.length = read_uint16be(frame, 3);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
105 elseif length_bytes == 8 then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
106 result.length = read_uint64be(frame, 3);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
107 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
108
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
109 if result.MASK then
11106
76f46c2579a2 net.websocket.frames: Allow all methods to work on non-string objects
Matthew Wild <mwild1@gmail.com>
parents: 8728
diff changeset
110 result.key = { frame:byte(length_bytes+3, length_bytes+6) };
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
111 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
112
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
113 return result, header_length;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
114 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
115
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
116 -- XORs the string `str` with the array of bytes `key`
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
117 -- TODO: optimize
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
118 local function apply_mask(str, key, from, to)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
119 from = from or 1
8728
41c959c5c84b Fix spelling throughout the codebase [codespell]
Kim Alvefur <zash@zash.se>
parents: 8442
diff changeset
120 if from < 0 then from = #str + from + 1 end -- negative indices
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
121 to = to or #str
8728
41c959c5c84b Fix spelling throughout the codebase [codespell]
Kim Alvefur <zash@zash.se>
parents: 8442
diff changeset
122 if to < 0 then to = #str + to + 1 end -- negative indices
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
123 local key_len = #key
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
124 local counter = 0;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
125 local data = {};
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
126 for i = from, to do
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
127 local key_index = counter%key_len + 1;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
128 counter = counter + 1;
11106
76f46c2579a2 net.websocket.frames: Allow all methods to work on non-string objects
Matthew Wild <mwild1@gmail.com>
parents: 8728
diff changeset
129 data[counter] = s_char(bxor(key[key_index], str:byte(i)));
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
130 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
131 return t_concat(data);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
132 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
133
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
134 local function parse_frame_body(frame, header, pos)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
135 if header.MASK then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
136 return apply_mask(frame, header.key, pos, pos + header.length - 1);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
137 else
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
138 return frame:sub(pos, pos + header.length - 1);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
139 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
140 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
141
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
142 local function parse_frame(frame)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
143 local result, pos = parse_frame_header(frame);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
144 if result == nil or #frame < (pos + result.length) then return; end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
145 result.data = parse_frame_body(frame, result, pos+1);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
146 return result, pos + result.length;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
147 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
148
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
149 local function build_frame(desc)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
150 local data = desc.data or "";
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
151
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
152 assert(desc.opcode and desc.opcode >= 0 and desc.opcode <= 0xF, "Invalid WebSocket opcode");
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
153 if desc.opcode >= 0x8 then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
154 -- RFC 6455 5.5
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
155 assert(#data <= 125, "WebSocket control frames MUST have a payload length of 125 bytes or less.");
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
156 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
157
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
158 local b1 = bor(desc.opcode,
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
159 desc.FIN and 0x80 or 0,
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
160 desc.RSV1 and 0x40 or 0,
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
161 desc.RSV2 and 0x20 or 0,
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
162 desc.RSV3 and 0x10 or 0);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
163
6395
e0164b0fcafd net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
164 local b2 = #data;
e0164b0fcafd net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
165 local length_extra;
e0164b0fcafd net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
166 if b2 <= 125 then -- 7-bit length
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
167 length_extra = "";
6395
e0164b0fcafd net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
168 elseif b2 <= 0xFFFF then -- 2-byte length
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
169 b2 = 126;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
170 length_extra = pack_uint16be(#data);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
171 else -- 8-byte length
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
172 b2 = 127;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
173 length_extra = pack_uint64be(#data);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
174 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
175
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
176 local key = ""
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
177 if desc.MASK then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
178 local key_a = desc.key
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
179 if key_a then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
180 key = s_char(unpack(key_a, 1, 4));
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
181 else
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
182 key = random_bytes(4);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
183 key_a = {key:byte(1,4)};
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
184 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
185 b2 = bor(b2, 0x80);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
186 data = apply_mask(data, key_a);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
187 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
188
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
189 return s_char(b1, b2) .. length_extra .. key .. data
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
190 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
191
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
192 local function parse_close(data)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
193 local code, message
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
194 if #data >= 2 then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
195 code = read_uint16be(data, 1);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
196 if #data > 2 then
11106
76f46c2579a2 net.websocket.frames: Allow all methods to work on non-string objects
Matthew Wild <mwild1@gmail.com>
parents: 8728
diff changeset
197 message = data:sub(3);
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
198 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
199 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
200 return code, message
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
201 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
202
6455
b6514e691a70 net.websocket: Make data masking configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 6398
diff changeset
203 local function build_close(code, message, mask)
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
204 local data = pack_uint16be(code);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
205 if message then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
206 assert(#message<=123, "Close reason must be <=123 bytes");
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
207 data = data .. message;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
208 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
209 return build_frame({
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
210 opcode = 0x8;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
211 FIN = true;
6455
b6514e691a70 net.websocket: Make data masking configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 6398
diff changeset
212 MASK = mask;
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
213 data = data;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
214 });
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
215 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
216
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
217 return {
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
218 parse_header = parse_frame_header;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
219 parse_body = parse_frame_body;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
220 parse = parse_frame;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
221 build = build_frame;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
222 parse_close = parse_close;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
223 build_close = build_close;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
224 };