em-websocket 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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