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 +1 -1
- data/examples/srv.rb +19 -0
- data/lib/em-websocket/connection.rb +9 -4
- data/lib/em-websocket/handler76.rb +4 -1
- data/spec/integration/integration_spec.rb +26 -0
- data/spec/unit/handler_spec.rb +10 -0
- data/spec/websocket_spec.rb +20 -1
- metadata +4 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.3
|
data/examples/srv.rb
ADDED
@@ -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!(
|
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
|
-
|
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
|
data/spec/unit/handler_spec.rb
CHANGED
@@ -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
|
data/spec/websocket_spec.rb
CHANGED
@@ -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
|
-
-
|
9
|
-
version: 0.1.
|
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-
|
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
|