Created
June 3, 2016 12:02
-
-
Save anonymous/ae63011651aee0500f0d9237fe2a76c4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# Author: Romi Strub | |
# Last Edited: 02-06-2016 | |
# WebSocket chat script. | |
puts "RUBY_VERSION " + RUBY_VERSION | |
puts "Process.pid " + Process.pid.to_s | |
class MyRequest | |
def self.parseHttpHeaders(headerString) | |
returnHash = {} | |
lines = headerString.split("\r\n") | |
firstLine = lines.shift | |
firstLineWords = firstLine.split(" ") | |
returnHash["Method"] = firstLineWords[0] | |
returnHash["URI"] = firstLineWords[1] | |
returnHash["Protocol"] = firstLineWords[2] | |
lines.each {|line| | |
keyval = line.split(": ") | |
returnHash[keyval[0]] = keyval[1] | |
} | |
returnHash | |
end | |
def self.unmaskPayload(mask, payload) | |
#mask expects string of 4 chars | |
#payload expects string of n chars | |
mask = mask.bytes | |
payload = payload.bytes | |
payload = payload.map.with_index{|byte, i| | |
byte^mask[i%4] ## if either bit is 1, result is 1 | |
} | |
payload.map{|c|c.chr}.join | |
end | |
def self.decodeFrame(connection) | |
header = connection.recv(2) | |
bytes = header.bytes | |
puts "header-bytes " + bytes.to_s | |
byteone = bytes.shift | |
# whittle down the first byte to get the opcode | |
# first bit is set to one if message is final | |
final = byteone[7] | |
puts "final #{final}" | |
byteone = final == 1 ? byteone-128 : byteone | |
reserveone = byteone[6] | |
puts "reserveone #{reserveone}" | |
byteone = reserveone == 1 ? byteone-64 : byteone | |
reservetwo = byteone[5] | |
puts "reservetwo #{reservetwo}" | |
byteone = reservetwo == 1 ? byteone-32 : byteone | |
reservethree = byteone[4] | |
puts "reservethree #{reservethree}" | |
byteone = reservethree == 1 ? byteone-16 : byteone | |
opcode = byteone | |
puts "opcode #{opcode}" | |
bytetwo = bytes.shift | |
# first bit (of second byte) is set to one if message is masked | |
masked = bytetwo[7] | |
puts "masked #{masked}" | |
if masked | |
bytetwo = bytetwo-128 # negate mask flag bit | |
mask = connection.recv(4) # receieve mask string (4 bytes) | |
puts "mask #{mask}" | |
end | |
payloadlength = bytetwo | |
puts "payloadlength #{payloadlength}" | |
# receieve payload | |
payload = connection.recv(payloadlength) | |
if masked | |
payload = MyRequest.unmaskPayload(mask, payload) | |
end | |
puts "payload #{payload}" | |
{"opcode"=> opcode, | |
"masked"=> masked, | |
"payloadlength"=> payloadlength, | |
"mask"=>mask, | |
"payload"=>payload} | |
end | |
def self.encodeFrame(opcode, payload) | |
byteone = 128 + opcode # assumes message is final | |
bytetwo = payload.length # assumes message is not masked | |
body = payload | |
byteone.chr << bytetwo.chr << body | |
end | |
end | |
require 'digest/sha1' | |
require 'socket' | |
require 'awesome_print' | |
port = 9292 | |
s = TCPServer.new '',port | |
puts "server started on port #{port}" ## | |
i=0 | |
connections = [] | |
loop { | |
i = i+1 | |
connection = s.accept | |
puts "connection #{i} on port #{port}" ## | |
puts "local address: " + connection.local_address.inspect | |
puts "remote address: " + connection.remote_address.inspect | |
connections << connection | |
puts "connections:" ## | |
ap connections ## | |
string = connection.recv(1024) | |
inHeaders = MyRequest.parseHttpHeaders(string) | |
ap inHeaders ## | |
if defined? inHeaders["Sec-WebSocket-Key"] | |
# compute response for WebSocket | |
websocketkey = inHeaders["Sec-WebSocket-Key"] | |
keysuffix = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" | |
computedkey = Digest::SHA1.base64digest(websocketkey + keysuffix) | |
outHeaders = "HTTP/1.1 101 Switching Protocols\r\n" | |
outHeaders << "Connection: Upgrade\r\n" | |
outHeaders << "Date: #{Time.now}\r\n" | |
outHeaders << "Sec-Websocket-Accept: #{computedkey}\r\n" | |
outHeaders << "Server: Ruby Websocket\r\n" | |
outHeaders << "Upgrade: websocket\r\n" | |
outHeaders << "\r\n" | |
connection.write outHeaders | |
puts "RESPONSE SENT:" ## | |
puts outHeaders ## | |
end | |
Thread.new { | |
thisconnection = connection | |
j=0 | |
loop { | |
j=j+1 | |
# loopback | |
payload = MyRequest.decodeFrame(thisconnection)["payload"] | |
puts "j = " + j.to_s | |
returnMessage = MyRequest.encodeFrame(1,payload) | |
ap connections | |
connections.each {|c| | |
puts "connection " + c | |
c.write returnMessage | |
} | |
} | |
} | |
##connection.close | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment