em-websocket 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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:
@@ -12,7 +12,8 @@
12
12
  element.appendChild(p);
13
13
  }
14
14
 
15
- ws = new WebSocket("ws://localhost:8080/");
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
- @frame_type = frame_type
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
- @frame_type = frame_type
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, :binary
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, :binary
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
@@ -1,5 +1,5 @@
1
1
  module EventMachine
2
2
  module Websocket
3
- VERSION = "0.3.1"
3
+ VERSION = "0.3.2"
4
4
  end
5
5
  end
@@ -5,7 +5,7 @@ require 'em-http'
5
5
 
6
6
  require 'em-websocket'
7
7
 
8
- Rspec.configure do |c|
8
+ RSpec.configure do |c|
9
9
  c.mock_with :rspec
10
10
  end
11
11
 
@@ -62,6 +62,7 @@ describe "draft06" do
62
62
  start_server { |server|
63
63
  server.onmessage { |msg|
64
64
  msg.should == 'Hello'
65
+ msg.encoding.should == Encoding.find("UTF-8")
65
66
  EM.stop
66
67
  }
67
68
  server.onerror {
@@ -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
@@ -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
- date: 2011-07-28 00:00:00 +01:00
14
- default_executable:
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
- prerelease: false
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
- requirement: &id002 !ruby/object:Gem::Requirement
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
- requirement: &id003 !ruby/object:Gem::Requirement
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
- requirement: &id004 !ruby/object:Gem::Requirement
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
- requirement: &id005 !ruby/object:Gem::Requirement
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: "0"
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
69
67
  type: :development
70
- version_requirements: *id005
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: "0"
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: "0"
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.2
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