em-websocket 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,6 +1,7 @@
1
1
  = EM-WebSocket
2
2
 
3
3
  EventMachine based WebSocket server -- highly experimental, at this point, at least.
4
+ - http://www.igvita.com/2009/12/22/ruby-websockets-tcp-for-the-browser/
4
5
 
5
6
  == Simple server example
6
7
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
data/examples/echo.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'lib/em-websocket'
2
2
 
3
- EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080) do |ws|
3
+ EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080, :debug => true) do |ws|
4
4
  ws.onopen { ws.send "Hello Client!"}
5
5
  ws.onmessage { |msg| ws.send "Pong: #{msg}" }
6
6
  ws.onclose { puts "WebSocket closed" }
@@ -1,7 +1,12 @@
1
+ require 'addressable/uri'
2
+ require 'uri'
1
3
  module EventMachine
2
4
  module WebSocket
3
5
  class Connection < EventMachine::Connection
4
6
 
7
+ PATH = /^GET (\/[^\s]*) HTTP\/1\.1$/
8
+ HEADER = /^([^:]+):\s*([^$]+)/
9
+
5
10
  # define WebSocket callbacks
6
11
  def onopen(&blk); @onopen = blk; end
7
12
  def onclose(&blk); @onclode = blk; end
@@ -11,14 +16,17 @@ module EventMachine
11
16
  @options = options
12
17
  @debug = options[:debug] || false
13
18
  @state = :handshake
19
+ @request = {}
20
+ @data = ''
14
21
 
15
22
  debug [:initialize]
16
23
  end
17
24
 
18
25
  def receive_data(data)
19
26
  debug [:receive_data, data]
20
-
21
- dispatch(data)
27
+
28
+ @data << data
29
+ dispatch
22
30
  end
23
31
 
24
32
  def unbind
@@ -26,33 +34,69 @@ module EventMachine
26
34
  @onclose.call if @onclose
27
35
  end
28
36
 
29
- def dispatch(data = nil)
37
+ def dispatch
30
38
  while case @state
31
39
  when :handshake
32
- new_request(data)
40
+ new_request
33
41
  when :upgrade
34
42
  send_upgrade
35
43
  when :connected
36
- process_message(data)
44
+ process_message
37
45
  else raise RuntimeError, "invalid state: #{@state}"
38
46
  end
39
47
  end
40
48
  end
41
49
 
42
- def new_request(data)
43
- # TODO: verify WS headers
44
- @state = :upgrade
50
+ def new_request
51
+ if @data.match(/\r\n\r\n$/)
52
+ debug [:inbound_headers, @data]
53
+ lines = @data.split("\r\n")
54
+
55
+ # extract request path
56
+ @request['Path'] = lines.shift.match(PATH)[1].strip
57
+
58
+ # extract remaining headers
59
+ lines.each do |line|
60
+ h = HEADER.match(line)
61
+ @request[h[1].strip] = h[2].strip
62
+ end
63
+
64
+ # transform headers
65
+ @request['Host'] = Addressable::URI.parse("ws://"+@request['Host'])
66
+
67
+ if not websocket_connection?
68
+ send_data "HTTP/1.1 400 Bad request\r\n\r\n"
69
+ close_connection_after_writing
70
+ return false
71
+
72
+ else
73
+ @data = ''
74
+ @state = :upgrade
75
+ return true
76
+ end
77
+ end
78
+
79
+ false
80
+ end
81
+
82
+ def websocket_connection?
83
+ @request['Connection'] == 'Upgrade' and @request['Upgrade'] == 'WebSocket'
45
84
  end
46
85
 
47
86
  def send_upgrade
87
+ location = "ws://#{@request['Host'].host}"
88
+ location << ":#{@request['Host'].port}" if @request['Host'].port
89
+ location << @request['Path']
90
+
48
91
  upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
49
92
  upgrade << "Upgrade: WebSocket\r\n"
50
93
  upgrade << "Connection: Upgrade\r\n"
51
- upgrade << "WebSocket-Origin: file://\r\n"
52
- upgrade << "WebSocket-Location: ws://localhost:8080/\r\n\r\n"
94
+ upgrade << "WebSocket-Origin: #{@request['Origin']}\r\n"
95
+ upgrade << "WebSocket-Location: #{location}\r\n\r\n"
53
96
 
54
97
  # upgrade connection and notify client callback
55
98
  # about completed handshake
99
+ debug [:upgrade_headers, upgrade]
56
100
  send_data upgrade
57
101
 
58
102
  @state = :connected
@@ -62,9 +106,10 @@ module EventMachine
62
106
  false
63
107
  end
64
108
 
65
- def process_message(data)
66
- debug [:message, data]
67
- @onmessage.call(data) if @onmessage
109
+ def process_message
110
+ debug [:message, @data]
111
+ @onmessage.call(@data) if @onmessage
112
+ @data = ''
68
113
 
69
114
  false
70
115
  end
@@ -33,8 +33,6 @@ describe EventMachine::WebSocket do
33
33
  end
34
34
 
35
35
  it "should fail on non WebSocket requests" do
36
- pending
37
-
38
36
  EM.run do
39
37
  EventMachine.add_timer(0.1) do
40
38
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get :timeout => 0
@@ -45,7 +43,7 @@ describe EventMachine::WebSocket do
45
43
  }
46
44
  end
47
45
 
48
- EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080, :debug => true) {}
46
+ EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080) {}
49
47
  end
50
48
  end
51
49
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: em-websocket
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ilya Grigorik
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-22 00:00:00 -05:00
12
+ date: 2009-12-23 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency