websocket 1.2.3 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
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