em-websocket 0.3.1 → 0.3.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/CHANGELOG.rdoc +7 -0
- data/examples/test.html +2 -1
- data/lib/em-websocket/connection.rb +13 -0
- data/lib/em-websocket/framing03.rb +11 -1
- data/lib/em-websocket/framing05.rb +9 -0
- data/lib/em-websocket/framing07.rb +2 -1
- data/lib/em-websocket/message_processor_03.rb +6 -1
- data/lib/em-websocket/message_processor_06.rb +6 -1
- data/lib/em-websocket/version.rb +1 -1
- data/spec/helper.rb +1 -1
- data/spec/integration/draft06_spec.rb +1 -0
- data/spec/integration/shared_examples.rb +29 -0
- data/spec/unit/framing_spec.rb +25 -0
- metadata +57 -64
data/CHANGELOG.rdoc
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
= Changelog
|
2
2
|
|
3
|
+
== 0.3.2 / 2011-10-09
|
4
|
+
|
5
|
+
- bugfixes:
|
6
|
+
- Handling of messages with > 2 frames
|
7
|
+
- Encode string passed to onmessage handler as UTF-8 on Ruby 1.9
|
8
|
+
- Add 10MB frame length limit to all draft versions
|
9
|
+
|
3
10
|
== 0.3.1 / 2011-07-28
|
4
11
|
|
5
12
|
- new features:
|
data/examples/test.html
CHANGED
@@ -12,7 +12,8 @@
|
|
12
12
|
element.appendChild(p);
|
13
13
|
}
|
14
14
|
|
15
|
-
|
15
|
+
var Socket = "MozWebSocket" in window ? MozWebSocket : WebSocket;
|
16
|
+
var ws = new Socket("ws://localhost:8080/");
|
16
17
|
ws.onmessage = function(evt) { debug("Message: " + evt.data); };
|
17
18
|
ws.onclose = function() { debug("socket closed"); };
|
18
19
|
ws.onopen = function() {
|
@@ -120,6 +120,19 @@ module EventMachine
|
|
120
120
|
end
|
121
121
|
|
122
122
|
def send(data)
|
123
|
+
# If we're using Ruby 1.9, be pedantic about encodings
|
124
|
+
if data.respond_to?(:force_encoding)
|
125
|
+
# Also accept ascii only data in other encodings for convenience
|
126
|
+
unless (data.encoding == Encoding.find("UTF-8") && data.valid_encoding?) || data.ascii_only?
|
127
|
+
raise WebSocketError, "Data sent to WebSocket must be valid UTF-8 but was #{data.encoding} (valid: #{data.valid_encoding?})"
|
128
|
+
end
|
129
|
+
# This labels the encoding as binary so that it can be combined with
|
130
|
+
# the BINARY framing
|
131
|
+
data.force_encoding("BINARY")
|
132
|
+
else
|
133
|
+
# TODO: Check that data is valid UTF-8
|
134
|
+
end
|
135
|
+
|
123
136
|
if @handler
|
124
137
|
@handler.send_text_frame(data)
|
125
138
|
else
|
@@ -4,6 +4,10 @@ module EventMachine
|
|
4
4
|
module WebSocket
|
5
5
|
module Framing03
|
6
6
|
|
7
|
+
# Set the max frame lenth to very high value (10MB) until there is a
|
8
|
+
# limit specified in the spec to protect against malicious attacks
|
9
|
+
MAXIMUM_FRAME_LENGTH = 10 * 1024 * 1024
|
10
|
+
|
7
11
|
def initialize_framing
|
8
12
|
@data = ''
|
9
13
|
@application_data_buffer = '' # Used for MORE frames
|
@@ -53,6 +57,11 @@ module EventMachine
|
|
53
57
|
length
|
54
58
|
end
|
55
59
|
|
60
|
+
# Addition to the spec to protect against malicious requests
|
61
|
+
if payload_length > MAXIMUM_FRAME_LENGTH
|
62
|
+
raise DataError, "Frame length too long (#{payload_length} bytes)"
|
63
|
+
end
|
64
|
+
|
56
65
|
# Check buffer size
|
57
66
|
if @data.getbyte(pointer+payload_length-1) == nil
|
58
67
|
debug [:buffer_incomplete, @data]
|
@@ -75,7 +84,8 @@ module EventMachine
|
|
75
84
|
if more
|
76
85
|
debug [:moreframe, frame_type, application_data]
|
77
86
|
@application_data_buffer << application_data
|
78
|
-
|
87
|
+
# The message type is passed in the first frame
|
88
|
+
@frame_type ||= frame_type
|
79
89
|
else
|
80
90
|
# Message is complete
|
81
91
|
if frame_type == :continuation
|
@@ -4,6 +4,10 @@ module EventMachine
|
|
4
4
|
module WebSocket
|
5
5
|
module Framing05
|
6
6
|
|
7
|
+
# Set the max frame lenth to very high value (10MB) until there is a
|
8
|
+
# limit specified in the spec to protect against malicious attacks
|
9
|
+
MAXIMUM_FRAME_LENGTH = 10 * 1024 * 1024
|
10
|
+
|
7
11
|
def initialize_framing
|
8
12
|
@data = MaskedString.new
|
9
13
|
@application_data_buffer = '' # Used for MORE frames
|
@@ -56,6 +60,11 @@ module EventMachine
|
|
56
60
|
length
|
57
61
|
end
|
58
62
|
|
63
|
+
# Addition to the spec to protect against malicious requests
|
64
|
+
if payload_length > MAXIMUM_FRAME_LENGTH
|
65
|
+
raise DataError, "Frame length too long (#{payload_length} bytes)"
|
66
|
+
end
|
67
|
+
|
59
68
|
# Check buffer size
|
60
69
|
if @data.getbyte(pointer+payload_length-1) == nil
|
61
70
|
debug [:buffer_incomplete, @data]
|
@@ -89,7 +89,8 @@ module EventMachine
|
|
89
89
|
if !fin
|
90
90
|
debug [:moreframe, frame_type, application_data]
|
91
91
|
@application_data_buffer << application_data
|
92
|
-
|
92
|
+
# The message type is passed in the first frame
|
93
|
+
@frame_type ||= frame_type
|
93
94
|
else
|
94
95
|
# Message is complete
|
95
96
|
if frame_type == :continuation
|
@@ -24,7 +24,12 @@ module EventMachine
|
|
24
24
|
send_frame(:pong, application_data)
|
25
25
|
when :pong
|
26
26
|
# TODO: Do something. Complete a deferrable established by a ping?
|
27
|
-
when :text
|
27
|
+
when :text
|
28
|
+
if application_data.respond_to?(:force_encoding)
|
29
|
+
application_data.force_encoding("UTF-8")
|
30
|
+
end
|
31
|
+
@connection.trigger_on_message(application_data)
|
32
|
+
when :binary
|
28
33
|
@connection.trigger_on_message(application_data)
|
29
34
|
end
|
30
35
|
end
|
@@ -37,7 +37,12 @@ module EventMachine
|
|
37
37
|
send_frame(:pong, application_data)
|
38
38
|
when :pong
|
39
39
|
# TODO: Do something. Complete a deferrable established by a ping?
|
40
|
-
when :text
|
40
|
+
when :text
|
41
|
+
if application_data.respond_to?(:force_encoding)
|
42
|
+
application_data.force_encoding("UTF-8")
|
43
|
+
end
|
44
|
+
@connection.trigger_on_message(application_data)
|
45
|
+
when :binary
|
41
46
|
@connection.trigger_on_message(application_data)
|
42
47
|
end
|
43
48
|
end
|
data/lib/em-websocket/version.rb
CHANGED
data/spec/helper.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
shared_examples_for "a websocket server" do
|
2
4
|
it "should call onerror if an application error raised in onopen" do
|
3
5
|
EM.run {
|
@@ -59,4 +61,31 @@ shared_examples_for "a websocket server" do
|
|
59
61
|
}
|
60
62
|
}
|
61
63
|
end
|
64
|
+
|
65
|
+
# Only run these tests on ruby 1.9
|
66
|
+
if "a".respond_to?(:force_encoding)
|
67
|
+
it "should raise error if you try to send non utf8 text data to ws" do
|
68
|
+
EM.run do
|
69
|
+
start_server { |server|
|
70
|
+
server.onopen {
|
71
|
+
# Create a string which claims to be UTF-8 but which is not
|
72
|
+
s = "ê" # utf-8 string
|
73
|
+
s.encode!("ISO-8859-1")
|
74
|
+
s.force_encoding("UTF-8")
|
75
|
+
s.valid_encoding?.should == false # now invalid utf8
|
76
|
+
|
77
|
+
# Send non utf8 encoded data
|
78
|
+
server.send(s)
|
79
|
+
}
|
80
|
+
server.onerror { |error|
|
81
|
+
error.class.should == EventMachine::WebSocket::WebSocketError
|
82
|
+
error.message.should == "Data sent to WebSocket must be valid UTF-8 but was UTF-8 (valid: false)"
|
83
|
+
EM.stop
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
start_client { }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
62
91
|
end
|
data/spec/unit/framing_spec.rb
CHANGED
@@ -96,6 +96,15 @@ describe EM::WebSocket::Framing03 do
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
+
describe "other tests" do
|
100
|
+
it "should accept a fragmented unmasked text message in 3 frames" do
|
101
|
+
@f.should_receive(:message).with(:text, '', 'Hello world')
|
102
|
+
@f << "\x84\x03Hel"
|
103
|
+
@f << "\x80\x02lo"
|
104
|
+
@f << "\x00\x06 world"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
99
108
|
describe "error cases" do
|
100
109
|
it "should raise an exception on continuation frame without preceeding more frame" do
|
101
110
|
lambda {
|
@@ -160,6 +169,15 @@ describe EM::WebSocket::Framing04 do
|
|
160
169
|
@f << "\x85\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data
|
161
170
|
end
|
162
171
|
end
|
172
|
+
|
173
|
+
describe "other tests" do
|
174
|
+
it "should accept a fragmented unmasked text message in 3 frames" do
|
175
|
+
@f.should_receive(:message).with(:text, '', 'Hello world')
|
176
|
+
@f << "\x04\x03Hel"
|
177
|
+
@f << "\x00\x02lo"
|
178
|
+
@f << "\x80\x06 world"
|
179
|
+
end
|
180
|
+
end
|
163
181
|
end
|
164
182
|
|
165
183
|
describe EM::WebSocket::Framing07 do
|
@@ -228,5 +246,12 @@ describe EM::WebSocket::Framing07 do
|
|
228
246
|
@f << "\x83\x05Hello"
|
229
247
|
}.should raise_error(EventMachine::WebSocket::DataError, "Unknown opcode")
|
230
248
|
end
|
249
|
+
|
250
|
+
it "should accept a fragmented unmasked text message in 3 frames" do
|
251
|
+
@f.should_receive(:message).with(:text, '', 'Hello world')
|
252
|
+
@f << "\x01\x03Hel"
|
253
|
+
@f << "\x00\x02lo"
|
254
|
+
@f << "\x80\x06 world"
|
255
|
+
end
|
231
256
|
end
|
232
257
|
end
|
metadata
CHANGED
@@ -1,83 +1,80 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-websocket
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.2
|
4
5
|
prerelease:
|
5
|
-
version: 0.3.1
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Ilya Grigorik
|
9
|
+
- Martyn Loughran
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
dependencies:
|
16
|
-
- !ruby/object:Gem::Dependency
|
13
|
+
date: 2011-10-17 00:00:00.000000000Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
17
16
|
name: eventmachine
|
18
|
-
|
19
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
17
|
+
requirement: &70120715076200 !ruby/object:Gem::Requirement
|
20
18
|
none: false
|
21
|
-
requirements:
|
22
|
-
- -
|
23
|
-
- !ruby/object:Gem::Version
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
24
22
|
version: 0.12.9
|
25
23
|
type: :runtime
|
26
|
-
version_requirements: *id001
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: addressable
|
29
24
|
prerelease: false
|
30
|
-
|
25
|
+
version_requirements: *70120715076200
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: addressable
|
28
|
+
requirement: &70120715061040 !ruby/object:Gem::Requirement
|
31
29
|
none: false
|
32
|
-
requirements:
|
33
|
-
- -
|
34
|
-
- !ruby/object:Gem::Version
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
35
33
|
version: 2.1.1
|
36
34
|
type: :runtime
|
37
|
-
version_requirements: *id002
|
38
|
-
- !ruby/object:Gem::Dependency
|
39
|
-
name: em-http-request
|
40
35
|
prerelease: false
|
41
|
-
|
36
|
+
version_requirements: *70120715061040
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: em-http-request
|
39
|
+
requirement: &70120715060520 !ruby/object:Gem::Requirement
|
42
40
|
none: false
|
43
|
-
requirements:
|
41
|
+
requirements:
|
44
42
|
- - ~>
|
45
|
-
- !ruby/object:Gem::Version
|
43
|
+
- !ruby/object:Gem::Version
|
46
44
|
version: 0.2.6
|
47
45
|
type: :development
|
48
|
-
version_requirements: *id003
|
49
|
-
- !ruby/object:Gem::Dependency
|
50
|
-
name: rspec
|
51
46
|
prerelease: false
|
52
|
-
|
47
|
+
version_requirements: *70120715060520
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: rspec
|
50
|
+
requirement: &70120715059920 !ruby/object:Gem::Requirement
|
53
51
|
none: false
|
54
|
-
requirements:
|
52
|
+
requirements:
|
55
53
|
- - ~>
|
56
|
-
- !ruby/object:Gem::Version
|
54
|
+
- !ruby/object:Gem::Version
|
57
55
|
version: 2.5.0
|
58
56
|
type: :development
|
59
|
-
version_requirements: *id004
|
60
|
-
- !ruby/object:Gem::Dependency
|
61
|
-
name: rake
|
62
57
|
prerelease: false
|
63
|
-
|
58
|
+
version_requirements: *70120715059920
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: rake
|
61
|
+
requirement: &70120715059420 !ruby/object:Gem::Requirement
|
64
62
|
none: false
|
65
|
-
requirements:
|
66
|
-
- -
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version:
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
69
67
|
type: :development
|
70
|
-
|
68
|
+
prerelease: false
|
69
|
+
version_requirements: *70120715059420
|
71
70
|
description: EventMachine based WebSocket server
|
72
|
-
email:
|
71
|
+
email:
|
73
72
|
- ilya@igvita.com
|
73
|
+
- me@mloughran.com
|
74
74
|
executables: []
|
75
|
-
|
76
75
|
extensions: []
|
77
|
-
|
78
76
|
extra_rdoc_files: []
|
79
|
-
|
80
|
-
files:
|
77
|
+
files:
|
81
78
|
- .gitignore
|
82
79
|
- CHANGELOG.rdoc
|
83
80
|
- Gemfile
|
@@ -131,35 +128,31 @@ files:
|
|
131
128
|
- spec/unit/framing_spec.rb
|
132
129
|
- spec/unit/handler_spec.rb
|
133
130
|
- spec/unit/masking_spec.rb
|
134
|
-
has_rdoc: true
|
135
131
|
homepage: http://github.com/igrigorik/em-websocket
|
136
132
|
licenses: []
|
137
|
-
|
138
133
|
post_install_message:
|
139
134
|
rdoc_options: []
|
140
|
-
|
141
|
-
require_paths:
|
135
|
+
require_paths:
|
142
136
|
- lib
|
143
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
137
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
144
138
|
none: false
|
145
|
-
requirements:
|
146
|
-
- -
|
147
|
-
- !ruby/object:Gem::Version
|
148
|
-
version:
|
149
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - ! '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
144
|
none: false
|
151
|
-
requirements:
|
152
|
-
- -
|
153
|
-
- !ruby/object:Gem::Version
|
154
|
-
version:
|
145
|
+
requirements:
|
146
|
+
- - ! '>='
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: '0'
|
155
149
|
requirements: []
|
156
|
-
|
157
150
|
rubyforge_project: em-websocket
|
158
|
-
rubygems_version: 1.6
|
151
|
+
rubygems_version: 1.8.6
|
159
152
|
signing_key:
|
160
153
|
specification_version: 3
|
161
154
|
summary: EventMachine based WebSocket server
|
162
|
-
test_files:
|
155
|
+
test_files:
|
163
156
|
- spec/helper.rb
|
164
157
|
- spec/integration/common_spec.rb
|
165
158
|
- spec/integration/draft03_spec.rb
|