em-websocket 0.1.3 → 0.1.4
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/CHANGELOG.rdoc +37 -0
- data/README.rdoc +18 -0
- data/VERSION +1 -1
- data/lib/em-websocket/connection.rb +18 -2
- data/lib/em-websocket/handler.rb +0 -2
- data/lib/em-websocket/handler76.rb +2 -2
- data/lib/em-websocket/handler_factory.rb +2 -1
- data/lib/em-websocket/websocket.rb +3 -0
- data/spec/integration/integration_spec.rb +39 -0
- metadata +4 -3
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
= Changelog
|
2
|
+
|
3
|
+
== 0.1.4 / 2010-08-23
|
4
|
+
|
5
|
+
- new features:
|
6
|
+
- Allow custom ssl certificate to be used by passing :tls_options
|
7
|
+
- Protect against errors caused by non limited frame lengths
|
8
|
+
- Use custom exceptions rather than RuntimeError
|
9
|
+
- bugfixes:
|
10
|
+
- Handle invalid HTTP request with HandshakeError
|
11
|
+
|
12
|
+
== 0.1.3 / 2010-07-18
|
13
|
+
|
14
|
+
- new features:
|
15
|
+
- onerror callback
|
16
|
+
- bugfixes:
|
17
|
+
- proper handling of zero spaces in key1 or key2(prevent ZeroDivisionError)
|
18
|
+
- convert received data to utf-8 to prevent ruby 1.9 errors
|
19
|
+
- fix handling of null bytes within a frame
|
20
|
+
|
21
|
+
== 0.1.2 / 2010-06-16
|
22
|
+
|
23
|
+
- new features:
|
24
|
+
- none
|
25
|
+
- bugfixes:
|
26
|
+
- allow $ character inside header key
|
27
|
+
|
28
|
+
== 0.1.1 / 2010-06-13
|
29
|
+
|
30
|
+
- new features:
|
31
|
+
- wss/ssl support
|
32
|
+
- bugfixes:
|
33
|
+
- can't & strings
|
34
|
+
|
35
|
+
== 0.1.0 / 2010-06-12
|
36
|
+
|
37
|
+
- initial release
|
data/README.rdoc
CHANGED
@@ -24,6 +24,24 @@ check out the blog post below:
|
|
24
24
|
end
|
25
25
|
}
|
26
26
|
|
27
|
+
== Secure server
|
28
|
+
|
29
|
+
It is possible to accept secure wss:// connections by passing :secure => true when opening the connection. Safari 5 does not currently support prompting on untrusted SSL certificates therefore using signed certificates is highly recommended. Pass a :tls_options hash containing keys as described in http://eventmachine.rubyforge.org/EventMachine/Connection.html#M000296
|
30
|
+
|
31
|
+
For example,
|
32
|
+
|
33
|
+
EventMachine::WebSocket.start({
|
34
|
+
:host => "0.0.0.0",
|
35
|
+
:port => 443
|
36
|
+
:secure => true,
|
37
|
+
:tls_options => {
|
38
|
+
:private_key_file => "/private/key",
|
39
|
+
:cert_chain_file => "/ssl/certificate"
|
40
|
+
}
|
41
|
+
}) do |ws|
|
42
|
+
...
|
43
|
+
end
|
44
|
+
|
27
45
|
== Examples
|
28
46
|
- examples/multicast.rb - broadcast all ruby tweets to all subscribers
|
29
47
|
- examples/echo.rb - server <> client exchange via a websocket
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.4
|
@@ -7,6 +7,10 @@ module EventMachine
|
|
7
7
|
|
8
8
|
attr_reader :state, :request
|
9
9
|
|
10
|
+
# Set the max frame lenth to very high value (10MB) until there is a
|
11
|
+
# limit specified in the spec to protect against malicious attacks
|
12
|
+
MAXIMUM_FRAME_LENGTH = 10 * 1024 * 1024
|
13
|
+
|
10
14
|
# define WebSocket callbacks
|
11
15
|
def onopen(&blk); @onopen = blk; end
|
12
16
|
def onclose(&blk); @onclose = blk; end
|
@@ -17,6 +21,7 @@ module EventMachine
|
|
17
21
|
@options = options
|
18
22
|
@debug = options[:debug] || false
|
19
23
|
@secure = options[:secure] || false
|
24
|
+
@tls_options = options[:tls_options] || {}
|
20
25
|
@state = :handshake
|
21
26
|
@request = {}
|
22
27
|
@data = ''
|
@@ -25,7 +30,7 @@ module EventMachine
|
|
25
30
|
end
|
26
31
|
|
27
32
|
def post_init
|
28
|
-
start_tls if @secure
|
33
|
+
start_tls(@tls_options) if @secure
|
29
34
|
end
|
30
35
|
|
31
36
|
def receive_data(data)
|
@@ -48,7 +53,7 @@ module EventMachine
|
|
48
53
|
handshake
|
49
54
|
when :connected
|
50
55
|
process_message
|
51
|
-
else raise
|
56
|
+
else raise WebSocketError, "invalid state: #{@state}"
|
52
57
|
end
|
53
58
|
end
|
54
59
|
|
@@ -118,6 +123,12 @@ module EventMachine
|
|
118
123
|
break unless (b & 0x80) == 0x80
|
119
124
|
end
|
120
125
|
|
126
|
+
# Addition to the spec to protect against malicious requests
|
127
|
+
if length > MAXIMUM_FRAME_LENGTH
|
128
|
+
close_with_error(DataError.new("Frame length too long (#{length} bytes)"))
|
129
|
+
return false
|
130
|
+
end
|
131
|
+
|
121
132
|
if @data[pointer+length-1] == nil
|
122
133
|
debug [:buffer_incomplete, @data.inspect]
|
123
134
|
# Incomplete data - leave @data to accumulate
|
@@ -170,6 +181,11 @@ module EventMachine
|
|
170
181
|
ary.collect{ |s| s.force_encoding('UTF-8') if s.respond_to?(:force_encoding) }
|
171
182
|
send_data(ary.join)
|
172
183
|
end
|
184
|
+
|
185
|
+
def close_with_error(message)
|
186
|
+
@onerror.call(message) if @onerror
|
187
|
+
close_connection_after_writing
|
188
|
+
end
|
173
189
|
end
|
174
190
|
end
|
175
191
|
end
|
data/lib/em-websocket/handler.rb
CHANGED
@@ -7,7 +7,7 @@ module EventMachine
|
|
7
7
|
TERMINATE_STRING = "\xff\x00"
|
8
8
|
|
9
9
|
def handshake
|
10
|
-
challenge_response =
|
10
|
+
challenge_response = solve_challenge(
|
11
11
|
@request['Sec-WebSocket-Key1'],
|
12
12
|
@request['Sec-WebSocket-Key2'],
|
13
13
|
@request['Third-Key']
|
@@ -36,7 +36,7 @@ module EventMachine
|
|
36
36
|
|
37
37
|
private
|
38
38
|
|
39
|
-
def
|
39
|
+
def solve_challenge(first, second, third)
|
40
40
|
# Refer to 5.2 4-9 of the draft 76
|
41
41
|
sum = [(extract_nums(first) / count_spaces(first))].pack("N*") +
|
42
42
|
[(extract_nums(second) / count_spaces(second))].pack("N*") +
|
@@ -12,6 +12,7 @@ module EventMachine
|
|
12
12
|
|
13
13
|
# extract request path
|
14
14
|
first_line = lines.shift.match(PATH)
|
15
|
+
raise HandshakeError, "Invalid HTTP header" unless first_line
|
15
16
|
request['Method'] = first_line[1].strip
|
16
17
|
request['Path'] = first_line[2].strip
|
17
18
|
|
@@ -44,7 +45,7 @@ module EventMachine
|
|
44
45
|
when 76
|
45
46
|
Handler76.new(request, response, debug)
|
46
47
|
else
|
47
|
-
raise "Must not happen"
|
48
|
+
raise WebSocketError, "Must not happen"
|
48
49
|
end
|
49
50
|
end
|
50
51
|
end
|
@@ -125,4 +125,43 @@ describe "WebSocket server draft76" do
|
|
125
125
|
end
|
126
126
|
end
|
127
127
|
end
|
128
|
+
|
129
|
+
it "should handle unreasonable frame lengths by calling onerror callback" do
|
130
|
+
EM.run do
|
131
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |server|
|
132
|
+
server.onerror { |error|
|
133
|
+
error.should be_an_instance_of EM::WebSocket::DataError
|
134
|
+
error.message.should == "Frame length too long (1180591620717411303296 bytes)"
|
135
|
+
EM.stop
|
136
|
+
}
|
137
|
+
}
|
138
|
+
|
139
|
+
# Create a fake client which sends draft 76 handshake
|
140
|
+
client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
141
|
+
client.send_data(format_request(@request))
|
142
|
+
|
143
|
+
# This particular frame indicates a message length of
|
144
|
+
# 1180591620717411303296 bytes. Such a message would previously cause
|
145
|
+
# a "bignum too big to convert into `long'" error.
|
146
|
+
# However it is clearly unreasonable and should be rejected.
|
147
|
+
client.onopen = lambda {
|
148
|
+
client.send_data("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00")
|
149
|
+
}
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should handle invalid http requests by raising HandshakeError passed to onerror callback" do
|
154
|
+
EM.run {
|
155
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |server|
|
156
|
+
server.onerror { |error|
|
157
|
+
error.should be_an_instance_of EM::WebSocket::HandshakeError
|
158
|
+
error.message.should == "Invalid HTTP header"
|
159
|
+
EM.stop
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
164
|
+
client.send_data("This is not a HTTP header")
|
165
|
+
}
|
166
|
+
end
|
128
167
|
end
|
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
|
+
- 4
|
9
|
+
version: 0.1.4
|
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-08-23 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -69,6 +69,7 @@ extra_rdoc_files:
|
|
69
69
|
- README.rdoc
|
70
70
|
files:
|
71
71
|
- .gitignore
|
72
|
+
- CHANGELOG.rdoc
|
72
73
|
- README.rdoc
|
73
74
|
- Rakefile
|
74
75
|
- VERSION
|