em-websocket 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 623f09b2677a73143c0f625ba3b516a00219103e
4
- data.tar.gz: 0ebcdd8490811e0b69a64262b2a63daeb8d6aa14
2
+ SHA256:
3
+ metadata.gz: b5ae1d6db2d88e23c98fce247af5c18d9af7343d196cc85224d2d62e6f39cf6b
4
+ data.tar.gz: eff929c27eb3949705cf0e5438af33c7b05612c5e5deedaf2ea39a81f0308559
5
5
  SHA512:
6
- metadata.gz: aad00490beaf8c9ae3606dc506d111c7d60c1f83c6b08c93ebbafd9d877f3c7a7ec2273cbb0a3d97f59d7fb749e4a6f157cdc1a53f4bab88c21cb6eb99605435
7
- data.tar.gz: 002ff0471519223522a43a3e865272af61c033960d4a74506080b551d8b01f3cc73471c4b19d677b7c3f90c76b8022c34aa5fbb0b4a3b348b37102b1a3ad597e
6
+ metadata.gz: 301e06c551ea5414cd463a606fc709676932094bdf92743555cf5ecccb20fb0c0d7abe14c19a61942337ea8c60053bd59d7b31841178df9f05dbae3c6e66232f
7
+ data.tar.gz: 5020a0dd90126780266b55c197acadcbabc40044e5513b4461f4f4d9500d9ace38646c931aeb19fd638b852a68346b5cb44c48b9cc5e5b5f2e96e3a80ff2cbf4
data/Gemfile CHANGED
@@ -5,5 +5,5 @@ gemspec
5
5
  gem "em-websocket-client", git: "git@github.com:movitto/em-websocket-client.git", branch: "expose-websocket-api"
6
6
  gem "em-spec", "~> 0.2.6"
7
7
  gem "em-http-request", "~> 1.1.1"
8
- gem "rspec", "~> 2.12.0"
8
+ gem "rspec", "~> 3.5.0"
9
9
  gem "rake"
data/LICENCE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2009-2014 Ilya Grigorik, Martyn Loughran
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -73,7 +73,7 @@ If unsure use a code in the 4xxx range. em-websocket may also close a connection
73
73
 
74
74
  ## Secure server
75
75
 
76
- It is possible to accept secure `wss://` connections by passing `:secure => true` when opening the connection. Pass a `:tls_options` hash containing keys as described in http://eventmachine.rubyforge.org/EventMachine/Connection.html#start_tls-instance_method
76
+ It is possible to accept secure `wss://` connections by passing `:secure => true` when opening the connection. Pass a `:tls_options` hash containing keys as described in http://www.rubydoc.info/github/eventmachine/eventmachine/EventMachine/Connection:start_tls
77
77
 
78
78
  **Warning**: Safari 5 does not currently support prompting on untrusted SSL certificates therefore using a self signed certificate may leave you scratching your head.
79
79
 
@@ -140,7 +140,3 @@ Using flash emulation does require some minimal support from em-websocket which
140
140
  * [Twitter AMQP WebSocket Example](http://github.com/rubenfonseca/twitter-amqp-websocket-example)
141
141
  * examples/multicast.rb - broadcast all ruby tweets to all subscribers
142
142
  * examples/echo.rb - server <> client exchange via a websocket
143
-
144
- # License
145
-
146
- The MIT License - Copyright (c) 2009-2013 Ilya Grigorik, Martyn Loughran
@@ -45,6 +45,7 @@ module EventMachine
45
45
  @secure_proxy = options[:secure_proxy] || false
46
46
  @tls_options = options[:tls_options] || {}
47
47
  @close_timeout = options[:close_timeout]
48
+ @outbound_limit = options[:outbound_limit] || 0
48
49
 
49
50
  @handler = nil
50
51
 
@@ -88,6 +89,16 @@ module EventMachine
88
89
  trigger_on_error(e) || raise(e)
89
90
  end
90
91
 
92
+ def send_data(data)
93
+ if @outbound_limit > 0 &&
94
+ get_outbound_data_size + data.bytesize > @outbound_limit
95
+ abort(:outbound_limit_reached)
96
+ return 0
97
+ end
98
+
99
+ super(data)
100
+ end
101
+
91
102
  def unbind
92
103
  debug [:unbind, :connection]
93
104
 
@@ -99,7 +110,9 @@ module EventMachine
99
110
  end
100
111
 
101
112
  def dispatch(data)
102
- if data.match(/\A<policy-file-request\s*\/>/)
113
+ if data.match(%r|^GET /healthcheck|)
114
+ send_healthcheck_response
115
+ elsif data.match(/\A<policy-file-request\s*\/>/)
103
116
  send_flash_cross_domain_file
104
117
  else
105
118
  @handshake ||= begin
@@ -118,7 +131,7 @@ module EventMachine
118
131
  debug [:error, e]
119
132
  trigger_on_error(e)
120
133
  # Handshake errors require the connection to be aborted
121
- abort
134
+ abort(:handshake_error)
122
135
  }
123
136
 
124
137
  handshake
@@ -128,6 +141,23 @@ module EventMachine
128
141
  end
129
142
  end
130
143
 
144
+ def send_healthcheck_response
145
+ debug [:healthcheck, 'OK']
146
+
147
+ healthcheck_res = ["HTTP/1.1 200 OK"]
148
+ healthcheck_res << "Content-Type: text/plain"
149
+ healthcheck_res << "Content-Length: 2"
150
+
151
+ healthcheck_res = healthcheck_res.join("\r\n") + "\r\n\r\nOK"
152
+
153
+ send_data healthcheck_res
154
+
155
+ # handle the healthcheck request transparently
156
+ # no need to notify the user about this connection
157
+ @onclose = nil
158
+ close_connection_after_writing
159
+ end
160
+
131
161
  def send_flash_cross_domain_file
132
162
  file = '<?xml version="1.0"?><cross-domain-policy><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>'
133
163
  debug [:cross_domain, file]
@@ -236,6 +266,11 @@ module EventMachine
236
266
  @handler ? @handler.state : :handshake
237
267
  end
238
268
 
269
+ # Returns the IP address for the remote peer
270
+ def remote_ip
271
+ get_peername[2,6].unpack('nC4')[1..4].join('.')
272
+ end
273
+
239
274
  # Returns the maximum frame size which this connection is configured to
240
275
  # accept. This can be set globally or on a per connection basis, and
241
276
  # defaults to a value of 10MB if not set.
@@ -256,7 +291,8 @@ module EventMachine
256
291
 
257
292
  # As definited in draft 06 7.2.2, some failures require that the server
258
293
  # abort the websocket connection rather than close cleanly
259
- def abort
294
+ def abort(reason)
295
+ debug [:abort, reason]
260
296
  close_connection
261
297
  end
262
298
 
@@ -266,7 +302,7 @@ module EventMachine
266
302
  @handler.close_websocket(code, body)
267
303
  else
268
304
  # The handshake hasn't completed - should be safe to terminate
269
- abort
305
+ abort(:handshake_incomplete)
270
306
  end
271
307
  end
272
308
 
@@ -17,12 +17,21 @@ module EventMachine
17
17
  upgrade << "Upgrade: websocket"
18
18
  upgrade << "Connection: Upgrade"
19
19
  upgrade << "Sec-WebSocket-Accept: #{signature}"
20
+ if protocol = headers['sec-websocket-protocol']
21
+ validate_protocol!(protocol)
22
+ upgrade << "Sec-WebSocket-Protocol: #{protocol}"
23
+ end
20
24
 
21
- # TODO: Support sec-websocket-protocol
25
+ # TODO: Support sec-websocket-protocol selection
22
26
  # TODO: sec-websocket-extensions
23
27
 
24
28
  return upgrade.join("\r\n") + "\r\n\r\n"
25
29
  end
30
+
31
+ def self.validate_protocol!(protocol)
32
+ raise HandshakeError, "Invalid WebSocket-Protocol: empty" if protocol.empty?
33
+ # TODO: Validate characters
34
+ end
26
35
  end
27
36
  end
28
37
  end
@@ -9,10 +9,20 @@ module EventMachine
9
9
  upgrade << "Upgrade: WebSocket\r\n"
10
10
  upgrade << "Connection: Upgrade\r\n"
11
11
  upgrade << "WebSocket-Origin: #{headers['origin']}\r\n"
12
- upgrade << "WebSocket-Location: #{location}\r\n\r\n"
12
+ upgrade << "WebSocket-Location: #{location}\r\n"
13
+ if protocol = headers['sec-websocket-protocol']
14
+ validate_protocol!(protocol)
15
+ upgrade << "Sec-WebSocket-Protocol: #{protocol}\r\n"
16
+ end
17
+ upgrade << "\r\n"
13
18
 
14
19
  return upgrade
15
20
  end
21
+
22
+ def self.validate_protocol!(protocol)
23
+ raise HandshakeError, "Invalid WebSocket-Protocol: empty" if protocol.empty?
24
+ # TODO: Validate characters
25
+ end
16
26
  end
17
27
  end
18
28
  end
@@ -37,8 +37,22 @@ module EventMachine
37
37
  @connection.close_connection_after_writing
38
38
  end
39
39
  when :ping
40
- # Pong back the same data
41
- send_frame(:pong, application_data)
40
+ # There are a couple of protections here against malicious/broken WebSocket abusing ping frames.
41
+ #
42
+ # 1. Delay 200ms before replying. This reduces the number of pings from WebSocket clients behaving as
43
+ # `for (;;) { send_ping(conn); rcv_pong(conn); }`. The spec says we "SHOULD respond with Pong frame as soon
44
+ # as is practical".
45
+ # 2. Reply at most every 200ms. This reduces the number of pong frames sent to WebSocket clients behaving as
46
+ # `for (;;) { send_ping(conn); }`. The spec says "If an endpoint receives a Ping frame and has not yet sent
47
+ # Pong frame(s) in response to previous Ping frame(s), the endpoint MAY elect to send a Pong frame for only
48
+ # the most recently processed Ping frame."
49
+ @most_recent_pong_application_data = application_data
50
+ if @pong_timer == nil then
51
+ @pong_timer = EventMachine.add_timer(0.2) do
52
+ @pong_timer = nil
53
+ send_frame(:pong, @most_recent_pong_application_data)
54
+ end
55
+ end
42
56
  @connection.trigger_on_ping(application_data)
43
57
  when :pong
44
58
  @connection.trigger_on_pong(application_data)
@@ -1,5 +1,5 @@
1
1
  module EventMachine
2
2
  module Websocket
3
- VERSION = "0.5.1"
3
+ VERSION = "0.5.2"
4
4
  end
5
5
  end
@@ -108,4 +108,31 @@ describe "WebSocket server" do
108
108
  end
109
109
  }
110
110
  end
111
+
112
+ context "outbound limit set" do
113
+ it "should close the connection if the limit is reached" do
114
+ em {
115
+ start_server(:outbound_limit => 150) do |ws|
116
+ # Increase the message size by one on each loop
117
+ ws.onmessage{|msg| ws.send(msg + "x") }
118
+ ws.onclose{|status|
119
+ status[:code].should == 1006 # Unclean
120
+ status[:was_clean].should be false
121
+ }
122
+ end
123
+
124
+ EM.add_timer(0.1) do
125
+ ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/')
126
+ ws.callback { ws.send_msg "hello" }
127
+ ws.disconnect { done } # Server closed the connection
128
+ ws.stream { |msg|
129
+ # minus frame size ? (getting 146 max here)
130
+ msg.data.size.should <= 150
131
+ # Return back the message
132
+ ws.send_msg(msg.data)
133
+ }
134
+ end
135
+ }
136
+ end
137
+ end
111
138
  end
@@ -26,6 +26,7 @@ describe "draft06" do
26
26
  "Upgrade" => "websocket",
27
27
  "Connection" => "Upgrade",
28
28
  "Sec-WebSocket-Accept" => "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
29
+ "Sec-WebSocket-Protocol" => "sample",
29
30
  }
30
31
  }
31
32
  end
@@ -28,6 +28,7 @@ describe "draft13" do
28
28
  "Upgrade" => "websocket",
29
29
  "Connection" => "Upgrade",
30
30
  "Sec-WebSocket-Accept" => "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
31
+ "Sec-WebSocket-Protocol" => "sample",
31
32
  }
32
33
  }
33
34
  end
@@ -29,6 +29,19 @@ shared_examples_for "a websocket server" do
29
29
  }
30
30
  end
31
31
 
32
+ it "should expose the remote IP address" do
33
+ em {
34
+ start_server { |ws|
35
+ ws.onopen {
36
+ ws.remote_ip.should == "127.0.0.1"
37
+ done
38
+ }
39
+ }
40
+
41
+ start_client
42
+ }
43
+ end
44
+
32
45
  it "should send messages successfully" do
33
46
  em {
34
47
  start_server { |ws|
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: em-websocket
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ilya Grigorik
8
8
  - Martyn Loughran
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-04-23 00:00:00.000000000 Z
12
+ date: 2020-09-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
@@ -50,6 +50,7 @@ files:
50
50
  - ".gitignore"
51
51
  - CHANGELOG.rdoc
52
52
  - Gemfile
53
+ - LICENCE
53
54
  - README.md
54
55
  - Rakefile
55
56
  - em-websocket.gemspec
@@ -101,9 +102,10 @@ files:
101
102
  - spec/unit/handshake_spec.rb
102
103
  - spec/unit/masking_spec.rb
103
104
  homepage: http://github.com/igrigorik/em-websocket
104
- licenses: []
105
+ licenses:
106
+ - MIT
105
107
  metadata: {}
106
- post_install_message:
108
+ post_install_message:
107
109
  rdoc_options: []
108
110
  require_paths:
109
111
  - lib
@@ -118,9 +120,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
120
  - !ruby/object:Gem::Version
119
121
  version: '0'
120
122
  requirements: []
121
- rubyforge_project: em-websocket
122
- rubygems_version: 2.2.2
123
- signing_key:
123
+ rubygems_version: 3.0.3
124
+ signing_key:
124
125
  specification_version: 4
125
126
  summary: EventMachine based WebSocket server
126
127
  test_files: