From 76691b05d2e4da159bcc7bab22b02e2e472a87d9 Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Sun, 20 Dec 2009 17:03:00 -0500 Subject: [PATCH] invoke callback on successfull websocket upgrade & invoke stream on every new message --- lib/em-http/client.rb | 40 +++++++++++++++++++--------------------- test/test_request.rb | 31 ++++++++++++------------------- 2 files changed, 31 insertions(+), 40 deletions(-) diff --git a/lib/em-http/client.rb b/lib/em-http/client.rb index 5f1a090b..c29afd46 100644 --- a/lib/em-http/client.rb +++ b/lib/em-http/client.rb @@ -246,10 +246,18 @@ def stream(&blk) @stream = blk end - # raw data push from the client (WebSocket) - def push(data) - p "\x00#{data}\xff" - send_data "\x00#{data}\xff" + # raw data push from the client (WebSocket) should + # only be invoked after handshake, otherwise it will + # inject data into the header exchange + # + # frames need to start with 0x00-0x7f byte and end with + # an 0xFF byte. Per spec, we can also set the first + # byte to a value betweent 0x80 and 0xFF, followed by + # a leading length indicator + def send(data) + if @state == :websocket + send_data("\x00#{data}\xff") + end end def normalize_body @@ -296,7 +304,7 @@ def send_request_header end end - # Set the Host header if it hasn't been specified already + # Set the Host header if it hasn't been specified already head['host'] ||= encode_host # Set the User-Agent if it hasn't been specified @@ -316,7 +324,6 @@ def send_request_body end def receive_data(data) - p "got: #{data.inspect}" @data << data dispatch end @@ -423,7 +430,6 @@ def parse_response_proxy end def parse_response_header - puts 'parsing header' return false unless parse_header(@response_header) unless @response_header.http_status and @response_header.http_reason @@ -431,7 +437,7 @@ def parse_response_header on_error "no HTTP response" return false end -p 'wtf' + # correct location header - some servers will incorrectly give a relative URI if @response_header.location begin @@ -455,6 +461,7 @@ def parse_response_header if websocket? if @response_header.status == 101 @state = :websocket + succeed else fail "websocket handshake failed" end @@ -579,19 +586,10 @@ def process_body end def process_websocket - # if @data =~ /\x00\x00(.*)\xff/ - @response << @data - @stream.call(@data) - @response = '' - @data.clear - # end - # if @response_header.status == 101 - # push ("test") - # sleep(1) - # succeed(self) - # else - # fail(self) - # end + if not @data.empty? + @stream.call(@data.read.gsub(/^(\x00)|(\xff)$/, "")) + @data.clear + end end end diff --git a/test/test_request.rb b/test/test_request.rb index e674a130..0a10ee4c 100644 --- a/test/test_request.rb +++ b/test/test_request.rb @@ -521,9 +521,14 @@ def failed end context "websocket connection" do + # Spec: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-55 + # + # ws.onopen = http.callback + # ws.onmessage = http.stream { |msg| } + # + it "should invoke errback on failed upgrade" do EventMachine.run { - http = EventMachine::HttpRequest.new('ws://127.0.0.1:8080/').get :timeout => 0 http.callback { failed } @@ -536,7 +541,7 @@ def failed it "should complete websocket handshake" do EventMachine.run { - + MSG = "hello bi-directional data exchange" http = EventMachine::HttpRequest.new('ws://127.0.0.1:2200/').get :timeout => 1 http.errback { failed } @@ -544,28 +549,16 @@ def failed http.response_header.status.should == 101 http.response_header['CONNECTION'].should match(/Upgrade/) http.response_header['UPGRADE'].should match(/WebSocket/) - - EventMachine.stop - - p "connected!" - p http; - http.push("hello world") - p 'sent data?' - + # push should only be invoked after handshake is complete + http.send(MSG) } - num = 0 - http.stream { - # p http.response - puts "recieved: #{http.response.inspect}" - sleep (1) - http.push "yo.. #{num}" - num+=1 + http.stream { |chunk| + chunk.should == MSG + EventMachine.stop } - # Needs to delayed as a callback until the handshake is complete - # http.push "data" } end end