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.
@@ -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