lib/websocket/driver/draft76.rb
module WebSocket class Driver class Draft76 < Draft75 BODY_SIZE = 8 def initialize(socket, options = {}) super input = @socket.env['rack.input'] @stage = -1 @body = Driver.encode(input ? input.read : '', :binary) @headers.clear @headers['Upgrade'] = 'WebSocket' @headers['Connection'] = 'Upgrade' @headers['Sec-WebSocket-Origin'] = @socket.env['HTTP_ORIGIN'] @headers['Sec-WebSocket-Location'] = @socket.url end def version 'hixie-76' end def start return false unless super send_handshake_body true end def close(reason = nil, code = nil) return false if @ready_state == 3 @socket.write(Driver.encode("\xFF\x00", :binary)) @ready_state = 3 emit(:close, CloseEvent.new(nil, nil)) true end private def handshake_response start = 'HTTP/1.1 101 WebSocket Protocol Handshake' headers = [start, @headers.to_s, ''] headers.join("\r\n") end def handshake_signature return nil unless @body.bytesize >= BODY_SIZE head = @body[0...BODY_SIZE] env = @socket.env key1 = env['HTTP_SEC_WEBSOCKET_KEY1'] value1 = number_from_key(key1) / spaces_in_key(key1) key2 = env['HTTP_SEC_WEBSOCKET_KEY2'] value2 = number_from_key(key2) / spaces_in_key(key2) Digest::MD5.digest(big_endian(value1) + big_endian(value2) + head) end def send_handshake_body return unless signature = handshake_signature @socket.write(Driver.encode(signature, :binary)) @stage = 0 open parse(@body[BODY_SIZE..-1]) if @body.bytesize > BODY_SIZE end def parse_leading_byte(data) return super unless data == 0xFF @closing = true @length = 0 @stage = 1 end def number_from_key(key) key.scan(/[0-9]/).join('').to_i(10) end def spaces_in_key(key) key.scan(/ /).size end def big_endian(number) string = Driver.encode('', :binary) [24, 16, 8, 0].each do |offset| string << (number >> offset & 0xFF).chr end string end end end end