Annotate

net/websocket/frames.lua @ 10228:e77bf4222fae

net.server_epoll: Add support for opportunistic writes This tries to flush data to the underlying sockets when receiving writes. This should lead to fewer timer objects being around. On the other hand, this leads to more and smaller writes which may translate to more TCP/IP packets being sent, depending on how the kernel handles this. This trades throughput for lower latency.
author Kim Alvefur <zash@zash.se>
date Wed, 28 Aug 2019 01:41:00 +0200
parent 9692:affcbccc1dff
child 10241:48f7cda4174d
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
9659
86c431650dfd net.websocket.frames: Prefer Lua 5.2 built-in bit module over LuaJIT version
Kim Alvefur <zash@zash.se>
parents: 8728
diff changeset
12 local bit = assert(softreq"bit32" or softreq"bit",
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;
9691
e11e076f0eb8 various: Don't rely on _G.unpack existing
Kim Alvefur <zash@zash.se>
parents: 9659
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_byte = string.byte;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
23 local s_char= string.char;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
24 local s_sub = string.sub;
9692
affcbccc1dff lint: Remove use of the 143 error code
Kim Alvefur <zash@zash.se>
parents: 9691
diff changeset
25 local s_pack = string.pack;
affcbccc1dff lint: Remove use of the 143 error code
Kim Alvefur <zash@zash.se>
parents: 9691
diff changeset
26 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
27
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 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
29 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
30 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
31 end
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
32
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
33 local function read_uint16be(str, pos)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
34 local l1, l2 = s_byte(str, pos, pos+1);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
35 return l1*256 + l2;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
36 end
6395
e0164b0fcafd net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
37 -- FIXME: this may lose precision
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
38 local function read_uint64be(str, pos)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
39 local l1, l2, l3, l4, l5, l6, l7, l8 = s_byte(str, 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
40 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
41 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
42 return h * 2^32 + l;
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
43 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
44 local function pack_uint16be(x)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
45 return s_char(rshift(x, 8), band(x, 0xFF));
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
46 end
6395
e0164b0fcafd net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
47 local function get_byte(x, n)
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
48 return band(rshift(x, n), 0xFF);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
49 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
50 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
51 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
52 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
53 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
54 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
55
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
56 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
57 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
58 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
59 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
60 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
61 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
62 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
63 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
64
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
65 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
66 function read_uint16be(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
67 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
68 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
69 function read_uint64be(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
70 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
71 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
72 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
73
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
74 local function parse_frame_header(frame)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
75 if #frame < 2 then return; end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
76
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
77 local byte1, byte2 = s_byte(frame, 1, 2);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
78 local result = {
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
79 FIN = band(byte1, 0x80) > 0;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
80 RSV1 = band(byte1, 0x40) > 0;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
81 RSV2 = band(byte1, 0x20) > 0;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
82 RSV3 = band(byte1, 0x10) > 0;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
83 opcode = band(byte1, 0x0F);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
84
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
85 MASK = band(byte2, 0x80) > 0;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
86 length = band(byte2, 0x7F);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
87 };
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 local length_bytes = 0;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
90 if result.length == 126 then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
91 length_bytes = 2;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
92 elseif result.length == 127 then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
93 length_bytes = 8;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
94 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
95
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
96 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
97 if #frame < header_length then return; end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
98
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
99 if length_bytes == 2 then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
100 result.length = read_uint16be(frame, 3);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
101 elseif length_bytes == 8 then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
102 result.length = read_uint64be(frame, 3);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
103 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
104
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
105 if result.MASK then
6395
e0164b0fcafd net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
106 result.key = { s_byte(frame, length_bytes+3, length_bytes+6) };
6389
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 return result, header_length;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
110 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
111
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
112 -- 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
113 -- TODO: optimize
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
114 local function apply_mask(str, key, from, to)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
115 from = from or 1
8728
41c959c5c84b Fix spelling throughout the codebase [codespell]
Kim Alvefur <zash@zash.se>
parents: 8442
diff changeset
116 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
117 to = to or #str
8728
41c959c5c84b Fix spelling throughout the codebase [codespell]
Kim Alvefur <zash@zash.se>
parents: 8442
diff changeset
118 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
119 local key_len = #key
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
120 local counter = 0;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
121 local data = {};
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
122 for i = from, to do
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
123 local key_index = counter%key_len + 1;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
124 counter = counter + 1;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
125 data[counter] = s_char(bxor(key[key_index], s_byte(str, i)));
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
126 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
127 return t_concat(data);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
128 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
129
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
130 local function parse_frame_body(frame, header, pos)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
131 if header.MASK then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
132 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
133 else
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
134 return frame:sub(pos, pos + header.length - 1);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
135 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
136 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
137
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
138 local function parse_frame(frame)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
139 local result, pos = parse_frame_header(frame);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
140 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
141 result.data = parse_frame_body(frame, result, pos+1);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
142 return result, pos + result.length;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
143 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
144
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
145 local function build_frame(desc)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
146 local data = desc.data or "";
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
147
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
148 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
149 if desc.opcode >= 0x8 then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
150 -- RFC 6455 5.5
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
151 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
152 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
153
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
154 local b1 = bor(desc.opcode,
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
155 desc.FIN and 0x80 or 0,
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
156 desc.RSV1 and 0x40 or 0,
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
157 desc.RSV2 and 0x20 or 0,
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
158 desc.RSV3 and 0x10 or 0);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
159
6395
e0164b0fcafd net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
160 local b2 = #data;
e0164b0fcafd net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
161 local length_extra;
e0164b0fcafd net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
162 if b2 <= 125 then -- 7-bit length
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
163 length_extra = "";
6395
e0164b0fcafd net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
164 elseif b2 <= 0xFFFF then -- 2-byte length
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
165 b2 = 126;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
166 length_extra = pack_uint16be(#data);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
167 else -- 8-byte length
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
168 b2 = 127;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
169 length_extra = pack_uint64be(#data);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
170 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
171
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
172 local key = ""
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
173 if desc.MASK then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
174 local key_a = desc.key
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
175 if key_a then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
176 key = s_char(unpack(key_a, 1, 4));
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
177 else
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
178 key = random_bytes(4);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
179 key_a = {key:byte(1,4)};
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
180 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
181 b2 = bor(b2, 0x80);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
182 data = apply_mask(data, key_a);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
183 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
184
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
185 return s_char(b1, b2) .. length_extra .. key .. data
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
186 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
187
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
188 local function parse_close(data)
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
189 local code, message
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
190 if #data >= 2 then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
191 code = read_uint16be(data, 1);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
192 if #data > 2 then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
193 message = s_sub(data, 3);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
194 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
195 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
196 return code, message
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
197 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
198
6455
b6514e691a70 net.websocket: Make data masking configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 6398
diff changeset
199 local function build_close(code, message, mask)
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
200 local data = pack_uint16be(code);
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
201 if message then
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
202 assert(#message<=123, "Close reason must be <=123 bytes");
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
203 data = data .. message;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
204 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
205 return build_frame({
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
206 opcode = 0x8;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
207 FIN = true;
6455
b6514e691a70 net.websocket: Make data masking configurable
Florian Zeitz <florob@babelmonkeys.de>
parents: 6398
diff changeset
208 MASK = mask;
6389
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
209 data = data;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
210 });
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
211 end
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
212
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
213 return {
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
214 parse_header = parse_frame_header;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
215 parse_body = parse_frame_body;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
216 parse = parse_frame;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
217 build = build_frame;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
218 parse_close = parse_close;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
219 build_close = build_close;
8eccd07b619c net/websocket: Add new websocket client code
daurnimator <quae@daurnimator.com>
parents:
diff changeset
220 };