em-websocket 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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