Skip to content

Instantly share code, notes, and snippets.

Created June 2, 2016 12:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/c630d0cc82575492d3193527771025d3 to your computer and use it in GitHub Desktop.
Save anonymous/c630d0cc82575492d3193527771025d3 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
# WebSocket handshake script.
# Accepts handshake request through CGI, returns handshake response
##sudo -s #export GEM_PATH= #export PATH=
puts RUBY_VERSION
puts Process.pid
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 array of 4 bytes
#payload expects array of n bytes
payload.map.with_index{|byte, i|
mask[i%4]^byte
}
end
def self.decodeFrame(connection)
header = connection.read(2) ##### <<<< ERROR IS HERE
puts "header: " + header.length.to_s
bytes = header.bytes
byteone = bytes.shift
opcode = byteone-128 # remove very first bit (set to one)
puts "opcode #{opcode}"
bytetwo = bytes.shift
masked = bytetwo[7]
puts "masked #{masked}"
length = bytetwo
if masked
payloadlength = length-128 # negate mask flag bit
bodylength = payloadlength+4 #+4 from mask bytes
end
body = connection.recv(bodylength)
puts "recv #{bodylength}"
bytes = body.bytes
if masked
mask = bytes.shift 4
puts "mask #{mask}"
end
puts "length #{payloadlength}"
payload = bytes.shift length
rawpayload = payload
if masked
payload = MyRequest.unmaskPayload(mask, payload)
end
puts "payload #{payload}"
# payload may be nil for message: ""
message = payload.map {|n| n.chr}.join('')
puts "message #{message}"
{"opcode"=> opcode,
"masked"=> masked,
"payloadlength"=> length,
"mask"=>mask,
"payload"=>rawpayload,
"message"=>message,
"length"=>bodylength+2}
end
def self.encodeFrame(opcode, message)
byteone = 128 + opcode
bytetwo = message.length
body = message
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 = "Status: 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
puts j
message = MyRequest.decodeFrame(thisconnection)["message"]
returnMessage = MyRequest.encodeFrame(1,message)
thisconnection.write returnMessage
}
#}
##connection.close
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment