em-websocket 0.1.2 → 0.1.3

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.3
@@ -0,0 +1,19 @@
1
+ require 'lib/em-websocket'
2
+ require 'sinatra/base'
3
+ require 'thin'
4
+
5
+ EM.run do
6
+ class App < Sinatra::Base
7
+ get '/' do
8
+
9
+ end
10
+ end
11
+
12
+ EM::WebSocket.start(:host => '0.0.0.0', :port => 3001) do
13
+ # Websocket code here
14
+ end
15
+
16
+ # You could also use Rainbows! instead of Thin.
17
+ # Any EM based Rack handler should do.
18
+ # Thin.start App, '0.0.0.0', 3000
19
+ end
@@ -10,6 +10,7 @@ module EventMachine
10
10
  # define WebSocket callbacks
11
11
  def onopen(&blk); @onopen = blk; end
12
12
  def onclose(&blk); @onclose = blk; end
13
+ def onerror(&blk); @onerror = blk; end
13
14
  def onmessage(&blk); @onmessage = blk; end
14
15
 
15
16
  def initialize(options)
@@ -68,13 +69,14 @@ module EventMachine
68
69
  return true
69
70
  rescue => e
70
71
  debug [:error, e]
71
- process_bad_request
72
+ process_bad_request(e)
72
73
  return false
73
74
  end
74
75
  end
75
76
  end
76
77
 
77
- def process_bad_request
78
+ def process_bad_request(reason)
79
+ @onerror.call(reason) if @onerror
78
80
  send_data "HTTP/1.1 400 Bad request\r\n\r\n"
79
81
  close_connection_after_writing
80
82
  end
@@ -139,10 +141,11 @@ module EventMachine
139
141
  # If the high-order bit of the /frame type/ byte is _not_ set
140
142
  msg = @data.slice!(/^\x00([^\xff]*)\xff/)
141
143
  if msg
142
- msg.gsub!(/^\x00|\xff$/, '')
144
+ msg.gsub!(/\A\x00|\xff\z/, '')
143
145
  if @state == :closing
144
146
  debug [:ignored_message, msg]
145
147
  else
148
+ msg.force_encoding('UTF-8') if msg.respond_to?(:force_encoding)
146
149
  @onmessage.call(msg) if @onmessage
147
150
  end
148
151
  else
@@ -163,7 +166,9 @@ module EventMachine
163
166
  # a leading length indicator
164
167
  def send(data)
165
168
  debug [:send, data]
166
- send_data("\x00#{data}\xff")
169
+ ary = ["\x00", data, "\xff"]
170
+ ary.collect{ |s| s.force_encoding('UTF-8') if s.respond_to?(:force_encoding) }
171
+ send_data(ary.join)
167
172
  end
168
173
  end
169
174
  end
@@ -49,7 +49,10 @@ module EventMachine
49
49
  end
50
50
 
51
51
  def count_spaces(string)
52
- string.scan(/ /).size
52
+ spaces = string.scan(/ /).size
53
+ # As per 5.2.5, abort the connection if spaces are zero.
54
+ raise HandshakeError, "Websocket Key1 or Key2 does not contain spaces - this is a symptom of a cross-protocol attack" if spaces == 0
55
+ return spaces
53
56
  end
54
57
 
55
58
  def validate_protocol!(protocol)
@@ -99,4 +99,30 @@ describe "WebSocket server draft76" do
99
99
  end
100
100
  end
101
101
  end
102
+
103
+ it "should accept null bytes within the frame after a line return" do
104
+ EM.run do
105
+ EM.add_timer(0.1) do
106
+ EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
107
+ ws.onmessage { |msg|
108
+ msg.should == "\n\000"
109
+ }
110
+ }
111
+
112
+ # Create a fake client which sends draft 76 handshake
113
+ connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
114
+ connection.send_data(format_request(@request))
115
+
116
+ # Send closing frame after handshake complete
117
+ connection.onopen = lambda {
118
+ connection.send_data("\000\n\000\377")
119
+ connection.send_data(EM::WebSocket::Handler76::TERMINATE_STRING)
120
+ }
121
+
122
+ connection.onclose = lambda {
123
+ EM.stop
124
+ }
125
+ end
126
+ end
127
+ end
102
128
  end
@@ -114,4 +114,14 @@ describe "EventMachine::WebSocket::Handler" do
114
114
  handler(@request).handshake
115
115
  }.should raise_error(EM::WebSocket::HandshakeError)
116
116
  end
117
+
118
+ %w[Sec-WebSocket-Key1 Sec-WebSocket-Key2].each do |header|
119
+ it "should raise error if #{header} has zero spaces" do
120
+ @request[:headers][header] = 'nospaces'
121
+
122
+ lambda {
123
+ handler(@request).handshake
124
+ }.should raise_error(EM::WebSocket::HandshakeError, 'Websocket Key1 or Key2 does not contain spaces - this is a symptom of a cross-protocol attack')
125
+ end
126
+ end
117
127
  end
@@ -18,7 +18,6 @@ describe EventMachine::WebSocket do
18
18
 
19
19
  EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
20
20
  ws.onopen {
21
- puts "WebSocket connection open"
22
21
  ws.send MSG
23
22
  }
24
23
  end
@@ -91,6 +90,26 @@ describe EventMachine::WebSocket do
91
90
  end
92
91
  end
93
92
 
93
+ it "should call onerror callback with raised exception and close connection on bad handshake" do
94
+ EM.run do
95
+ EventMachine.add_timer(0.1) do
96
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:12345/').get :timeout => 0
97
+ http.errback { http.response_header.status.should == 0 }
98
+ http.callback { failed }
99
+ end
100
+
101
+ EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
102
+ ws.onopen { failed }
103
+ ws.onclose { EventMachine.stop }
104
+ ws.onerror {|e|
105
+ e.should be_an_instance_of EventMachine::WebSocket::HandshakeError
106
+ e.message.should match('Connection and Upgrade headers required')
107
+ EventMachine.stop
108
+ }
109
+ end
110
+ end
111
+ end
112
+
94
113
  it "should populate ws.request with appropriate headers" do
95
114
  EM.run do
96
115
  EventMachine.add_timer(0.1) do
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 2
9
- version: 0.1.2
8
+ - 3
9
+ version: 0.1.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Ilya Grigorik
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-06-16 00:00:00 -04:00
17
+ date: 2010-07-18 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -129,3 +129,4 @@ test_files:
129
129
  - spec/websocket_spec.rb
130
130
  - examples/echo.rb
131
131
  - examples/multicast.rb
132
+ - examples/srv.rb