websocket 1.2.3 → 1.2.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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -0
  3. data/.travis.yml +14 -3
  4. data/CHANGELOG.md +4 -0
  5. data/Gemfile +0 -4
  6. data/README.md +1 -0
  7. data/Rakefile +6 -3
  8. data/lib/websocket/error.rb +6 -0
  9. data/lib/websocket/frame/base.rb +2 -2
  10. data/lib/websocket/frame/data.rb +1 -1
  11. data/lib/websocket/frame/handler/base.rb +2 -2
  12. data/lib/websocket/frame/handler/handler03.rb +12 -12
  13. data/lib/websocket/frame/handler/handler07.rb +8 -8
  14. data/lib/websocket/frame/handler/handler75.rb +6 -6
  15. data/lib/websocket/frame/outgoing.rb +1 -1
  16. data/lib/websocket/handshake/base.rb +13 -3
  17. data/lib/websocket/handshake/client.rb +15 -14
  18. data/lib/websocket/handshake/handler/client04.rb +12 -2
  19. data/lib/websocket/handshake/handler/client75.rb +15 -0
  20. data/lib/websocket/handshake/handler/client76.rb +11 -2
  21. data/lib/websocket/handshake/handler/server04.rb +8 -2
  22. data/lib/websocket/handshake/handler/server75.rb +7 -1
  23. data/lib/websocket/handshake/handler/server76.rb +10 -6
  24. data/lib/websocket/handshake/server.rb +5 -4
  25. data/lib/websocket/version.rb +1 -1
  26. data/spec/frame/outgoing_03_spec.rb +1 -1
  27. data/spec/frame/outgoing_04_spec.rb +1 -1
  28. data/spec/handshake/client_04_spec.rb +41 -0
  29. data/spec/handshake/client_75_spec.rb +25 -0
  30. data/spec/handshake/client_76_spec.rb +25 -0
  31. data/spec/handshake/server_04_spec.rb +32 -1
  32. data/spec/handshake/server_75_spec.rb +22 -0
  33. data/spec/handshake/server_76_spec.rb +22 -0
  34. data/spec/support/handshake_requests.rb +3 -3
  35. data/spec/support/incoming_frames.rb +15 -13
  36. data/websocket.gemspec +5 -0
  37. metadata +60 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 48ee0f12aaa5fd6aba76f7c2070a09f600c53204
4
- data.tar.gz: d011719667dc6227eecf743a764d0f24f7bf17b2
3
+ metadata.gz: 4bf1d6b28aadb7224c53978094d179673364550a
4
+ data.tar.gz: 0d376d27450259b680f585c8ff9dc56a7d3e5210
5
5
  SHA512:
6
- metadata.gz: 568b9cd4986500c8c9ddf5ec2d8f90b81b654fd6b10451480209ca505be73e0d8a24b11b10040aa7bd3211c84bf6c25154482655985a117705657e75eb302e0f
7
- data.tar.gz: 3c3c8d8c324b480654891f7326f1cf7153dbf3f7b4838c1b3ad2bbe670ba25c57dc2485092b049f5d5fd35b1f131a63882a46b989f684fc40a3925fc3d2024bb
6
+ metadata.gz: 0ab8110e8e84a36c606da58933b48b89e9df724dc145b4ac4d7cbe36f51c6c56f02ece9ad077103be2fba3d4c617c19692f0a2e1934037a39bf50bb47c81c6c1
7
+ data.tar.gz: 7239ff151df05fb67c67a713c6485377a1e0ab13446a945cef84497979aab255c18a09eaa794cc068da59e44d9f7f536af6d8bfe8dc75cd8fa3d70d1b9f43dcf
@@ -1,3 +1,6 @@
1
+ AllCops:
2
+ DisplayCopNames: true
3
+
1
4
  # Target: 15
2
5
  Metrics/AbcSize:
3
6
  Max: 24
@@ -5,6 +8,10 @@ Metrics/AbcSize:
5
8
  - lib/websocket/frame/handler/handler75.rb
6
9
  - spec/**/*
7
10
 
11
+ Metrics/BlockLength:
12
+ Exclude:
13
+ - spec/**/*
14
+
8
15
  Metrics/ClassLength:
9
16
  Enabled: false
10
17
 
@@ -1,12 +1,23 @@
1
1
  language: ruby
2
- script: "bundle exec rake spec"
2
+ script: "bundle exec rake"
3
3
  rvm:
4
4
  - 1.9.3
5
5
  - 2.0
6
6
  - 2.1
7
7
  - 2.2
8
- - rbx-2
9
- - jruby-19mode
8
+ - 2.3
10
9
  - ruby-head
10
+ - jruby
11
+ - jruby-head
12
+ - rbx
13
+ - rbx-head
14
+
15
+ matrix:
16
+ allow_failures:
17
+ - rvm: ruby-head
18
+ - rvm: jruby-head
19
+ - rvm: rbx
20
+ - rvm: rbx-head
21
+
11
22
  before_install:
12
23
  - gem install bundler
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.4
4
+
5
+ - add subprotocol handling for both server and client
6
+
3
7
  ## 1.2.3
4
8
 
5
9
  - fix for draft 76 when challenge might sometimes fail
data/Gemfile CHANGED
@@ -1,7 +1,3 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
3
  gemspec
4
-
5
- gem 'rake'
6
- gem 'rspec', '~> 3.0.0'
7
- gem 'rspec-its'
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  Universal Ruby library to handle WebSocket protocol. It focuses on providing abstraction layer over [WebSocket API](http://dev.w3.org/html5/websockets/) instead of providing server or client functionality.
4
4
 
5
5
  [![Gem Version](https://badge.fury.io/rb/websocket.svg)](http://badge.fury.io/rb/websocket)
6
+ [![Gem Downloads](https://img.shields.io/gem/dt/websocket.svg?maxAge=2592000)](https://rubygems.org/gems/websocket)
6
7
  [![Travis CI](https://travis-ci.org/imanel/websocket-ruby.png)](http://travis-ci.org/imanel/websocket-ruby)
7
8
  [![Code Climate](https://codeclimate.com/github/imanel/websocket-ruby.png)](https://codeclimate.com/github/imanel/websocket-ruby)
8
9
 
data/Rakefile CHANGED
@@ -1,14 +1,17 @@
1
1
  require 'bundler'
2
- Bundler::GemHelper.install_tasks
3
-
4
2
  require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ Bundler::GemHelper.install_tasks
5
6
 
6
7
  RSpec::Core::RakeTask.new do |t|
7
8
  t.rspec_opts = ['-c', '-f progress']
8
9
  t.pattern = 'spec/**/*_spec.rb'
9
10
  end
10
11
 
11
- task default: :spec
12
+ RuboCop::RakeTask.new
13
+
14
+ task default: [:spec, :rubocop]
12
15
 
13
16
  namespace :autobahn do
14
17
  desc 'Run autobahn tests for client'
@@ -99,6 +99,12 @@ module WebSocket
99
99
  end
100
100
  end
101
101
 
102
+ class UnsupportedProtocol < ::WebSocket::Error::Handshake
103
+ def message
104
+ :unsupported_protocol
105
+ end
106
+ end
107
+
102
108
  class InvalidStatusCode < ::WebSocket::Error::Handshake
103
109
  def message
104
110
  :invalid_status_code
@@ -36,7 +36,7 @@ module WebSocket
36
36
 
37
37
  # Implement in submodules
38
38
  def supported_frames
39
- fail NotImplementedError
39
+ raise NotImplementedError
40
40
  end
41
41
 
42
42
  # Recreate inspect as #to_s was overwritten
@@ -58,7 +58,7 @@ module WebSocket
58
58
  when 4 then Handler::Handler04.new(self)
59
59
  when 5..6 then Handler::Handler05.new(self)
60
60
  when 7..13 then Handler::Handler07.new(self)
61
- else fail WebSocket::Error::Frame::UnknownVersion
61
+ else raise WebSocket::Error::Frame::UnknownVersion
62
62
  end
63
63
  end
64
64
  end
@@ -16,7 +16,7 @@ module WebSocket
16
16
 
17
17
  # Extract mask from 4 first bytes according to spec
18
18
  def set_mask
19
- fail WebSocket::Error::Frame::MaskTooShort if bytesize < 4
19
+ raise WebSocket::Error::Frame::MaskTooShort if bytesize < 4
20
20
  @masking_key = self[0..3].bytes.to_a
21
21
  end
22
22
 
@@ -9,13 +9,13 @@ module WebSocket
9
9
  # Convert data to raw frame ready to send to client
10
10
  # @return [String] Encoded frame
11
11
  def encode_frame
12
- fail NotImplementedError
12
+ raise NotImplementedError
13
13
  end
14
14
 
15
15
  # Convert raw data to decoded frame
16
16
  # @return [WebSocket::Frame::Incoming] Frame if found, nil otherwise
17
17
  def decode_frame
18
- fail NotImplementedError
18
+ raise NotImplementedError
19
19
  end
20
20
 
21
21
  private
@@ -13,10 +13,10 @@ module WebSocket
13
13
  pong: 3,
14
14
  text: 4,
15
15
  binary: 5
16
- }
16
+ }.freeze
17
17
 
18
18
  # Hash of frame opcodes and it's names
19
- FRAME_TYPES_INVERSE = FRAME_TYPES.invert
19
+ FRAME_TYPES_INVERSE = FRAME_TYPES.invert.freeze
20
20
 
21
21
  # @see WebSocket::Frame::Base#supported_frames
22
22
  def supported_frames
@@ -50,7 +50,7 @@ module WebSocket
50
50
  elsif frame_type == :continuation
51
51
  return decode_finish_continuation_frame(application_data)
52
52
  else
53
- fail(WebSocket::Error::Frame::InvalidPayloadEncoding) if frame_type == :text && !application_data.valid_encoding?
53
+ raise(WebSocket::Error::Frame::InvalidPayloadEncoding) if frame_type == :text && !application_data.valid_encoding?
54
54
  return @frame.class.new(version: @frame.version, type: frame_type, data: application_data, decoded: true)
55
55
  end
56
56
  end
@@ -74,7 +74,7 @@ module WebSocket
74
74
  # @return [Integer] opcode or nil
75
75
  # @raise [WebSocket::Error] if frame opcode is not known
76
76
  def type_to_opcode(frame_type)
77
- FRAME_TYPES[frame_type] || fail(WebSocket::Error::Frame::UnknownFrameType)
77
+ FRAME_TYPES[frame_type] || raise(WebSocket::Error::Frame::UnknownFrameType)
78
78
  end
79
79
 
80
80
  # Convert frame opcode to type name
@@ -82,7 +82,7 @@ module WebSocket
82
82
  # @return [Symbol] Frame type name or nil
83
83
  # @raise [WebSocket::Error] if frame type name is not known
84
84
  def opcode_to_type(opcode)
85
- FRAME_TYPES_INVERSE[opcode] || fail(WebSocket::Error::Frame::UnknownOpcode)
85
+ FRAME_TYPES_INVERSE[opcode] || raise(WebSocket::Error::Frame::UnknownOpcode)
86
86
  end
87
87
 
88
88
  def encode_header
@@ -117,7 +117,7 @@ module WebSocket
117
117
  frame_length = header_length + payload_length
118
118
  frame_length += 4 if mask
119
119
 
120
- fail(WebSocket::Error::Frame::TooLong) if frame_length > WebSocket.max_frame_size
120
+ raise(WebSocket::Error::Frame::TooLong) if frame_length > WebSocket.max_frame_size
121
121
 
122
122
  # Check buffer size
123
123
  return unless buffer_exists?(frame_length) # Buffer incomplete
@@ -135,13 +135,13 @@ module WebSocket
135
135
  def decode_first_byte
136
136
  first_byte = @frame.data.getbyte(0)
137
137
 
138
- fail(WebSocket::Error::Frame::ReservedBitUsed) if first_byte & 0b01110000 != 0b00000000
138
+ raise(WebSocket::Error::Frame::ReservedBitUsed) if first_byte & 0b01110000 != 0b00000000
139
139
 
140
140
  more = ((first_byte & 0b10000000) == 0b10000000) ^ fin
141
141
  frame_type = opcode_to_type first_byte & 0b00001111
142
142
 
143
- fail(WebSocket::Error::Frame::FragmentedControlFrame) if more && control_frame?(frame_type)
144
- fail(WebSocket::Error::Frame::DataFrameInsteadContinuation) if data_frame?(frame_type) && !@application_data_buffer.nil?
143
+ raise(WebSocket::Error::Frame::FragmentedControlFrame) if more && control_frame?(frame_type)
144
+ raise(WebSocket::Error::Frame::DataFrameInsteadContinuation) if data_frame?(frame_type) && !@application_data_buffer.nil?
145
145
 
146
146
  [more, frame_type]
147
147
  end
@@ -152,7 +152,7 @@ module WebSocket
152
152
  mask = @frame.incoming_masking? && (second_byte & 0b10000000) == 0b10000000
153
153
  length = second_byte & 0b01111111
154
154
 
155
- fail(WebSocket::Error::Frame::ControlFramePayloadTooLong) if length > 125 && control_frame?(frame_type)
155
+ raise(WebSocket::Error::Frame::ControlFramePayloadTooLong) if length > 125 && control_frame?(frame_type)
156
156
 
157
157
  header_length, payload_length = decode_payload_length(length)
158
158
 
@@ -202,10 +202,10 @@ module WebSocket
202
202
  end
203
203
 
204
204
  def decode_finish_continuation_frame(application_data)
205
- fail(WebSocket::Error::Frame::UnexpectedContinuationFrame) unless @frame_type
205
+ raise(WebSocket::Error::Frame::UnexpectedContinuationFrame) unless @frame_type
206
206
  @application_data_buffer << application_data
207
207
  # Test valid UTF-8 encoding
208
- fail(WebSocket::Error::Frame::InvalidPayloadEncoding) if @frame_type == :text && !@application_data_buffer.valid_encoding?
208
+ raise(WebSocket::Error::Frame::InvalidPayloadEncoding) if @frame_type == :text && !@application_data_buffer.valid_encoding?
209
209
  message = @frame.class.new(version: @frame.version, type: @frame_type, data: @application_data_buffer, decoded: true)
210
210
  @application_data_buffer = nil
211
211
  @frame_type = nil
@@ -12,15 +12,15 @@ module WebSocket
12
12
  close: 8,
13
13
  ping: 9,
14
14
  pong: 10
15
- }
15
+ }.freeze
16
16
 
17
17
  # Hash of frame opcodes and it's names
18
- FRAME_TYPES_INVERSE = FRAME_TYPES.invert
18
+ FRAME_TYPES_INVERSE = FRAME_TYPES.invert.freeze
19
19
 
20
20
  def encode_frame
21
21
  if @frame.type == :close
22
22
  code = @frame.code || 1000
23
- fail WebSocket::Error::Frame::UnknownCloseCode unless valid_code?(code)
23
+ raise WebSocket::Error::Frame::UnknownCloseCode unless valid_code?(code)
24
24
  @frame.data = Data.new([code].pack('n') + @frame.data.to_s)
25
25
  @frame.code = nil
26
26
  end
@@ -32,8 +32,8 @@ module WebSocket
32
32
  if close_code?(result)
33
33
  code = result.data.slice!(0..1)
34
34
  result.code = code.unpack('n').first
35
- fail WebSocket::Error::Frame::UnknownCloseCode unless valid_code?(result.code)
36
- fail WebSocket::Error::Frame::InvalidPayloadEncoding unless valid_encoding?(result.data)
35
+ raise WebSocket::Error::Frame::UnknownCloseCode unless valid_code?(result.code)
36
+ raise WebSocket::Error::Frame::InvalidPayloadEncoding unless valid_encoding?(result.data)
37
37
  end
38
38
  result
39
39
  end
@@ -41,7 +41,7 @@ module WebSocket
41
41
  private
42
42
 
43
43
  def valid_code?(code)
44
- [1000, 1001, 1002, 1003, 1007, 1008, 1009, 1010, 1011].include?(code) || (3000..4999).include?(code)
44
+ [1000, 1001, 1002, 1003, 1007, 1008, 1009, 1010, 1011].include?(code) || (3000..4999).cover?(code)
45
45
  end
46
46
 
47
47
  def valid_encoding?(data)
@@ -61,7 +61,7 @@ module WebSocket
61
61
  # @return [Integer] opcode or nil
62
62
  # @raise [WebSocket::Error] if frame opcode is not known
63
63
  def type_to_opcode(frame_type)
64
- FRAME_TYPES[frame_type] || fail(WebSocket::Error::Frame::UnknownFrameType)
64
+ FRAME_TYPES[frame_type] || raise(WebSocket::Error::Frame::UnknownFrameType)
65
65
  end
66
66
 
67
67
  # Convert frame opcode to type name
@@ -69,7 +69,7 @@ module WebSocket
69
69
  # @return [Symbol] Frame type name or nil
70
70
  # @raise [WebSocket::Error] if frame type name is not known
71
71
  def opcode_to_type(opcode)
72
- FRAME_TYPES_INVERSE[opcode] || fail(WebSocket::Error::Frame::UnknownOpcode)
72
+ FRAME_TYPES_INVERSE[opcode] || raise(WebSocket::Error::Frame::UnknownOpcode)
73
73
  end
74
74
  end
75
75
  end
@@ -17,13 +17,13 @@ module WebSocket
17
17
  ary = ["\x00", @frame.data, "\xff"]
18
18
  ary.map { |s| s.encode('UTF-8', 'UTF-8', invalid: :replace) }
19
19
  ary.join
20
- else fail WebSocket::Error::Frame::UnknownFrameType
20
+ else raise WebSocket::Error::Frame::UnknownFrameType
21
21
  end
22
22
  end
23
23
 
24
24
  # @see WebSocket::Frame::Handler::Base#decode_frame
25
25
  def decode_frame
26
- return if @frame.data.size == 0
26
+ return if @frame.data.size.zero?
27
27
 
28
28
  pointer = 0
29
29
  frame_type = @frame.data.getbyte(pointer)
@@ -42,7 +42,7 @@ module WebSocket
42
42
  break unless (b & 0x80) == 0x80
43
43
  end
44
44
 
45
- fail WebSocket::Error::Frame::TooLong if length > ::WebSocket.max_frame_size
45
+ raise WebSocket::Error::Frame::TooLong if length > ::WebSocket.max_frame_size
46
46
 
47
47
  unless @frame.data.getbyte(pointer + length - 1).nil?
48
48
  # Straight from spec - I'm sure this isn't crazy...
@@ -51,17 +51,17 @@ module WebSocket
51
51
  @frame.instance_variable_set '@data', @frame.data[(pointer + length)..-1]
52
52
 
53
53
  # If the /frame type/ is 0xFF and the /length/ was 0, then close
54
- if length == 0
54
+ if length.zero?
55
55
  @frame.class.new(version: @frame.version, type: :close, decoded: true)
56
56
  end
57
57
  end
58
58
  else
59
59
  # If the high-order bit of the /frame type/ byte is _not_ set
60
60
 
61
- fail WebSocket::Error::Frame::Invalid if @frame.data.getbyte(0) != 0x00
61
+ raise WebSocket::Error::Frame::Invalid if @frame.data.getbyte(0) != 0x00
62
62
 
63
63
  # Addition to the spec to protect against malicious requests
64
- fail WebSocket::Error::Frame::TooLong if @frame.data.size > ::WebSocket.max_frame_size
64
+ raise WebSocket::Error::Frame::TooLong if @frame.data.size > ::WebSocket.max_frame_size
65
65
 
66
66
  msg = @frame.data.slice!(/\A\x00[^\xff]*\xff/)
67
67
  if msg
@@ -24,7 +24,7 @@ module WebSocket
24
24
 
25
25
  # Return raw frame formatted for sending.
26
26
  def to_s
27
- fail WebSocket::Error::Frame::UnknownFrameType unless supported?
27
+ raise WebSocket::Error::Frame::UnknownFrameType unless supported?
28
28
  @handler.encode_frame
29
29
  end
30
30
  rescue_method :to_s
@@ -5,7 +5,8 @@ module WebSocket
5
5
  include ExceptionHandler
6
6
 
7
7
  attr_reader :host, :port, :path, :query,
8
- :state, :version, :secure, :headers
8
+ :state, :version, :secure,
9
+ :headers, :protocols
9
10
 
10
11
  # Initialize new WebSocket Handshake and set it's state to :new
11
12
  def initialize(args = {})
@@ -16,6 +17,7 @@ module WebSocket
16
17
 
17
18
  @data = ''
18
19
  @headers ||= {}
20
+ @protocols ||= []
19
21
  end
20
22
 
21
23
  # @abstract Add data to handshake
@@ -52,7 +54,7 @@ module WebSocket
52
54
 
53
55
  # @abstract Should send data after parsing is finished?
54
56
  def should_respond?
55
- fail NotImplementedError
57
+ raise NotImplementedError
56
58
  end
57
59
 
58
60
  # Data left from parsing. Sometimes data that doesn't belong to handshake are added - use this method to retrieve them.
@@ -104,7 +106,15 @@ module WebSocket
104
106
 
105
107
  lines.each do |line|
106
108
  h = HEADER.match(line)
107
- @headers[h[1].strip.downcase] = h[2].strip if h
109
+ next unless h # Skip any invalid headers
110
+ key = h[1].strip.downcase
111
+ val = h[2].strip
112
+ # If the header is already set and refers to the websocket protocol, append the new value
113
+ if @headers.key?(key) && key =~ /^(sec-)?websocket-protocol$/
114
+ @headers[key] << ", #{val}"
115
+ else
116
+ @headers[key] = val
117
+ end
108
118
  end
109
119
 
110
120
  @state = :finished
@@ -38,16 +38,17 @@ module WebSocket
38
38
  #
39
39
  # @param [Hash] args Arguments for client
40
40
  #
41
- # @option args [String] :host Host of request. Required if no :url param was provided.
42
- # @option args [String] :origin Origin of request. Optional, should be used mostly by browsers. Default: nil
43
- # @option args [String] :path Path of request. Should start with '/'. Default: '/'
44
- # @option args [Integer] :port Port of request. Default: nil
45
- # @option args [String] :query. Query for request. Should be in format "aaa=bbb&ccc=ddd"
46
- # @option args [Boolean] :secure Defines protocol to use. If true then wss://, otherwise ws://. This option will not change default port - it should be handled by programmer.
47
- # @option args [String] :url URL of request. Must by in format like ws://example.com/path?query=true. Every part of this url will be overriden by more specific arguments.
48
- # @option args [String] :uri Alias to :url
49
- # @option args [Integer] :version Version of WebSocket to use. Default: 13 (this is version from RFC)
50
- # @option args [Hash] :headers HTTP headers to use in the handshake
41
+ # @option args [String] :host Host of request. Required if no :url param was provided.
42
+ # @option args [String] :origin Origin of request. Optional, should be used mostly by browsers. Default: nil
43
+ # @option args [String] :path Path of request. Should start with '/'. Default: '/'
44
+ # @option args [Integer] :port Port of request. Default: nil
45
+ # @option args [String] :query. Query for request. Should be in format "aaa=bbb&ccc=ddd"
46
+ # @option args [Boolean] :secure Defines protocol to use. If true then wss://, otherwise ws://. This option will not change default port - it should be handled by programmer.
47
+ # @option args [String] :url URL of request. Must by in format like ws://example.com/path?query=true. Every part of this url will be overriden by more specific arguments.
48
+ # @option args [String] :uri Alias to :url
49
+ # @option args [Array<String>] :protocols An array of supported sub-protocols
50
+ # @option args [Integer] :version Version of WebSocket to use. Default: 13 (this is version from RFC)
51
+ # @option args [Hash] :headers HTTP headers to use in the handshake
51
52
  #
52
53
  # @example
53
54
  # Websocket::Handshake::Client.new(url: "ws://example.com/path?query=true")
@@ -66,7 +67,7 @@ module WebSocket
66
67
  @path = '/' if @path.nil? || @path.empty?
67
68
  @version ||= DEFAULT_VERSION
68
69
 
69
- fail WebSocket::Error::Handshake::NoHostProvided unless @host
70
+ raise WebSocket::Error::Handshake::NoHostProvided unless @host
70
71
 
71
72
  include_version
72
73
  end
@@ -107,7 +108,7 @@ module WebSocket
107
108
  when 1..3 then Handler::Client01.new(self)
108
109
  when 4..10 then Handler::Client04.new(self)
109
110
  when 11..17 then Handler::Client11.new(self)
110
- else fail WebSocket::Error::Handshake::UnknownVersion
111
+ else raise WebSocket::Error::Handshake::UnknownVersion
111
112
  end
112
113
  end
113
114
 
@@ -118,9 +119,9 @@ module WebSocket
118
119
  # @return [Boolean] True if parsed correctly. False otherwise
119
120
  def parse_first_line(line)
120
121
  line_parts = line.match(FIRST_LINE)
121
- fail WebSocket::Error::Handshake::InvalidHeader unless line_parts
122
+ raise WebSocket::Error::Handshake::InvalidHeader unless line_parts
122
123
  status = line_parts[1]
123
- fail WebSocket::Error::Handshake::InvalidStatusCode unless status == '101'
124
+ raise WebSocket::Error::Handshake::InvalidStatusCode unless status == '101'
124
125
  end
125
126
  end
126
127
  end
@@ -7,7 +7,7 @@ module WebSocket
7
7
  class Client04 < Client
8
8
  # @see WebSocket::Handshake::Base#valid?
9
9
  def valid?
10
- super && verify_accept
10
+ super && verify_accept && verify_protocol
11
11
  end
12
12
 
13
13
  private
@@ -25,6 +25,7 @@ module WebSocket
25
25
  keys << ['Sec-WebSocket-Origin', @handshake.origin] if @handshake.origin
26
26
  keys << ['Sec-WebSocket-Version', @handshake.version]
27
27
  keys << ['Sec-WebSocket-Key', key]
28
+ keys << ['Sec-WebSocket-Protocol', @handshake.protocols.join(', ')] if @handshake.protocols.any?
28
29
  keys
29
30
  end
30
31
 
@@ -43,7 +44,16 @@ module WebSocket
43
44
  # Verify if received header Sec-WebSocket-Accept matches generated one.
44
45
  # @return [Boolean] True if accept is matching. False otherwise(appropriate error is set)
45
46
  def verify_accept
46
- fail WebSocket::Error::Handshake::InvalidAuthentication unless @handshake.headers['sec-websocket-accept'] == accept
47
+ raise WebSocket::Error::Handshake::InvalidAuthentication unless @handshake.headers['sec-websocket-accept'] == accept
48
+ true
49
+ end
50
+
51
+ # Verify if received header Sec-WebSocket-Protocol matches with one of the sent ones
52
+ # @return [Boolean] True if matching. False otherwise(appropriate error is set)
53
+ def verify_protocol
54
+ return true if @handshake.protocols.empty?
55
+ protos = @handshake.headers['sec-websocket-protocol'].split(/ *, */) & @handshake.protocols
56
+ raise WebSocket::Error::Handshake::UnsupportedProtocol if protos.empty?
47
57
  true
48
58
  end
49
59
  end
@@ -2,6 +2,11 @@ module WebSocket
2
2
  module Handshake
3
3
  module Handler
4
4
  class Client75 < Client
5
+ # @see WebSocket::Handshake::Base#valid?
6
+ def valid?
7
+ super && verify_protocol
8
+ end
9
+
5
10
  private
6
11
 
7
12
  # @see WebSocket::Handshake::Handler::Base#handshake_keys
@@ -14,9 +19,19 @@ module WebSocket
14
19
  host += ":#{@handshake.port}" if @handshake.port
15
20
  keys << ['Host', host]
16
21
  keys << ['Origin', @handshake.origin] if @handshake.origin
22
+ keys << ['WebSocket-Protocol', @handshake.protocols.first] if @handshake.protocols.any?
17
23
  keys += super
18
24
  keys
19
25
  end
26
+
27
+ # Verify if received header WebSocket-Protocol matches with the sent one
28
+ # @return [Boolean] True if matching. False otherwise(appropriate error is set)
29
+ def verify_protocol
30
+ return true if @handshake.protocols.empty?
31
+ invalid = @handshake.headers['websocket-protocol'].strip != @handshake.protocols.first
32
+ raise WebSocket::Error::Handshake::UnsupportedProtocol if invalid
33
+ true
34
+ end
20
35
  end
21
36
  end
22
37
  end
@@ -6,7 +6,7 @@ module WebSocket
6
6
  class Client76 < Client75
7
7
  # @see WebSocket::Handshake::Base#valid?
8
8
  def valid?
9
- super && verify_challenge
9
+ super && verify_challenge && verify_protocol
10
10
  end
11
11
 
12
12
  private
@@ -62,7 +62,7 @@ module WebSocket
62
62
  # Verify if challenge sent by server match generated one
63
63
  # @return [Boolena] True if challenge matches, false otherwise(sets appropriate error)
64
64
  def verify_challenge
65
- fail WebSocket::Error::Handshake::InvalidAuthentication unless @handshake.leftovers == challenge
65
+ raise WebSocket::Error::Handshake::InvalidAuthentication unless @handshake.leftovers == challenge
66
66
  true
67
67
  end
68
68
 
@@ -93,6 +93,15 @@ module WebSocket
93
93
  def generate_key3
94
94
  [rand(0x100000000)].pack('N') + [rand(0x100000000)].pack('N')
95
95
  end
96
+
97
+ # Verify if received header Sec-WebSocket-Protocol matches with the sent one
98
+ # @return [Boolean] True if matching. False otherwise(appropriate error is set)
99
+ def verify_protocol
100
+ return true if @handshake.protocols.empty?
101
+ invalid = @handshake.headers['sec-websocket-protocol'].strip != @handshake.protocols.first
102
+ raise WebSocket::Error::Handshake::UnsupportedProtocol if invalid
103
+ true
104
+ end
96
105
  end
97
106
  end
98
107
  end
@@ -23,7 +23,7 @@ module WebSocket
23
23
  %w(Upgrade websocket),
24
24
  %w(Connection Upgrade),
25
25
  ['Sec-WebSocket-Accept', signature]
26
- ]
26
+ ] + protocol
27
27
  end
28
28
 
29
29
  # Signature of response, created from client request Sec-WebSocket-Key
@@ -35,13 +35,19 @@ module WebSocket
35
35
  end
36
36
 
37
37
  def verify_key
38
- fail WebSocket::Error::Handshake::InvalidAuthentication unless key
38
+ raise WebSocket::Error::Handshake::InvalidAuthentication unless key
39
39
  true
40
40
  end
41
41
 
42
42
  def key
43
43
  @handshake.headers['sec-websocket-key']
44
44
  end
45
+
46
+ def protocol
47
+ return [] unless @handshake.headers.key?('sec-websocket-protocol')
48
+ protos = @handshake.headers['sec-websocket-protocol'].split(/ *, */) & @handshake.protocols
49
+ [['Sec-WebSocket-Protocol', protos.first]]
50
+ end
45
51
  end
46
52
  end
47
53
  end
@@ -16,7 +16,13 @@ module WebSocket
16
16
  %w(Connection Upgrade),
17
17
  ['WebSocket-Origin', @handshake.headers['origin']],
18
18
  ['WebSocket-Location', @handshake.uri]
19
- ]
19
+ ] + protocol
20
+ end
21
+
22
+ def protocol
23
+ return [] unless @handshake.headers.key?('websocket-protocol')
24
+ proto = @handshake.headers['websocket-protocol']
25
+ [['WebSocket-Protocol', @handshake.protocols.include?(proto) ? proto : nil]]
20
26
  end
21
27
  end
22
28
  end
@@ -28,7 +28,7 @@ module WebSocket
28
28
  %w(Connection Upgrade),
29
29
  ['Sec-WebSocket-Origin', @handshake.headers['origin']],
30
30
  ['Sec-WebSocket-Location', @handshake.uri]
31
- ]
31
+ ] + protocol
32
32
  end
33
33
 
34
34
  # @see WebSocket::Handshake::Handler::Base#finishing_line
@@ -36,8 +36,6 @@ module WebSocket
36
36
  @finishing_line ||= challenge_response
37
37
  end
38
38
 
39
- private
40
-
41
39
  # Response to client challenge from request Sec-WebSocket-Key1, Sec-WebSocket-Key2 and leftovers
42
40
  # @return [String] Challenge response or nil if error occured
43
41
  def challenge_response
@@ -60,17 +58,23 @@ module WebSocket
60
58
 
61
59
  spaces = string.scan(/ /).size
62
60
  # As per 5.2.5, abort the connection if spaces are zero.
63
- fail WebSocket::Error::Handshake::InvalidAuthentication if spaces == 0
61
+ raise WebSocket::Error::Handshake::InvalidAuthentication if spaces.zero?
64
62
 
65
63
  # As per 5.2.6, abort if numbers is not an integral multiple of spaces
66
- fail WebSocket::Error::Handshake::InvalidAuthentication if numbers % spaces != 0
64
+ raise WebSocket::Error::Handshake::InvalidAuthentication if numbers % spaces != 0
67
65
 
68
66
  quotient = numbers / spaces
69
67
 
70
- fail WebSocket::Error::Handshake::InvalidAuthentication if quotient > 2**32 - 1
68
+ raise WebSocket::Error::Handshake::InvalidAuthentication if quotient > 2**32 - 1
71
69
 
72
70
  quotient
73
71
  end
72
+
73
+ def protocol
74
+ return [] unless @handshake.headers.key?('sec-websocket-protocol')
75
+ proto = @handshake.headers['sec-websocket-protocol']
76
+ [['Sec-WebSocket-Protocol', @handshake.protocols.include?(proto) ? proto : nil]]
77
+ end
74
78
  end
75
79
  end
76
80
  end
@@ -35,6 +35,7 @@ module WebSocket
35
35
  # @param [Hash] args Arguments for server
36
36
  #
37
37
  # @option args [Boolean] :secure If true then server will use wss:// protocol
38
+ # @option args [Array<String>] :protocols an array of supported sub-protocols
38
39
  #
39
40
  # @example
40
41
  # Websocket::Handshake::Server.new(secure: true)
@@ -70,7 +71,7 @@ module WebSocket
70
71
  # @example
71
72
  # @handshake.from_rack(env)
72
73
  def from_rack(env)
73
- @headers = env.select { |key, _value| key =~ /\AHTTP_/ }.each_with_object({}) do |tuple, memo|
74
+ @headers = env.select { |key, _value| key.start_with? 'HTTP_' }.each_with_object({}) do |tuple, memo|
74
75
  key, value = tuple
75
76
  memo[key.gsub(/\AHTTP_/, '').tr('_', '-').downcase] = value
76
77
  end
@@ -153,7 +154,7 @@ module WebSocket
153
154
  when 75 then Handler::Server75.new(self)
154
155
  when 76, 0..3 then Handler::Server76.new(self)
155
156
  when 4..17 then Handler::Server04.new(self)
156
- else fail WebSocket::Error::Handshake::UnknownVersion
157
+ else raise WebSocket::Error::Handshake::UnknownVersion
157
158
  end
158
159
  end
159
160
 
@@ -164,9 +165,9 @@ module WebSocket
164
165
  # @return [Boolean] True if parsed correctly. False otherwise
165
166
  def parse_first_line(line)
166
167
  line_parts = line.match(PATH)
167
- fail WebSocket::Error::Handshake::InvalidHeader unless line_parts
168
+ raise WebSocket::Error::Handshake::InvalidHeader unless line_parts
168
169
  method = line_parts[1].strip
169
- fail WebSocket::Error::Handshake::GetRequestRequired unless method == 'GET'
170
+ raise WebSocket::Error::Handshake::GetRequestRequired unless method == 'GET'
170
171
 
171
172
  resource_name = line_parts[2].strip
172
173
  @path, @query = resource_name.split('?', 2)
@@ -1,3 +1,3 @@
1
1
  module WebSocket
2
- VERSION = '1.2.3'
2
+ VERSION = '1.2.4'.freeze
3
3
  end
@@ -2,7 +2,7 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  RSpec.describe 'Outgoing frame draft 03' do
5
- let(:version) { 03 }
5
+ let(:version) { 3 }
6
6
  let(:frame) { WebSocket::Frame::Outgoing.new(version: version, data: decoded_text, type: frame_type) }
7
7
  let(:decoded_text) { '' }
8
8
  let(:encoded_text) { "\x04\x00" }
@@ -2,7 +2,7 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  RSpec.describe 'Outgoing frame draft 04' do
5
- let(:version) { 04 }
5
+ let(:version) { 4 }
6
6
  let(:frame) { WebSocket::Frame::Outgoing.new(version: version, data: decoded_text, type: frame_type) }
7
7
  let(:decoded_text) { '' }
8
8
  let(:encoded_text) { "\x84\x00" }
@@ -17,4 +17,45 @@ RSpec.describe 'Client draft 4 handshake' do
17
17
  expect(handshake).not_to be_valid
18
18
  expect(handshake.error).to eql(:invalid_handshake_authentication)
19
19
  end
20
+
21
+ context 'protocol header specified' do
22
+ let(:handshake) { WebSocket::Handshake::Client.new(uri: 'ws://example.com/demo', origin: 'http://example.com', version: version, protocols: protocols) }
23
+
24
+ context 'single protocol requested' do
25
+ let(:protocols) { %w(binary) }
26
+
27
+ it 'returns a valid handshake' do
28
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'binary' } }
29
+ handshake << server_response
30
+
31
+ expect(handshake).to be_finished
32
+ expect(handshake).to be_valid
33
+ end
34
+ end
35
+
36
+ context 'multiple protocols requested' do
37
+ let(:protocols) { %w(binary xmpp) }
38
+
39
+ it 'returns with a valid handshake' do
40
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'xmpp' } }
41
+ handshake << server_response
42
+
43
+ expect(handshake).to be_finished
44
+ expect(handshake).to be_valid
45
+ end
46
+ end
47
+
48
+ context 'unsupported protocol requested' do
49
+ let(:protocols) { %w(binary xmpp) }
50
+
51
+ it 'fails with an unsupported protocol error' do
52
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'generic' } }
53
+ handshake << server_response
54
+
55
+ expect(handshake).to be_finished
56
+ expect(handshake).not_to be_valid
57
+ expect(handshake.error).to eql(:unsupported_protocol)
58
+ end
59
+ end
60
+ end
20
61
  end
@@ -8,4 +8,29 @@ RSpec.describe 'Client draft 75 handshake' do
8
8
  let(:server_response) { server_handshake_75(@request_params || {}) }
9
9
 
10
10
  it_should_behave_like 'all client drafts'
11
+
12
+ context 'protocol header specified' do
13
+ let(:handshake) { WebSocket::Handshake::Client.new(uri: 'ws://example.com/demo', origin: 'http://example.com', version: version, protocols: %w(binary)) }
14
+
15
+ context 'supported' do
16
+ it 'returns a valid handshake' do
17
+ @request_params = { headers: { 'WebSocket-Protocol' => 'binary' } }
18
+ handshake << server_response
19
+
20
+ expect(handshake).to be_finished
21
+ expect(handshake).to be_valid
22
+ end
23
+ end
24
+
25
+ context 'unsupported' do
26
+ it 'fails with an unsupported protocol error' do
27
+ @request_params = { headers: { 'WebSocket-Protocol' => 'xmpp' } }
28
+ handshake << server_response
29
+
30
+ expect(handshake).to be_finished
31
+ expect(handshake).not_to be_valid
32
+ expect(handshake.error).to eql(:unsupported_protocol)
33
+ end
34
+ end
35
+ end
11
36
  end
@@ -17,4 +17,29 @@ RSpec.describe 'Client draft 76 handshake' do
17
17
  expect(handshake).not_to be_valid
18
18
  expect(handshake.error).to eql(:invalid_handshake_authentication)
19
19
  end
20
+
21
+ context 'protocol header specified' do
22
+ let(:handshake) { WebSocket::Handshake::Client.new(uri: 'ws://example.com/demo', origin: 'http://example.com', version: version, protocols: %w(binary)) }
23
+
24
+ context 'supported' do
25
+ it 'returns a valid handshake' do
26
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'binary' } }
27
+ handshake << server_response
28
+
29
+ expect(handshake).to be_finished
30
+ expect(handshake).to be_valid
31
+ end
32
+ end
33
+
34
+ context 'unsupported' do
35
+ it 'fails with an unsupported protocol error' do
36
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'xmpp' } }
37
+ handshake << server_response
38
+
39
+ expect(handshake).to be_finished
40
+ expect(handshake).not_to be_valid
41
+ expect(handshake.error).to eql(:unsupported_protocol)
42
+ end
43
+ end
44
+ end
20
45
  end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  RSpec.describe 'Server draft 04 handshake' do
4
4
  let(:handshake) { WebSocket::Handshake::Server.new }
5
- let(:version) { 04 }
5
+ let(:version) { 4 }
6
6
  let(:client_request) { client_handshake_04(@request_params || {}) }
7
7
  let(:server_response) { server_handshake_04(@request_params || {}) }
8
8
 
@@ -15,4 +15,35 @@ RSpec.describe 'Server draft 04 handshake' do
15
15
  expect(handshake).not_to be_valid
16
16
  expect(handshake.error).to eql(:invalid_handshake_authentication)
17
17
  end
18
+
19
+ context 'protocol header specified' do
20
+ let(:handshake) { WebSocket::Handshake::Server.new(protocols: %w(binary xmpp)) }
21
+
22
+ context 'single protocol requested' do
23
+ it 'returns with the same protocol' do
24
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'binary' } }
25
+ handshake << client_request
26
+
27
+ expect(handshake.to_s).to match('Sec-WebSocket-Protocol: binary')
28
+ end
29
+ end
30
+
31
+ context 'multiple protocols requested' do
32
+ it 'returns with the first supported protocol' do
33
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'xmpp, binary' } }
34
+ handshake << client_request
35
+
36
+ expect(handshake.to_s).to match('Sec-WebSocket-Protocol: xmpp')
37
+ end
38
+ end
39
+
40
+ context 'unsupported protocol requested' do
41
+ it 'reutrns with an empty protocol header' do
42
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'generic' } }
43
+ handshake << client_request
44
+
45
+ expect(handshake.to_s).to match("Sec-WebSocket-Protocol: \r\n")
46
+ end
47
+ end
48
+ end
18
49
  end
@@ -8,4 +8,26 @@ RSpec.describe 'Server draft 75 handshake' do
8
8
  let(:server_response) { server_handshake_75(@request_params || {}) }
9
9
 
10
10
  it_should_behave_like 'all server drafts'
11
+
12
+ context 'protocol header specified' do
13
+ let(:handshake) { WebSocket::Handshake::Server.new(protocols: %w(binary)) }
14
+
15
+ context 'supported' do
16
+ it 'returns with the same protocol' do
17
+ @request_params = { headers: { 'WebSocket-Protocol' => 'binary' } }
18
+ handshake << client_request
19
+
20
+ expect(handshake.to_s).to match('WebSocket-Protocol: binary')
21
+ end
22
+ end
23
+
24
+ context 'unsupported' do
25
+ it 'returns with an empty protocol header' do
26
+ @request_params = { headers: { 'WebSocket-Protocol' => 'xmpp' } }
27
+ handshake << client_request
28
+
29
+ expect(handshake.to_s).to match("WebSocket-Protocol: \r\n")
30
+ end
31
+ end
32
+ end
11
33
  end
@@ -43,4 +43,26 @@ RSpec.describe 'Server draft 76 handshake' do
43
43
  expect(handshake).not_to be_valid
44
44
  expect(handshake.error).to eql(:invalid_handshake_authentication)
45
45
  end
46
+
47
+ context 'protocol header specified' do
48
+ let(:handshake) { WebSocket::Handshake::Server.new(protocols: %w(binary)) }
49
+
50
+ context 'supported' do
51
+ it 'returns with the same protocol' do
52
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'binary' } }
53
+ handshake << client_request
54
+
55
+ expect(handshake.to_s).to match('Sec-WebSocket-Protocol: binary')
56
+ end
57
+ end
58
+
59
+ context 'unsupported' do
60
+ it 'returns with an empty protocol header' do
61
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'xmpp' } }
62
+ handshake << client_request
63
+
64
+ expect(handshake.to_s).to match("Sec-WebSocket-Protocol: \r\n")
65
+ end
66
+ end
67
+ end
46
68
  end
@@ -14,7 +14,7 @@ def server_handshake_75(args = {})
14
14
  HTTP/1.1 101 Web Socket Protocol Handshake\r
15
15
  Upgrade: WebSocket\r
16
16
  Connection: Upgrade\r
17
- WebSocket-Origin: http://example.com\r
17
+ #{(args[:headers] || {}).map { |key, value| "#{key}: #{value}\r\n" }.join('')}WebSocket-Origin: http://example.com\r
18
18
  WebSocket-Location: ws#{args[:secure] ? 's' : ''}://#{args[:host] || 'example.com'}#{":#{args[:port]}" if args[:port]}#{args[:path] || '/demo'}\r
19
19
  \r
20
20
  EOF
@@ -40,7 +40,7 @@ def server_handshake_76(args = {})
40
40
  HTTP/1.1 101 WebSocket Protocol Handshake\r
41
41
  Upgrade: WebSocket\r
42
42
  Connection: Upgrade\r
43
- Sec-WebSocket-Origin: http://example.com\r
43
+ #{(args[:headers] || {}).map { |key, value| "#{key}: #{value}\r\n" }.join('')}Sec-WebSocket-Origin: http://example.com\r
44
44
  Sec-WebSocket-Location: ws#{args[:secure] ? 's' : ''}://#{args[:host] || 'example.com'}#{":#{args[:port]}" if args[:port]}#{args[:path] || '/demo'}\r
45
45
  \r
46
46
  #{args[:challenge] || "8jKS'y:G*Co,Wxa-"}
@@ -66,7 +66,7 @@ def server_handshake_04(args = {})
66
66
  HTTP/1.1 101 Switching Protocols\r
67
67
  Upgrade: websocket\r
68
68
  Connection: Upgrade\r
69
- Sec-WebSocket-Accept: #{args[:accept] || 's3pPLMBiTxaQ9kYGzzhZRbK+xOo='}\r
69
+ #{(args[:headers] || {}).map { |key, value| "#{key}: #{value}\r\n" }.join('')}Sec-WebSocket-Accept: #{args[:accept] || 's3pPLMBiTxaQ9kYGzzhZRbK+xOo='}\r
70
70
  \r
71
71
  EOF
72
72
  end
@@ -38,19 +38,21 @@ RSpec.shared_examples_for 'valid_incoming_frame' do
38
38
  after(:each) { WebSocket.should_raise = false }
39
39
 
40
40
  it 'should have specified number of returned frames' do
41
- expect do
42
- decoded_text_array.each_with_index do |da, index|
43
- n = subject.next
44
- expect(n).not_to be_nil, "Should return frame for #{da}, #{frame_type_array[index]}"
45
- expect(n.class).to eql(WebSocket::Frame::Incoming), "Should be WebSocket::Frame::Incoming, #{n} received instead"
46
- end
47
- expect(subject.next).to be_nil
48
- if error.is_a?(Class)
49
- expect(subject.error).to eql(error.new.message)
50
- else
51
- expect(subject.error).to eql(error)
52
- end
53
- end.to raise_error(error) if error
41
+ if error
42
+ expect do
43
+ decoded_text_array.each_with_index do |da, index|
44
+ n = subject.next
45
+ expect(n).not_to be_nil, "Should return frame for #{da}, #{frame_type_array[index]}"
46
+ expect(n.class).to eql(WebSocket::Frame::Incoming), "Should be WebSocket::Frame::Incoming, #{n} received instead"
47
+ end
48
+ expect(subject.next).to be_nil
49
+ if error.is_a?(Class)
50
+ expect(subject.error).to eql(error.new.message)
51
+ else
52
+ expect(subject.error).to eql(error)
53
+ end
54
+ end.to raise_error(error)
55
+ end
54
56
  end
55
57
  end
56
58
  end
@@ -17,4 +17,9 @@ Gem::Specification.new do |s|
17
17
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
19
19
  s.require_paths = ['lib']
20
+
21
+ s.add_development_dependency 'rake'
22
+ s.add_development_dependency 'rspec', '~> 3.0'
23
+ s.add_development_dependency 'rspec-its'
24
+ s.add_development_dependency 'rubocop'
20
25
  end
metadata CHANGED
@@ -1,15 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: websocket
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Potocki
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-05 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2017-01-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-its
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
13
69
  description: Universal Ruby library to handle WebSocket protocol
14
70
  email:
15
71
  - bernard.potocki@imanel.org
@@ -109,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
165
  version: '0'
110
166
  requirements: []
111
167
  rubyforge_project:
112
- rubygems_version: 2.5.1
168
+ rubygems_version: 2.5.2
113
169
  signing_key:
114
170
  specification_version: 4
115
171
  summary: Universal Ruby library to handle WebSocket protocol