class EventMachine::WebSocket::Handshake
Resposible for creating the server handshake response
Attributes
parser[R]
protocol_version[R]
Public Class Methods
new(secure)
click to toggle source
Unfortunately drafts 75 & 76 require knowledge of whether the connection is being terminated as ws/wss in order to generate the correct handshake response
# File lib/em-websocket/handshake.rb, line 16 def initialize(secure) @parser = Http::Parser.new @secure = secure @parser.on_headers_complete = proc { |headers| @headers = Hash[headers.map { |k,v| [k.downcase, v] }] } end
Public Instance Methods
headers()
click to toggle source
Returns the WebSocket upgrade headers as a hash.
Keys are strings, unmodified from the request.
# File lib/em-websocket/handshake.rb, line 39 def headers @parser.headers end
headers_downcased()
click to toggle source
The same as headers, except that the hash keys are downcased
# File lib/em-websocket/handshake.rb, line 45 def headers_downcased @headers end
origin()
click to toggle source
Returns the WebSocket origin header if provided
# File lib/em-websocket/handshake.rb, line 66 def origin @headers["origin"] || @headers["sec-websocket-origin"] || nil end
path()
click to toggle source
Returns the request path (excluding any query params)
# File lib/em-websocket/handshake.rb, line 51 def path @path end
query()
click to toggle source
# File lib/em-websocket/handshake.rb, line 60 def query Hash[query_string.split('&').map { |c| c.split('=', 2) }] end
query_string()
click to toggle source
Returns the query params as a string foo=bar&baz=…
# File lib/em-websocket/handshake.rb, line 56 def query_string @query_string end
receive_data(data)
click to toggle source
# File lib/em-websocket/handshake.rb, line 25 def receive_data(data) @parser << data if defined? @headers process(@headers, @parser.upgrade_data) end rescue HTTP::Parser::Error => e fail(HandshakeError.new("Invalid HTTP header: #{e.message}")) end
secure?()
click to toggle source
# File lib/em-websocket/handshake.rb, line 70 def secure? @secure end
Private Instance Methods
process(headers, remains)
click to toggle source
# File lib/em-websocket/handshake.rb, line 76 def process(headers, remains) unless @parser.http_method == "GET" raise HandshakeError, "Must be GET request" end # Validate request path # # According to http://tools.ietf.org/search/rfc2616#section-5.1.2, an # invalid Request-URI should result in a 400 status code, but # HandshakeError's currently result in a WebSocket abort. It's not # clear which should take precedence, but an abort will do just fine. begin uri = URI.parse(@parser.request_url) @path = uri.path @query_string = uri.query || "" rescue URI::InvalidURIError raise HandshakeError, "Invalid request URI: #{@parser.request_url}" end # Validate Upgrade unless @parser.upgrade? raise HandshakeError, "Not an upgrade request" end upgrade = @headers['upgrade'] unless upgrade.kind_of?(String) && upgrade.downcase == 'websocket' raise HandshakeError, "Invalid upgrade header: #{upgrade.inspect}" end # Determine version heuristically version = if @headers['sec-websocket-version'] # Used from drafts 04 onwards @headers['sec-websocket-version'].to_i elsif @headers['sec-websocket-draft'] # Used in drafts 01 - 03 @headers['sec-websocket-draft'].to_i elsif @headers['sec-websocket-key1'] 76 else 75 end # Additional handling of bytes after the header if required case version when 75 if !remains.empty? raise HandshakeError, "Extra bytes after header" end when 76, 1..3 if remains.length < 8 # The whole third-key has not been received yet. return nil elsif remains.length > 8 raise HandshakeError, "Extra bytes after third key" end @headers['third-key'] = remains end handshake_klass = case version when 75 Handshake75 when 76, 1..3 Handshake76 when 5, 6, 7, 8, 13 Handshake04 else # According to spec should abort the connection raise HandshakeError, "Protocol version #{version} not supported" end upgrade_response = handshake_klass.handshake(@headers, @parser.request_url, @secure) handler_klass = Handler.klass_factory(version) @protocol_version = version succeed(upgrade_response, handler_klass) rescue HandshakeError => e fail(e) end