Advertisement
Guest User

Duncan Cross

a guest
Dec 10th, 2009
3,018
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 3.58 KB | None | 0 0
  1.  
  2. -- websocket.lua
  3. -- HTML5 websockets - simple module for sending and receiving messages using Copas
  4.  
  5. local assert = assert
  6. local print = print
  7. local tostring = tostring
  8. local tconcat = table.concat
  9. local strformat = string.format
  10. local strmatch = string.match
  11. local strlower = string.lower
  12. local setmetatable = setmetatable
  13. local getmetatable = getmetatable
  14. local socket = require 'socket'
  15. local mime = require 'mime'
  16. local copas = require 'copas'
  17.  
  18.  
  19. module (...)
  20.  
  21.  
  22. local webskt_meta = {__index = _M}
  23.  
  24. -- websocket.wrap(skt)
  25. -- !! skt is expected to be a copas socket
  26. function wrap(skt)
  27.   return setmetatable({skt = copas.wrap(skt)}, webskt_meta)
  28. end
  29.  
  30. function receiveClientHandshake(webskt)
  31.   assert(getmetatable(webskt) == webskt_meta, 'bad argument: expecting websocket')
  32.   local line
  33.   do
  34.     line = webskt.skt:receive("*l")
  35.     local path = strmatch(line, 'GET (/[^ ]*) HTTP/1.1')
  36.     assert(path, 'invalid first line: ' .. tostring(line))
  37.     webskt.path = path
  38.   end
  39.   webskt.headers = {}
  40.   -- "Upgrade: WebSocket"
  41.   do
  42.     line = webskt.skt:receive("*l")
  43.     if (line ~= 'Upgrade: WebSocket') then
  44.       return nil, strformat('second line must be "Upgrade: WebSocket" - received "%q"', line)
  45.     end
  46.     webskt.headers["upgrade"] = "WebSocket"
  47.   end
  48.   -- "Connection: Upgrade"
  49.   do
  50.     line = webskt.skt:receive("*l")
  51.     if (line ~= 'Connection: Upgrade') then
  52.       return nil, strformat('third line must be "Connection: Upgrade" - received "%q"', line)
  53.     end
  54.     webskt.headers["connection"] = "Upgrade"
  55.   end
  56.   -- Arbitrary headers
  57.   while true do
  58.     local line = webskt.skt:receive("*l")
  59.     if (#line == 0) then
  60.       break
  61.     end
  62.     local header_name, header_value = strmatch(line, '^([^:]+): ?(.*)$')
  63.     assert(header_name, strformat('invalid header: %q', line))
  64.     header_name = strlower(header_name)
  65.     if (header_name == 'origin') then
  66.       webskt.origin = header_value
  67.     elseif (header_name == 'host') then
  68.       webskt.location = 'ws://' .. header_value .. webskt.path
  69.     end
  70.     webskt.headers[header_name] = header_value
  71.   end
  72.   assert(webskt.location, 'missing "Host" header')
  73.   assert(webskt.origin, 'missing "Origin" header')
  74. end
  75.  
  76. function sendServerHandshake(webskt)
  77.   assert(getmetatable(webskt) == webskt_meta, 'bad argument: expecting websocket')
  78.   assert(webskt.origin and webskt.location, 'websocket object missing vital information')
  79.   webskt.skt:send("HTTP/1.1 101 Web Socket Protocol Handshake" .. "\r\n"
  80.     .. "Upgrade: WebSocket" .. "\r\n"
  81.     .. "Connection: Upgrade" .. "\r\n"
  82.     .. "WebSocket-Origin: " .. webskt.origin .. "\r\n"
  83.     .. "WebSocket-Location: " .. webskt.location .. "\r\n"
  84.     .. "WebSocket-Protocol: sample" .. "\r\n"
  85.     .. "\r\n")
  86. end
  87.  
  88. function receiveUTF8(webskt)
  89.   assert(getmetatable(webskt) == webskt_meta, 'bad argument: expecting websocket')
  90.   local b
  91.   local msg = {}
  92.   b = assert(webskt.skt:receive(1))
  93.   if (b ~= '\000') then
  94.     return nil, 'unrecognised frame character'
  95.   end
  96.   while true do
  97.     b = assert(webskt.skt:receive(1))
  98.     if (b == '\255') then
  99.       break
  100.     end
  101.     msg[#msg+1] = b
  102.   end
  103.   return tconcat(msg)
  104. end
  105.  
  106. function sendUTF8(webskt, msg)
  107.   assert(getmetatable(webskt) == webskt_meta, 'bad argument: expecting websocket')
  108.   msg = tostring(msg)
  109.   assert(not strmatch(msg, '[%z\255]'), 'message must not contain characters \\000 or \\255')
  110.   webskt.skt:send('\000' .. msg .. '\255')
  111. end
  112.  
  113. function receiveBase64(...)
  114.   return mime.unb64(receiveUTF8(...))
  115. end
  116.  
  117. function sendBase64(webskt, binstring)
  118.   sendUTF8(webskt, mime.b64(binstring))
  119. end
  120.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement