websocket 1.2.3 → 1.2.9

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 (76) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +17 -0
  3. data/.github/workflows/publish.yml +17 -0
  4. data/.rubocop.yml +35 -3
  5. data/.travis.yml +14 -7
  6. data/CHANGELOG.md +24 -0
  7. data/Gemfile +12 -4
  8. data/README.md +3 -2
  9. data/Rakefile +8 -3
  10. data/lib/websocket.rb +4 -1
  11. data/lib/websocket/error.rb +8 -0
  12. data/lib/websocket/exception_handler.rb +3 -1
  13. data/lib/websocket/frame.rb +2 -0
  14. data/lib/websocket/frame/base.rb +5 -9
  15. data/lib/websocket/frame/data.rb +5 -2
  16. data/lib/websocket/frame/handler.rb +2 -0
  17. data/lib/websocket/frame/handler/base.rb +6 -4
  18. data/lib/websocket/frame/handler/handler03.rb +23 -16
  19. data/lib/websocket/frame/handler/handler04.rb +1 -0
  20. data/lib/websocket/frame/handler/handler05.rb +1 -0
  21. data/lib/websocket/frame/handler/handler07.rb +10 -9
  22. data/lib/websocket/frame/handler/handler75.rb +8 -7
  23. data/lib/websocket/frame/incoming.rb +2 -0
  24. data/lib/websocket/frame/incoming/client.rb +2 -0
  25. data/lib/websocket/frame/incoming/server.rb +2 -0
  26. data/lib/websocket/frame/outgoing.rb +3 -1
  27. data/lib/websocket/frame/outgoing/client.rb +2 -0
  28. data/lib/websocket/frame/outgoing/server.rb +2 -0
  29. data/lib/websocket/handshake.rb +2 -0
  30. data/lib/websocket/handshake/base.rb +26 -13
  31. data/lib/websocket/handshake/client.rb +17 -14
  32. data/lib/websocket/handshake/handler.rb +2 -0
  33. data/lib/websocket/handshake/handler/base.rb +2 -0
  34. data/lib/websocket/handshake/handler/client.rb +11 -0
  35. data/lib/websocket/handshake/handler/client01.rb +2 -0
  36. data/lib/websocket/handshake/handler/client04.rb +15 -4
  37. data/lib/websocket/handshake/handler/client11.rb +2 -0
  38. data/lib/websocket/handshake/handler/client75.rb +18 -2
  39. data/lib/websocket/handshake/handler/client76.rb +11 -5
  40. data/lib/websocket/handshake/handler/server.rb +2 -0
  41. data/lib/websocket/handshake/handler/server04.rb +12 -4
  42. data/lib/websocket/handshake/handler/server75.rb +21 -5
  43. data/lib/websocket/handshake/handler/server76.rb +14 -16
  44. data/lib/websocket/handshake/server.rb +7 -4
  45. data/lib/websocket/nice_inspect.rb +12 -0
  46. data/lib/websocket/version.rb +3 -1
  47. data/spec/frame/incoming_03_spec.rb +20 -17
  48. data/spec/frame/incoming_04_spec.rb +20 -17
  49. data/spec/frame/incoming_05_spec.rb +22 -19
  50. data/spec/frame/incoming_07_spec.rb +24 -21
  51. data/spec/frame/incoming_75_spec.rb +13 -10
  52. data/spec/frame/incoming_common_spec.rb +18 -8
  53. data/spec/frame/masking_spec.rb +3 -1
  54. data/spec/frame/outgoing_03_spec.rb +13 -10
  55. data/spec/frame/outgoing_04_spec.rb +13 -10
  56. data/spec/frame/outgoing_05_spec.rb +12 -9
  57. data/spec/frame/outgoing_07_spec.rb +13 -10
  58. data/spec/frame/outgoing_75_spec.rb +8 -5
  59. data/spec/frame/outgoing_common_spec.rb +11 -4
  60. data/spec/handshake/client_04_spec.rb +46 -3
  61. data/spec/handshake/client_11_spec.rb +5 -3
  62. data/spec/handshake/client_75_spec.rb +28 -1
  63. data/spec/handshake/client_76_spec.rb +30 -3
  64. data/spec/handshake/server_04_spec.rb +37 -4
  65. data/spec/handshake/server_75_spec.rb +25 -1
  66. data/spec/handshake/server_76_spec.rb +33 -9
  67. data/spec/spec_helper.rb +2 -2
  68. data/spec/support/all_client_drafts.rb +23 -21
  69. data/spec/support/all_server_drafts.rb +21 -16
  70. data/spec/support/frames_base.rb +2 -0
  71. data/spec/support/handshake_requests.rb +19 -17
  72. data/spec/support/incoming_frames.rb +46 -25
  73. data/spec/support/outgoing_frames.rb +30 -8
  74. data/spec/support/overwrites.rb +2 -0
  75. data/websocket.gemspec +4 -1
  76. metadata +7 -5
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  RSpec.describe 'Client draft 76 handshake' do
@@ -7,14 +9,39 @@ RSpec.describe 'Client draft 76 handshake' do
7
9
  let(:client_request) { client_handshake_76({ key1: handshake.handler.send(:key1), key2: handshake.handler.send(:key2), key3: handshake.handler.send(:key3) }.merge(@request_params || {})) }
8
10
  let(:server_response) { server_handshake_76({ challenge: handshake.handler.send(:challenge) }.merge(@request_params || {})) }
9
11
 
10
- it_should_behave_like 'all client drafts'
12
+ it_behaves_like 'all client drafts'
11
13
 
12
- it 'should disallow client with invalid challenge' do
14
+ it 'disallows client with invalid challenge' do
13
15
  @request_params = { challenge: 'invalid' }
14
16
  handshake << server_response
15
17
 
16
18
  expect(handshake).to be_finished
17
19
  expect(handshake).not_to be_valid
18
- expect(handshake.error).to eql(:invalid_handshake_authentication)
20
+ expect(handshake.error).to be(:invalid_handshake_authentication)
21
+ end
22
+
23
+ context 'protocol header specified' do
24
+ let(:handshake) { WebSocket::Handshake::Client.new(uri: 'ws://example.com/demo', origin: 'http://example.com', version: version, protocols: %w[binary]) }
25
+
26
+ context 'supported' do
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 'unsupported' do
37
+ it 'fails with an unsupported protocol error' do
38
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'xmpp' } }
39
+ handshake << server_response
40
+
41
+ expect(handshake).to be_finished
42
+ expect(handshake).not_to be_valid
43
+ expect(handshake.error).to be(:unsupported_protocol)
44
+ end
45
+ end
19
46
  end
20
47
  end
@@ -1,18 +1,51 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  RSpec.describe 'Server draft 04 handshake' do
4
6
  let(:handshake) { WebSocket::Handshake::Server.new }
5
- let(:version) { 04 }
7
+ let(:version) { 4 }
6
8
  let(:client_request) { client_handshake_04(@request_params || {}) }
7
9
  let(:server_response) { server_handshake_04(@request_params || {}) }
8
10
 
9
- it_should_behave_like 'all server drafts'
11
+ it_behaves_like 'all server drafts'
10
12
 
11
- it 'should disallow request without Sec-WebSocket-Key' do
13
+ it 'disallows request without Sec-WebSocket-Key' do
12
14
  handshake << client_request.gsub(/^Sec-WebSocket-Key:.*\n/, '')
13
15
 
14
16
  expect(handshake).to be_finished
15
17
  expect(handshake).not_to be_valid
16
- expect(handshake.error).to eql(:invalid_handshake_authentication)
18
+ expect(handshake.error).to be(:invalid_handshake_authentication)
19
+ end
20
+
21
+ context 'protocol header specified' do
22
+ let(:handshake) { WebSocket::Handshake::Server.new(protocols: %w[binary xmpp]) }
23
+
24
+ context 'single protocol requested' do
25
+ it 'returns with the same protocol' do
26
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'binary' } }
27
+ handshake << client_request
28
+
29
+ expect(handshake.to_s).to match('Sec-WebSocket-Protocol: binary')
30
+ end
31
+ end
32
+
33
+ context 'multiple protocols requested' do
34
+ it 'returns with the first supported protocol' do
35
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'xmpp, binary' } }
36
+ handshake << client_request
37
+
38
+ expect(handshake.to_s).to match('Sec-WebSocket-Protocol: xmpp')
39
+ end
40
+ end
41
+
42
+ context 'unsupported protocol requested' do
43
+ it 'reutrns with an empty protocol header' do
44
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'generic' } }
45
+ handshake << client_request
46
+
47
+ expect(handshake.to_s).to match("Sec-WebSocket-Protocol: \r\n")
48
+ end
49
+ end
17
50
  end
18
51
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  RSpec.describe 'Server draft 75 handshake' do
@@ -7,5 +9,27 @@ RSpec.describe 'Server draft 75 handshake' do
7
9
  let(:client_request) { client_handshake_75(@request_params || {}) }
8
10
  let(:server_response) { server_handshake_75(@request_params || {}) }
9
11
 
10
- it_should_behave_like 'all server drafts'
12
+ it_behaves_like 'all server drafts'
13
+
14
+ context 'protocol header specified' do
15
+ let(:handshake) { WebSocket::Handshake::Server.new(protocols: %w[binary]) }
16
+
17
+ context 'supported' do
18
+ it 'returns with the same protocol' do
19
+ @request_params = { headers: { 'WebSocket-Protocol' => 'binary' } }
20
+ handshake << client_request
21
+
22
+ expect(handshake.to_s).to match('WebSocket-Protocol: binary')
23
+ end
24
+ end
25
+
26
+ context 'unsupported' do
27
+ it 'returns with an empty protocol header' do
28
+ @request_params = { headers: { 'WebSocket-Protocol' => 'xmpp' } }
29
+ handshake << client_request
30
+
31
+ expect(handshake.to_s).to match("WebSocket-Protocol: \r\n")
32
+ end
33
+ end
34
+ end
11
35
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  RSpec.describe 'Server draft 76 handshake' do
@@ -6,41 +8,63 @@ RSpec.describe 'Server draft 76 handshake' do
6
8
  let(:client_request) { client_handshake_76(@request_params || {}) }
7
9
  let(:server_response) { server_handshake_76(@request_params || {}) }
8
10
 
9
- it_should_behave_like 'all server drafts'
11
+ it_behaves_like 'all server drafts'
10
12
 
11
- it 'should disallow request without spaces in key 1' do
13
+ it 'disallows request without spaces in key 1' do
12
14
  @request_params = { key1: '4@146546xW%0l15' }
13
15
  handshake << client_request
14
16
 
15
17
  expect(handshake).to be_finished
16
18
  expect(handshake).not_to be_valid
17
- expect(handshake.error).to eql(:invalid_handshake_authentication)
19
+ expect(handshake.error).to be(:invalid_handshake_authentication)
18
20
  end
19
21
 
20
- it 'should disallow request without spaces in key 2' do
22
+ it 'disallows request without spaces in key 2' do
21
23
  @request_params = { key2: '129985Y31.P00' }
22
24
  handshake << client_request
23
25
 
24
26
  expect(handshake).to be_finished
25
27
  expect(handshake).not_to be_valid
26
- expect(handshake.error).to eql(:invalid_handshake_authentication)
28
+ expect(handshake.error).to be(:invalid_handshake_authentication)
27
29
  end
28
30
 
29
- it 'should disallow request with invalid number of spaces or numbers in key 1' do
31
+ it 'disallows request with invalid number of spaces or numbers in key 1' do
30
32
  @request_params = { key1: '4 @1 46546xW%0l 1 5' }
31
33
  handshake << client_request
32
34
 
33
35
  expect(handshake).to be_finished
34
36
  expect(handshake).not_to be_valid
35
- expect(handshake.error).to eql(:invalid_handshake_authentication)
37
+ expect(handshake.error).to be(:invalid_handshake_authentication)
36
38
  end
37
39
 
38
- it 'should disallow request with invalid number of spaces or numbers in key 2' do
40
+ it 'disallows request with invalid number of spaces or numbers in key 2' do
39
41
  @request_params = { key2: '12998 5 Y3 1 .P00' }
40
42
  handshake << client_request
41
43
 
42
44
  expect(handshake).to be_finished
43
45
  expect(handshake).not_to be_valid
44
- expect(handshake.error).to eql(:invalid_handshake_authentication)
46
+ expect(handshake.error).to be(:invalid_handshake_authentication)
47
+ end
48
+
49
+ context 'protocol header specified' do
50
+ let(:handshake) { WebSocket::Handshake::Server.new(protocols: %w[binary]) }
51
+
52
+ context 'supported' do
53
+ it 'returns with the same protocol' do
54
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'binary' } }
55
+ handshake << client_request
56
+
57
+ expect(handshake.to_s).to match('Sec-WebSocket-Protocol: binary')
58
+ end
59
+ end
60
+
61
+ context 'unsupported' do
62
+ it 'returns with an empty protocol header' do
63
+ @request_params = { headers: { 'Sec-WebSocket-Protocol' => 'xmpp' } }
64
+ handshake << client_request
65
+
66
+ expect(handshake.to_s).to match("Sec-WebSocket-Protocol: \r\n")
67
+ end
68
+ end
45
69
  end
46
70
  end
@@ -1,6 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rspec'
2
- require 'rspec/its'
3
- require 'webrick'
4
4
 
5
5
  require 'websocket'
6
6
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.shared_examples_for 'all client drafts' do
2
4
  def validate_request
3
5
  expect(handshake.to_s).to eql(client_request)
@@ -9,7 +11,7 @@ RSpec.shared_examples_for 'all client drafts' do
9
11
  expect(handshake).to be_valid
10
12
  end
11
13
 
12
- it 'should be valid' do
14
+ it 'is valid' do
13
15
  handshake << server_response
14
16
 
15
17
  expect(handshake.error).to be_nil
@@ -17,92 +19,92 @@ RSpec.shared_examples_for 'all client drafts' do
17
19
  expect(handshake).to be_valid
18
20
  end
19
21
 
20
- it 'should return valid version' do
22
+ it 'returns valid version' do
21
23
  expect(handshake.version).to eql(version)
22
24
  end
23
25
 
24
- it 'should return valid host' do
26
+ it 'returns valid host' do
25
27
  @request_params = { host: 'www.test.cc' }
26
28
  expect(handshake.host).to eql('www.test.cc')
27
29
  end
28
30
 
29
- it 'should return valid path' do
31
+ it 'returns valid path' do
30
32
  @request_params = { path: '/custom' }
31
33
  expect(handshake.path).to eql('/custom')
32
34
  end
33
35
 
34
- it 'should return valid query' do
36
+ it 'returns valid query' do
35
37
  @request_params = { query: 'aaa=bbb' }
36
38
  expect(handshake.query).to eql('aaa=bbb')
37
39
  end
38
40
 
39
- it 'should return valid port' do
41
+ it 'returns valid port' do
40
42
  @request_params = { port: 123 }
41
- expect(handshake.port).to eql(123)
43
+ expect(handshake.port).to be(123)
42
44
  end
43
45
 
44
- it 'should return valid headers' do
46
+ it 'returns valid headers' do
45
47
  @request_params = { headers: { 'aaa' => 'bbb' } }
46
48
  expect(handshake.headers).to eql('aaa' => 'bbb')
47
49
  end
48
50
 
49
- it 'should parse uri' do
51
+ it 'parses uri' do
50
52
  @request_params = { uri: 'ws://test.example.org:301/test_path?query=true' }
51
53
  expect(handshake.host).to eql('test.example.org')
52
- expect(handshake.port).to eql(301)
54
+ expect(handshake.port).to be(301)
53
55
  expect(handshake.path).to eql('/test_path')
54
56
  expect(handshake.query).to eql('query=true')
55
57
  end
56
58
 
57
- it 'should parse url' do
59
+ it 'parses url' do
58
60
  @request_params = { url: 'ws://test.example.org:301/test_path?query=true' }
59
61
  expect(handshake.host).to eql('test.example.org')
60
- expect(handshake.port).to eql(301)
62
+ expect(handshake.port).to be(301)
61
63
  expect(handshake.path).to eql('/test_path')
62
64
  expect(handshake.query).to eql('query=true')
63
65
  end
64
66
 
65
- it 'should resolve correct path with root server provided' do
67
+ it 'resolves correct path with root server provided' do
66
68
  @request_params = { url: 'ws://test.example.org' }
67
69
  expect(handshake.path).to eql('/')
68
70
  end
69
71
 
70
- it 'should return valid response' do
72
+ it 'returns valid response' do
71
73
  validate_request
72
74
  end
73
75
 
74
- it 'should allow custom path' do
76
+ it 'allows custom path' do
75
77
  @request_params = { path: '/custom' }
76
78
  validate_request
77
79
  end
78
80
 
79
- it 'should allow query in path' do
81
+ it 'allows query in path' do
80
82
  @request_params = { query: 'test=true' }
81
83
  validate_request
82
84
  end
83
85
 
84
- it 'should allow custom port' do
86
+ it 'allows custom port' do
85
87
  @request_params = { port: 123 }
86
88
  validate_request
87
89
  end
88
90
 
89
- it 'should allow custom headers' do
91
+ it 'allows custom headers' do
90
92
  @request_params = { headers: { 'aaa' => 'bbb' } }
91
93
  validate_request
92
94
  end
93
95
 
94
- it 'should recognize unfinished requests' do
96
+ it 'recognizes unfinished requests' do
95
97
  handshake << server_response[0..-20]
96
98
 
97
99
  expect(handshake).not_to be_finished
98
100
  expect(handshake).not_to be_valid
99
101
  end
100
102
 
101
- it 'should disallow requests with invalid request method' do
103
+ it 'disallows requests with invalid request method' do
102
104
  handshake << server_response.gsub('101', '404')
103
105
 
104
106
  expect(handshake).to be_finished
105
107
  expect(handshake).not_to be_valid
106
- expect(handshake.error).to eql(:invalid_status_code)
108
+ expect(handshake.error).to be(:invalid_status_code)
107
109
  end
108
110
  end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'webrick'
4
+
1
5
  RSpec.shared_examples_for 'all server drafts' do
2
6
  def validate_request
3
7
  handshake << client_request
@@ -8,7 +12,7 @@ RSpec.shared_examples_for 'all server drafts' do
8
12
  expect(handshake.to_s).to eql(server_response)
9
13
  end
10
14
 
11
- it 'should be valid' do
15
+ it 'is valid' do
12
16
  handshake << client_request
13
17
 
14
18
  expect(handshake.error).to be_nil
@@ -16,86 +20,87 @@ RSpec.shared_examples_for 'all server drafts' do
16
20
  expect(handshake).to be_valid
17
21
  end
18
22
 
19
- it 'should return valid version' do
23
+ it 'returns valid version' do
20
24
  handshake << client_request
21
25
 
22
26
  expect(handshake.version).to eql(version)
23
27
  end
24
28
 
25
- it 'should return valid host' do
29
+ it 'returns valid host' do
26
30
  @request_params = { host: 'www.test.cc' }
27
31
  handshake << client_request
28
32
 
29
33
  expect(handshake.host).to eql('www.test.cc')
30
34
  end
31
35
 
32
- it 'should return valid path' do
36
+ it 'returns valid path' do
33
37
  @request_params = { path: '/custom' }
34
38
  handshake << client_request
35
39
 
36
40
  expect(handshake.path).to eql('/custom')
37
41
  end
38
42
 
39
- it 'should return valid query' do
43
+ it 'returns valid query' do
40
44
  @request_params = { path: '/custom?aaa=bbb' }
41
45
  handshake << client_request
42
46
 
43
47
  expect(handshake.query).to eql('aaa=bbb')
44
48
  end
45
49
 
46
- it 'should return valid port' do
50
+ it 'returns valid port' do
47
51
  @request_params = { port: 123 }
48
52
  handshake << client_request
49
53
 
50
54
  expect(handshake.port).to eql('123')
51
55
  end
52
56
 
53
- it 'should return valid response' do
57
+ it 'returns valid response' do
54
58
  validate_request
55
59
  end
56
60
 
57
- it 'should allow custom path' do
61
+ it 'allows custom path' do
58
62
  @request_params = { path: '/custom' }
59
63
  validate_request
60
64
  end
61
65
 
62
- it 'should allow query in path' do
66
+ it 'allows query in path' do
63
67
  @request_params = { path: '/custom?test=true' }
64
68
  validate_request
65
69
  end
66
70
 
67
- it 'should allow custom port' do
71
+ it 'allows custom port' do
68
72
  @request_params = { port: 123 }
69
73
  validate_request
70
74
  end
71
75
 
72
- it 'should recognize unfinished requests' do
76
+ it 'recognizes unfinished requests' do
73
77
  handshake << client_request[0..-10]
74
78
 
75
79
  expect(handshake).not_to be_finished
76
80
  expect(handshake).not_to be_valid
77
81
  end
78
82
 
79
- it 'should disallow requests with invalid request method' do
83
+ it 'disallows requests with invalid request method' do
80
84
  handshake << client_request.gsub('GET', 'POST')
81
85
 
82
86
  expect(handshake).to be_finished
83
87
  expect(handshake).not_to be_valid
84
- expect(handshake.error).to eql(:get_request_required)
88
+ expect(handshake.error).to be(:get_request_required)
85
89
  end
86
90
 
87
- it 'should parse a rack request' do
91
+ it 'parses a rack request' do
88
92
  request = WEBrick::HTTPRequest.new(ServerSoftware: 'rspec')
89
93
  expect(request.parse(StringIO.new(client_request))).to be true
90
94
  rest = client_request.slice((request.to_s.length..-1))
91
95
 
92
96
  handshake.from_rack(request.meta_vars.merge(
93
- 'rack.input' => StringIO.new(rest)
97
+ 'rack.input' => StringIO.new(rest),
98
+ :random_key => :random_value
94
99
  ))
95
100
  validate_request
96
101
  end
97
102
 
98
- it 'should parse a hash request' do
103
+ it 'parses a hash request' do
99
104
  request = WEBrick::HTTPRequest.new(ServerSoftware: 'rspec')
100
105
  expect(request.parse(StringIO.new(client_request))).to be true
101
106
  body = client_request.slice((request.to_s.length..-1))