Mercurial > prosody-hg
comparison net/websocket.lua @ 8892:fb38b2c77a72
net.websocket: Fix incompatibility with net.http changes
I was unable to pinpoint the exact revision that broke this.
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Fri, 08 Jun 2018 16:30:04 +0100 |
| parents | a3565d7dd304 |
| children | eb710675f7f8 |
comparison
equal
deleted
inserted
replaced
| 8891:d9b7db6f140f | 8892:fb38b2c77a72 |
|---|---|
| 19 local close_timeout = 3; -- Seconds to wait after sending close frame until closing connection. | 19 local close_timeout = 3; -- Seconds to wait after sending close frame until closing connection. |
| 20 | 20 |
| 21 local websockets = {}; | 21 local websockets = {}; |
| 22 | 22 |
| 23 local websocket_listeners = {}; | 23 local websocket_listeners = {}; |
| 24 function websocket_listeners.ondisconnect(handler, err) | 24 function websocket_listeners.ondisconnect(conn, err) |
| 25 local s = websockets[handler]; | 25 local s = websockets[conn]; |
| 26 websockets[handler] = nil; | 26 websockets[conn] = nil; |
| 27 if s.close_timer then | 27 if s.close_timer then |
| 28 timer.stop(s.close_timer); | 28 timer.stop(s.close_timer); |
| 29 s.close_timer = nil; | 29 s.close_timer = nil; |
| 30 end | 30 end |
| 31 s.readyState = 3; | 31 s.readyState = 3; |
| 32 if s.close_code == nil and s.onerror then s:onerror(err); end | 32 if s.close_code == nil and s.onerror then s:onerror(err); end |
| 33 if s.onclose then s:onclose(s.close_code, s.close_message or err); end | 33 if s.onclose then s:onclose(s.close_code, s.close_message or err); end |
| 34 end | 34 end |
| 35 | 35 |
| 36 function websocket_listeners.ondetach(handler) | 36 function websocket_listeners.ondetach(conn) |
| 37 websockets[handler] = nil; | 37 websockets[conn] = nil; |
| 38 end | 38 end |
| 39 | 39 |
| 40 local function fail(s, code, reason) | 40 local function fail(s, code, reason) |
| 41 log("warn", "WebSocket connection failed, closing. %d %s", code, reason); | 41 log("warn", "WebSocket connection failed, closing. %d %s", code, reason); |
| 42 s:close(code, reason); | 42 s:close(code, reason); |
| 43 s.handler:close(); | 43 s.conn:close(); |
| 44 return false | 44 return false |
| 45 end | 45 end |
| 46 | 46 |
| 47 function websocket_listeners.onincoming(handler, buffer, err) -- luacheck: ignore 212/err | 47 function websocket_listeners.onincoming(conn, buffer, err) -- luacheck: ignore 212/err |
| 48 local s = websockets[handler]; | 48 local s = websockets[conn]; |
| 49 s.readbuffer = s.readbuffer..buffer; | 49 s.readbuffer = s.readbuffer..buffer; |
| 50 while true do | 50 while true do |
| 51 local frame, len = frames.parse(s.readbuffer); | 51 local frame, len = frames.parse(s.readbuffer); |
| 52 if frame == nil then break end | 52 if frame == nil then break end |
| 53 s.readbuffer = s.readbuffer:sub(len+1); | 53 s.readbuffer = s.readbuffer:sub(len+1); |
| 109 s:close(1000); | 109 s:close(1000); |
| 110 return true; | 110 return true; |
| 111 elseif frame.opcode == 0x9 then -- Ping frame | 111 elseif frame.opcode == 0x9 then -- Ping frame |
| 112 frame.opcode = 0xA; | 112 frame.opcode = 0xA; |
| 113 frame.MASK = true; -- RFC 6455 6.1.5: If the data is being sent by the client, the frame(s) MUST be masked | 113 frame.MASK = true; -- RFC 6455 6.1.5: If the data is being sent by the client, the frame(s) MUST be masked |
| 114 handler:write(frames.build(frame)); | 114 conn:write(frames.build(frame)); |
| 115 elseif frame.opcode == 0xA then -- Pong frame | 115 elseif frame.opcode == 0xA then -- Pong frame |
| 116 log("debug", "Received unexpected pong frame: " .. tostring(frame.data)); | 116 log("debug", "Received unexpected pong frame: " .. tostring(frame.data)); |
| 117 else | 117 else |
| 118 return fail(s, 1002, "Reserved opcode"); | 118 return fail(s, 1002, "Reserved opcode"); |
| 119 end | 119 end |
| 124 | 124 |
| 125 local websocket_methods = {}; | 125 local websocket_methods = {}; |
| 126 local function close_timeout_cb(now, timerid, s) -- luacheck: ignore 212/now 212/timerid | 126 local function close_timeout_cb(now, timerid, s) -- luacheck: ignore 212/now 212/timerid |
| 127 s.close_timer = nil; | 127 s.close_timer = nil; |
| 128 log("warn", "Close timeout waiting for server to close, closing manually."); | 128 log("warn", "Close timeout waiting for server to close, closing manually."); |
| 129 s.handler:close(); | 129 s.conn:close(); |
| 130 end | 130 end |
| 131 function websocket_methods:close(code, reason) | 131 function websocket_methods:close(code, reason) |
| 132 if self.readyState < 2 then | 132 if self.readyState < 2 then |
| 133 code = code or 1000; | 133 code = code or 1000; |
| 134 log("debug", "closing WebSocket with code %i: %s" , code , tostring(reason)); | 134 log("debug", "closing WebSocket with code %i: %s" , code , tostring(reason)); |
| 135 self.readyState = 2; | 135 self.readyState = 2; |
| 136 local handler = self.handler; | 136 local conn = self.conn; |
| 137 handler:write(frames.build_close(code, reason, true)); | 137 conn:write(frames.build_close(code, reason, true)); |
| 138 -- Do not close socket straight away, wait for acknowledgement from server. | 138 -- Do not close socket straight away, wait for acknowledgement from server. |
| 139 self.close_timer = timer.add_task(close_timeout, close_timeout_cb, self); | 139 self.close_timer = timer.add_task(close_timeout, close_timeout_cb, self); |
| 140 elseif self.readyState == 2 then | 140 elseif self.readyState == 2 then |
| 141 log("debug", "tried to close a closing WebSocket, closing the raw socket."); | 141 log("debug", "tried to close a closing WebSocket, closing the raw socket."); |
| 142 -- Stop timer | 142 -- Stop timer |
| 143 if self.close_timer then | 143 if self.close_timer then |
| 144 timer.stop(self.close_timer); | 144 timer.stop(self.close_timer); |
| 145 self.close_timer = nil; | 145 self.close_timer = nil; |
| 146 end | 146 end |
| 147 local handler = self.handler; | 147 local conn = self.conn; |
| 148 handler:close(); | 148 conn:close(); |
| 149 else | 149 else |
| 150 log("debug", "tried to close a closed WebSocket, ignoring."); | 150 log("debug", "tried to close a closed WebSocket, ignoring."); |
| 151 end | 151 end |
| 152 end | 152 end |
| 153 function websocket_methods:send(data, opcode) | 153 function websocket_methods:send(data, opcode) |
| 166 MASK = true; -- RFC 6455 6.1.5: If the data is being sent by the client, the frame(s) MUST be masked | 166 MASK = true; -- RFC 6455 6.1.5: If the data is being sent by the client, the frame(s) MUST be masked |
| 167 opcode = opcode; | 167 opcode = opcode; |
| 168 data = tostring(data); | 168 data = tostring(data); |
| 169 }; | 169 }; |
| 170 log("debug", "WebSocket sending frame: opcode=%0x, %i bytes", frame.opcode, #frame.data); | 170 log("debug", "WebSocket sending frame: opcode=%0x, %i bytes", frame.opcode, #frame.data); |
| 171 return self.handler:write(frames.build(frame)); | 171 return self.conn:write(frames.build(frame)); |
| 172 end | 172 end |
| 173 | 173 |
| 174 local websocket_metatable = { | 174 local websocket_metatable = { |
| 175 __index = websocket_methods; | 175 __index = websocket_methods; |
| 176 }; | 176 }; |
| 214 end | 214 end |
| 215 | 215 |
| 216 local s = setmetatable({ | 216 local s = setmetatable({ |
| 217 readbuffer = ""; | 217 readbuffer = ""; |
| 218 databuffer = nil; | 218 databuffer = nil; |
| 219 handler = nil; | 219 conn = nil; |
| 220 close_code = nil; | 220 close_code = nil; |
| 221 close_message = nil; | 221 close_message = nil; |
| 222 close_timer = nil; | 222 close_timer = nil; |
| 223 readyState = 0; | 223 readyState = 0; |
| 224 protocol = nil; | 224 protocol = nil; |
| 250 end | 250 end |
| 251 | 251 |
| 252 s.protocol = r.headers["sec-websocket-protocol"]; | 252 s.protocol = r.headers["sec-websocket-protocol"]; |
| 253 | 253 |
| 254 -- Take possession of socket from http | 254 -- Take possession of socket from http |
| 255 local conn = http_req.conn; | |
| 255 http_req.conn = nil; | 256 http_req.conn = nil; |
| 256 local handler = http_req.handler; | 257 s.conn = conn; |
| 257 s.handler = handler; | 258 websockets[conn] = s; |
| 258 websockets[handler] = s; | 259 conn:setlistener(websocket_listeners); |
| 259 handler:setlistener(websocket_listeners); | |
| 260 | 260 |
| 261 log("debug", "WebSocket connected successfully to %s", url); | 261 log("debug", "WebSocket connected successfully to %s", url); |
| 262 s.readyState = 1; | 262 s.readyState = 1; |
| 263 if s.onopen then s:onopen(); end | 263 if s.onopen then s:onopen(); end |
| 264 websocket_listeners.onincoming(handler, b); | 264 websocket_listeners.onincoming(conn, b); |
| 265 end); | 265 end); |
| 266 | 266 |
| 267 return s; | 267 return s; |
| 268 end | 268 end |
| 269 | 269 |
