Created
June 2, 2016 12:41
-
-
Save anonymous/3edf8cc810232d873bf4cb731d1724a4 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 | |
# 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) | |
connection = IO.select([connection])[0][0] # should cause Ruby to wait for available connection, but I suspect connection is already available | |
header = connection.recv(2) | |
puts "header: " + header.length.to_s | |
bytes = header.bytes | |
puts "bytes: " + bytes.to_s | |
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 = " + j.to_s | |
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