websocket 1.1.4 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.travis.yml +2 -6
  2. data/CHANGELOG.md +7 -0
  3. data/Gemfile +2 -1
  4. data/README.md +10 -6
  5. data/Rakefile +1 -1
  6. data/lib/websocket.rb +1 -1
  7. data/lib/websocket/exception_handler.rb +6 -0
  8. data/lib/websocket/frame/base.rb +1 -1
  9. data/lib/websocket/frame/data.rb +11 -9
  10. data/lib/websocket/frame/handler.rb +1 -1
  11. data/lib/websocket/frame/handler/handler03.rb +17 -17
  12. data/lib/websocket/frame/handler/handler07.rb +8 -8
  13. data/lib/websocket/frame/handler/handler75.rb +8 -7
  14. data/lib/websocket/frame/incoming.rb +1 -1
  15. data/lib/websocket/frame/outgoing.rb +1 -1
  16. data/lib/websocket/handshake/base.rb +7 -7
  17. data/lib/websocket/handshake/client.rb +5 -3
  18. data/lib/websocket/handshake/handler/base.rb +5 -5
  19. data/lib/websocket/handshake/handler/client.rb +6 -1
  20. data/lib/websocket/handshake/handler/client04.rb +7 -6
  21. data/lib/websocket/handshake/handler/client75.rb +5 -4
  22. data/lib/websocket/handshake/handler/client76.rb +5 -5
  23. data/lib/websocket/handshake/handler/server04.rb +11 -6
  24. data/lib/websocket/handshake/handler/server75.rb +5 -5
  25. data/lib/websocket/handshake/handler/server76.rb +9 -9
  26. data/lib/websocket/handshake/server.rb +25 -24
  27. data/lib/websocket/version.rb +1 -1
  28. data/spec/frame/incoming_03_spec.rb +25 -25
  29. data/spec/frame/incoming_04_spec.rb +25 -25
  30. data/spec/frame/incoming_05_spec.rb +29 -29
  31. data/spec/frame/incoming_07_spec.rb +31 -31
  32. data/spec/frame/incoming_75_spec.rb +13 -13
  33. data/spec/frame/incoming_common_spec.rb +12 -13
  34. data/spec/frame/masking_spec.rb +10 -10
  35. data/spec/frame/outgoing_03_spec.rb +17 -17
  36. data/spec/frame/outgoing_04_spec.rb +17 -17
  37. data/spec/frame/outgoing_05_spec.rb +17 -17
  38. data/spec/frame/outgoing_07_spec.rb +19 -19
  39. data/spec/frame/outgoing_75_spec.rb +9 -9
  40. data/spec/frame/outgoing_common_spec.rb +7 -8
  41. data/spec/handshake/client_04_spec.rb +9 -9
  42. data/spec/handshake/client_75_spec.rb +2 -2
  43. data/spec/handshake/client_76_spec.rb +9 -9
  44. data/spec/handshake/server_04_spec.rb +5 -5
  45. data/spec/handshake/server_75_spec.rb +1 -1
  46. data/spec/handshake/server_76_spec.rb +21 -21
  47. data/spec/spec_helper.rb +4 -1
  48. data/spec/support/all_client_drafts.rb +62 -52
  49. data/spec/support/all_server_drafts.rb +49 -49
  50. data/spec/support/handshake_requests.rb +16 -16
  51. data/spec/support/incoming_frames.rb +28 -28
  52. data/spec/support/outgoing_frames.rb +10 -10
  53. data/websocket.gemspec +1 -1
  54. metadata +42 -22
  55. checksums.yaml +0 -7
data/.travis.yml CHANGED
@@ -1,14 +1,10 @@
1
1
  language: ruby
2
2
  script: "bundle exec rake spec"
3
3
  rvm:
4
- - 1.8.7
5
- - 1.9.2
6
4
  - 1.9.3
7
5
  - 2.0.0
8
6
  - 2.1.1
9
- - ree
10
- - rbx
11
- - jruby-18mode
7
+ - 2.1.2
8
+ - rbx-2
12
9
  - jruby-19mode
13
10
  - ruby-head
14
- - jruby-head
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.0
4
+
5
+ - Remove support for Ruby 1.8
6
+ - Add support for sending custom headers for Client
7
+ - Better detection and handling of draft 76
8
+ - Multiple small fixes and optimizations
9
+
3
10
  ## 1.1.4
4
11
 
5
12
  - verify valid close codes according to spec
data/Gemfile CHANGED
@@ -3,4 +3,5 @@ source "http://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  gem 'rake'
6
- gem 'rspec', '~> 2.11'
6
+ gem 'rspec', '~> 3.0.0'
7
+ gem 'rspec-its'
data/README.md CHANGED
@@ -1,10 +1,13 @@
1
1
  # WebSocket Ruby
2
2
 
3
- - Travis CI build: [![](https://travis-ci.org/imanel/websocket-ruby.png)](http://travis-ci.org/imanel/websocket-ruby)
4
- - Autobahn tests: [server](http://imanel.github.com/websocket-ruby/autobahn/server/), [client](http://imanel.github.com/websocket-ruby/autobahn/client/)
5
-
6
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.
7
4
 
5
+ [![Gem Version](https://badge.fury.io/rb/websocket.svg)](http://badge.fury.io/rb/websocket)
6
+ [![Travis CI](https://travis-ci.org/imanel/websocket-ruby.png)](http://travis-ci.org/imanel/websocket-ruby)
7
+ [![Code Climate](https://codeclimate.com/github/imanel/websocket-ruby.png)](https://codeclimate.com/github/imanel/websocket-ruby)
8
+
9
+ **Autobahn tests:** [server](http://imanel.github.com/websocket-ruby/autobahn/server/), [client](http://imanel.github.com/websocket-ruby/autobahn/client/)
10
+
8
11
  Currently WebSocket Ruby supports all existing drafts of WebSocket, which include:
9
12
 
10
13
  - [hixie-75](http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75)
@@ -59,13 +62,14 @@ EOF
59
62
  ## Client handshake
60
63
 
61
64
  ``` ruby
62
- @handshake = WebSocket::Handshake::Client.new(:url => 'ws://example.com')
65
+ @handshake = WebSocket::Handshake::Client.new(url: 'ws://example.com', headers: { 'Cookie' => 'SESSIONID=1234' })
63
66
 
64
67
  # Create request
65
68
  @handshake.to_s # GET /demo HTTP/1.1
66
69
  # Upgrade: websocket
67
70
  # Connection: Upgrade
68
71
  # Host: example.com
72
+ # Cookie: SESSIONID=1234
69
73
  # Sec-WebSocket-Origin: http://example.com
70
74
  # Sec-WebSocket-Version: 13
71
75
  # Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
@@ -90,11 +94,11 @@ EOF
90
94
 
91
95
  ``` ruby
92
96
  # Prepare frame for sending
93
- frame = WebSocket::Frame::Outgoing::Server.new(:version => @handshake.version, :data => "Hello", :type => :text)
97
+ frame = WebSocket::Frame::Outgoing::Server.new(version: @handshake.version, data: "Hello", type: :text)
94
98
  frame.to_s # "\x81\x05\x48\x65\x6c\x6c\x6f"
95
99
 
96
100
  # Parse incoming frames
97
- frame = WebSocket::Frame::Incoming::Server.new(:version => @handshake.version)
101
+ frame = WebSocket::Frame::Incoming::Server.new(version: @handshake.version)
98
102
  frame << "\x81\x05\x48\x65\x6c\x6c\x6f\x81\x06\x77\x6f\x72\x6c\x64\x21"
99
103
  frame.next # "Hello"
100
104
  frame.next # "world!""
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ RSpec::Core::RakeTask.new do |t|
8
8
  t.pattern = 'spec/**/*_spec.rb'
9
9
  end
10
10
 
11
- task :default => :spec
11
+ task default: :spec
12
12
 
13
13
  namespace :autobahn do
14
14
  desc "Run autobahn tests for client"
data/lib/websocket.rb CHANGED
@@ -39,6 +39,6 @@ end
39
39
 
40
40
  # Try loading websocket-native if available
41
41
  begin
42
- require "websocket-native"
42
+ require 'websocket-native'
43
43
  rescue LoadError
44
44
  end
@@ -17,6 +17,12 @@ module WebSocket
17
17
 
18
18
  module ClassMethods
19
19
 
20
+ # Rescue from WebSocket::Error errors.
21
+ #
22
+ # @param [String] method_name Name of method that should be wrapped and rescued
23
+ # @param [Hash] options Options for rescue
24
+ #
25
+ # @options options [Any] :return Value that should be returned instead of raised error
20
26
  def rescue_method(method_name, options = {})
21
27
  define_method "#{method_name}_with_rescue" do |*args|
22
28
  begin
@@ -41,7 +41,7 @@ module WebSocket
41
41
 
42
42
  # Recreate inspect as #to_s was overwritten
43
43
  def inspect
44
- vars = self.instance_variables.map{|v| "#{v}=#{instance_variable_get(v).inspect}"}.join(", ")
44
+ vars = self.instance_variables.map { |v| "#{v}=#{instance_variable_get(v).inspect}" }.join(', ')
45
45
  insp = "#{self.class}:0x%08x" % (self.__id__ * 2)
46
46
  "<#{insp} #{vars}>"
47
47
  end
@@ -3,35 +3,37 @@ module WebSocket
3
3
  class Data < String
4
4
 
5
5
  def initialize(*args)
6
- super *args.each { |arg| arg.force_encoding('ASCII-8BIT') if respond_to?(:force_encoding) }
6
+ super(*convert_args(args))
7
7
  end
8
8
 
9
9
  def <<(*args)
10
- super *args.each { |arg| arg.force_encoding('ASCII-8BIT') if respond_to?(:force_encoding) }
10
+ super(*convert_args(args))
11
11
  end
12
12
 
13
+ # Convert all arguments to ASCII-8BIT for easier traversing
14
+ def convert_args(args)
15
+ args.each { |arg| arg.force_encoding('ASCII-8BIT') }
16
+ end
17
+
18
+ # Extract mask from 4 first bytes according to spec
13
19
  def set_mask
14
20
  raise WebSocket::Error::Frame::MaskTooShort if bytesize < 4
15
21
  @masking_key = self[0..3].bytes.to_a
16
22
  end
17
23
 
24
+ # Remove mask flag - it will still be present in payload
18
25
  def unset_mask
19
26
  @masking_key = nil
20
27
  end
21
28
 
29
+ # Extract `count` bytes starting from `start_index` and unmask it if needed.
22
30
  def getbytes(start_index, count)
23
31
  data = self[start_index, count]
24
32
  data = mask(data.bytes.to_a, @masking_key).pack('C*') if @masking_key
25
33
  data
26
34
  end
27
35
 
28
- # Required for support of Ruby 1.8
29
- unless new.respond_to?(:getbyte)
30
- def getbyte(index)
31
- self[index]
32
- end
33
- end
34
-
36
+ # Mask whole payload using mask key
35
37
  def mask(payload, mask)
36
38
  return mask_native(payload, mask) if respond_to?(:mask_native)
37
39
  result = []
@@ -2,7 +2,7 @@ module WebSocket
2
2
  module Frame
3
3
  module Handler
4
4
 
5
- autoload :Base, "#{::WebSocket::ROOT}/websocket/frame/handler/base"
5
+ autoload :Base, "#{::WebSocket::ROOT}/websocket/frame/handler/base"
6
6
 
7
7
  autoload :Handler03, "#{::WebSocket::ROOT}/websocket/frame/handler/handler03"
8
8
  autoload :Handler04, "#{::WebSocket::ROOT}/websocket/frame/handler/handler04"
@@ -7,12 +7,12 @@ module WebSocket
7
7
 
8
8
  # Hash of frame names and it's opcodes
9
9
  FRAME_TYPES = {
10
- :continuation => 0,
11
- :close => 1,
12
- :ping => 2,
13
- :pong => 3,
14
- :text => 4,
15
- :binary => 5
10
+ continuation: 0,
11
+ close: 1,
12
+ ping: 2,
13
+ pong: 3,
14
+ text: 4,
15
+ binary: 5
16
16
  }
17
17
 
18
18
  # Hash of frame opcodes and it's names
@@ -37,12 +37,12 @@ module WebSocket
37
37
  if length <= 125
38
38
  byte2 = length # since rsv4 is 0
39
39
  frame << (byte2 | mask)
40
- elsif length < 65536 # write 2 byte length
40
+ elsif length < 65_536 # write 2 byte length
41
41
  frame << (126 | mask)
42
42
  frame << [length].pack('n')
43
43
  else # write 8 byte length
44
44
  frame << (127 | mask)
45
- frame << [length >> 32, length & 0xFFFFFFFF].pack("NN")
45
+ frame << [length >> 32, length & 0xFFFFFFFF].pack('NN')
46
46
  end
47
47
 
48
48
  if @frame.outgoing_masking?
@@ -83,16 +83,16 @@ module WebSocket
83
83
  payload_length = case length
84
84
  when 127 # Length defined by 8 bytes
85
85
  # Check buffer size
86
- return if @frame.data.getbyte(pointer+8-1) == nil # Buffer incomplete
86
+ return if @frame.data.getbyte(pointer + 8 - 1) == nil # Buffer incomplete
87
87
 
88
88
  # Only using the last 4 bytes for now, till I work out how to
89
89
  # unpack 8 bytes. I'm sure 4GB frames will do for now :)
90
- l = @frame.data.getbytes(pointer+4, 4).unpack('N').first
90
+ l = @frame.data.getbytes(pointer + 4, 4).unpack('N').first
91
91
  pointer += 8
92
92
  l
93
93
  when 126 # Length defined by 2 bytes
94
94
  # Check buffer size
95
- return if @frame.data.getbyte(pointer+2-1) == nil # Buffer incomplete
95
+ return if @frame.data.getbyte(pointer + 2 - 1) == nil # Buffer incomplete
96
96
 
97
97
  l = @frame.data.getbytes(pointer, 2).unpack('n').first
98
98
  pointer += 2
@@ -108,7 +108,7 @@ module WebSocket
108
108
  raise(WebSocket::Error::Frame::TooLong) if frame_length > WebSocket.max_frame_size
109
109
 
110
110
  # Check buffer size
111
- return if @frame.data.getbyte(frame_length-1) == nil # Buffer incomplete
111
+ return if @frame.data.getbyte(frame_length - 1) == nil # Buffer incomplete
112
112
 
113
113
  # Remove frame header
114
114
  @frame.data.slice!(0...pointer)
@@ -118,7 +118,7 @@ module WebSocket
118
118
  @frame.data.set_mask if mask
119
119
  pointer += 4 if mask
120
120
  application_data = @frame.data.getbytes(pointer, payload_length)
121
- application_data.force_encoding('UTF-8') if application_data.respond_to?(:force_encoding)
121
+ application_data.force_encoding('UTF-8')
122
122
  pointer += payload_length
123
123
  @frame.data.unset_mask if mask
124
124
 
@@ -136,14 +136,14 @@ module WebSocket
136
136
  if frame_type == :continuation
137
137
  @application_data_buffer << application_data
138
138
  # Test valid UTF-8 encoding
139
- raise(WebSocket::Error::Frame::InvalidPayloadEncoding) if @frame_type == :text && @application_data_buffer.respond_to?(:valid_encoding?) && !@application_data_buffer.valid_encoding?
140
- message = @frame.class.new(:version => @frame.version, :type => @frame_type, :data => @application_data_buffer, :decoded => true)
139
+ raise(WebSocket::Error::Frame::InvalidPayloadEncoding) if @frame_type == :text && !@application_data_buffer.valid_encoding?
140
+ message = @frame.class.new(version: @frame.version, type: @frame_type, data: @application_data_buffer, decoded: true)
141
141
  @application_data_buffer = nil
142
142
  @frame_type = nil
143
143
  return message
144
144
  else
145
- raise(WebSocket::Error::Frame::InvalidPayloadEncoding) if frame_type == :text && application_data.respond_to?(:valid_encoding?) && !application_data.valid_encoding?
146
- return @frame.class.new(:version => @frame.version, :type => frame_type, :data => application_data, :decoded => true)
145
+ raise(WebSocket::Error::Frame::InvalidPayloadEncoding) if frame_type == :text && !application_data.valid_encoding?
146
+ return @frame.class.new(version: @frame.version, type: frame_type, data: application_data, decoded: true)
147
147
  end
148
148
  end
149
149
  end
@@ -7,12 +7,12 @@ module WebSocket
7
7
 
8
8
  # Hash of frame names and it's opcodes
9
9
  FRAME_TYPES = {
10
- :continuation => 0,
11
- :text => 1,
12
- :binary => 2,
13
- :close => 8,
14
- :ping => 9,
15
- :pong => 10,
10
+ continuation: 0,
11
+ text: 1,
12
+ binary: 2,
13
+ close: 8,
14
+ ping: 9,
15
+ pong: 10,
16
16
  }
17
17
 
18
18
  # Hash of frame opcodes and it's names
@@ -42,11 +42,11 @@ module WebSocket
42
42
  private
43
43
 
44
44
  def valid_code?(code)
45
- [1000,1001,1002,1003,1007,1008,1009,1010,1011].include?(code) || (3000..4999).include?(code)
45
+ [1000, 1001, 1002, 1003, 1007, 1008, 1009, 1010, 1011].include?(code) || (3000..4999).include?(code)
46
46
  end
47
47
 
48
48
  def valid_encoding?(data)
49
- return true if data.nil? || !data.respond_to?(:encode)
49
+ return true if data.nil?
50
50
  data.encode('UTF-8')
51
51
  true
52
52
  rescue
@@ -16,8 +16,9 @@ module WebSocket
16
16
  when :close then "\xff\x00"
17
17
  when :text then
18
18
  ary = ["\x00", @frame.data, "\xff"]
19
- ary.collect{ |s| s.encode('UTF-8', 'UTF-8', :invalid => :replace) if s.respond_to?(:encode) }
19
+ ary.map { |s| s.encode('UTF-8', 'UTF-8', invalid: :replace) }
20
20
  ary.join
21
+ else raise WebSocket::Error::Frame::UnknownFrameType
21
22
  end
22
23
  end
23
24
 
@@ -34,7 +35,7 @@ module WebSocket
34
35
  length = 0
35
36
 
36
37
  loop do
37
- return if !@frame.data.getbyte(pointer)
38
+ return unless @frame.data.getbyte(pointer)
38
39
  b = @frame.data.getbyte(pointer)
39
40
  pointer += 1
40
41
  b_v = b & 0x7F
@@ -44,15 +45,15 @@ module WebSocket
44
45
 
45
46
  raise WebSocket::Error::Frame::TooLong if length > ::WebSocket.max_frame_size
46
47
 
47
- unless @frame.data.getbyte(pointer+length-1) == nil
48
+ unless @frame.data.getbyte(pointer + length - 1) == nil
48
49
  # Straight from spec - I'm sure this isn't crazy...
49
50
  # 6. Read /length/ bytes.
50
51
  # 7. Discard the read bytes.
51
- @frame.instance_variable_set '@data', @frame.data[(pointer+length)..-1]
52
+ @frame.instance_variable_set '@data', @frame.data[(pointer + length)..-1]
52
53
 
53
54
  # If the /frame type/ is 0xFF and the /length/ was 0, then close
54
55
  if length == 0
55
- @frame.class.new(:version => @frame.version, :type => :close, :decoded => true)
56
+ @frame.class.new(version: @frame.version, type: :close, decoded: true)
56
57
  end
57
58
  end
58
59
  else
@@ -66,8 +67,8 @@ module WebSocket
66
67
  msg = @frame.data.slice!(/\A\x00[^\xff]*\xff/)
67
68
  if msg
68
69
  msg.gsub!(/\A\x00|\xff\z/, '')
69
- msg.force_encoding('UTF-8') if msg.respond_to?(:force_encoding)
70
- @frame.class.new(:version => @frame.version, :type => :text, :data => msg, :decoded => true)
70
+ msg.force_encoding('UTF-8')
71
+ @frame.class.new(version: @frame.version, type: :text, data: msg, decoded: true)
71
72
  end
72
73
  end
73
74
  end
@@ -4,7 +4,7 @@ module WebSocket
4
4
  # @note You should NEVER use this class directly - use Client or Server subclasses instead, as they contain additional frame options(i.e. Client-side masking in draft 04)
5
5
  #
6
6
  # @example
7
- # frame = WebSocket::Frame::Incoming::Server.new(:version => @handshake.version)
7
+ # frame = WebSocket::Frame::Incoming::Server.new(version: @handshake.version)
8
8
  # frame << "\x81\x05\x48\x65\x6c\x6c\x6f\x81\x06\x77\x6f\x72\x6c\x64\x21"
9
9
  # frame.next # "Hello"
10
10
  # frame.next # "world!""
@@ -4,7 +4,7 @@ module WebSocket
4
4
  # @note You should NEVER use this class directly - use Client or Server subclasses instead, as they contain additional frame options(i.e. Client-side masking in draft 04)
5
5
  #
6
6
  # @example
7
- # frame = WebSocket::Frame::Outgoing::Server.new(:version => @handshake.version, :data => "Hello", :type => :text)
7
+ # frame = WebSocket::Frame::Outgoing::Server.new(version: @handshake.version, data: "Hello", type: :text)
8
8
  # frame.to_s # "\x81\x05\x48\x65\x6c\x6c\x6f"
9
9
  class Outgoing < Base
10
10
 
@@ -12,7 +12,7 @@ module WebSocket
12
12
  @state = :new
13
13
  @handler = nil
14
14
 
15
- @data = ""
15
+ @data = ''
16
16
  @headers = {}
17
17
  end
18
18
 
@@ -24,13 +24,13 @@ module WebSocket
24
24
  # Return textual representation of handshake request or response
25
25
  # @return [String] text of response
26
26
  def to_s
27
- @handler ? @handler.to_s : ""
27
+ @handler ? @handler.to_s : ''
28
28
  end
29
- rescue_method :to_s, :return => ""
29
+ rescue_method :to_s, return: ''
30
30
 
31
31
  # Recreate inspect as #to_s was overwritten
32
32
  def inspect
33
- vars = self.instance_variables.map{|v| "#{v}=#{instance_variable_get(v).inspect}"}.join(", ")
33
+ vars = self.instance_variables.map { |v| "#{v}=#{instance_variable_get(v).inspect}" }.join(', ')
34
34
  insp = "#{self.class}:0x%08x" % (self.__id__ * 2)
35
35
  "<#{insp} #{vars}>"
36
36
  end
@@ -46,7 +46,7 @@ module WebSocket
46
46
  def valid?
47
47
  finished? && @error == nil && @handler && @handler.valid?
48
48
  end
49
- rescue_method :valid?, :return => false
49
+ rescue_method :valid?, return: false
50
50
 
51
51
  # @abstract Should send data after parsing is finished?
52
52
  def should_respond?
@@ -56,7 +56,7 @@ module WebSocket
56
56
  # Data left from parsing. Sometimes data that doesn't belong to handshake are added - use this method to retrieve them.
57
57
  # @return [String] String if some data are available. Nil otherwise
58
58
  def leftovers
59
- @leftovers.split("\n", reserved_leftover_lines + 1)[reserved_leftover_lines]
59
+ @leftovers.to_s.split("\n", reserved_leftover_lines + 1)[reserved_leftover_lines]
60
60
  end
61
61
 
62
62
  # URI of request.
@@ -64,7 +64,7 @@ module WebSocket
64
64
  # @example
65
65
  # @handshake.uri #=> "ws://example.com/path?query=true"
66
66
  def uri
67
- uri = secure ? "wss://" : "ws://"
67
+ uri = secure ? 'wss://' : 'ws://'
68
68
  uri << host
69
69
  uri << ":#{port}" if port
70
70
  uri << path
@@ -5,7 +5,7 @@ module WebSocket
5
5
  # Construct or parse a client WebSocket handshake.
6
6
  #
7
7
  # @example
8
- # @handshake = WebSocket::Handshake::Client.new(:url => 'ws://example.com')
8
+ # @handshake = WebSocket::Handshake::Client.new(url: 'ws://example.com')
9
9
  #
10
10
  # # Create request
11
11
  # @handshake.to_s # GET /demo HTTP/1.1
@@ -33,7 +33,7 @@ module WebSocket
33
33
  #
34
34
  class Client < Base
35
35
 
36
- attr_reader :origin
36
+ attr_reader :origin, :headers
37
37
 
38
38
  # Initialize new WebSocket Client
39
39
  #
@@ -48,14 +48,16 @@ module WebSocket
48
48
  # @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.
49
49
  # @option args [String] :uri Alias to :url
50
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
- # Websocket::Handshake::Client.new(:url => "ws://example.com/path?query=true")
54
+ # Websocket::Handshake::Client.new(url: "ws://example.com/path?query=true")
54
55
  def initialize(args = {})
55
56
  super
56
57
 
57
58
  @version = args[:version] || DEFAULT_VERSION
58
59
  @origin = args[:origin]
60
+ @headers = args[:headers] || {}
59
61
 
60
62
  if args[:url] || args[:uri]
61
63
  uri = URI.parse(args[:url] || args[:uri])