websocket 1.2.2 → 1.2.3
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +37 -0
- data/.travis.yml +2 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +1 -1
- data/Rakefile +3 -3
- data/lib/websocket.rb +2 -3
- data/lib/websocket/error.rb +57 -25
- data/lib/websocket/exception_handler.rb +2 -14
- data/lib/websocket/frame.rb +0 -2
- data/lib/websocket/frame/base.rb +12 -13
- data/lib/websocket/frame/data.rb +1 -3
- data/lib/websocket/frame/handler.rb +0 -2
- data/lib/websocket/frame/handler/base.rb +2 -4
- data/lib/websocket/frame/handler/handler03.rb +149 -112
- data/lib/websocket/frame/handler/handler04.rb +3 -3
- data/lib/websocket/frame/handler/handler05.rb +3 -3
- data/lib/websocket/frame/handler/handler07.rb +8 -10
- data/lib/websocket/frame/handler/handler75.rb +10 -12
- data/lib/websocket/frame/incoming.rb +0 -2
- data/lib/websocket/frame/incoming/client.rb +0 -2
- data/lib/websocket/frame/incoming/server.rb +0 -2
- data/lib/websocket/frame/outgoing.rb +1 -3
- data/lib/websocket/frame/outgoing/client.rb +0 -2
- data/lib/websocket/frame/outgoing/server.rb +0 -2
- data/lib/websocket/handshake.rb +0 -2
- data/lib/websocket/handshake/base.rb +10 -9
- data/lib/websocket/handshake/client.rb +22 -35
- data/lib/websocket/handshake/handler.rb +0 -2
- data/lib/websocket/handshake/handler/base.rb +0 -2
- data/lib/websocket/handshake/handler/client.rb +0 -2
- data/lib/websocket/handshake/handler/client01.rb +0 -2
- data/lib/websocket/handshake/handler/client04.rb +3 -5
- data/lib/websocket/handshake/handler/client11.rb +0 -2
- data/lib/websocket/handshake/handler/client75.rb +2 -4
- data/lib/websocket/handshake/handler/client76.rb +6 -8
- data/lib/websocket/handshake/handler/server.rb +0 -1
- data/lib/websocket/handshake/handler/server04.rb +3 -5
- data/lib/websocket/handshake/handler/server75.rb +2 -4
- data/lib/websocket/handshake/handler/server76.rb +7 -9
- data/lib/websocket/handshake/server.rb +19 -24
- data/lib/websocket/version.rb +1 -1
- data/spec/frame/incoming_03_spec.rb +1 -2
- data/spec/frame/incoming_04_spec.rb +1 -2
- data/spec/frame/incoming_05_spec.rb +1 -2
- data/spec/frame/incoming_07_spec.rb +1 -2
- data/spec/frame/incoming_75_spec.rb +1 -2
- data/spec/support/all_client_drafts.rb +1 -1
- data/spec/support/all_server_drafts.rb +7 -10
- data/spec/support/frames_base.rb +0 -2
- data/spec/support/handshake_requests.rb +4 -4
- data/spec/support/outgoing_frames.rb +0 -1
- data/spec/support/overwrites.rb +0 -2
- data/websocket.gemspec +10 -10
- metadata +4 -3
@@ -3,7 +3,6 @@ module WebSocket
|
|
3
3
|
module Handler
|
4
4
|
# This class and it's descendants are included in client or server handshake in order to extend basic functionality
|
5
5
|
class Base
|
6
|
-
|
7
6
|
def initialize(handshake)
|
8
7
|
@handshake = handshake
|
9
8
|
end
|
@@ -42,7 +41,6 @@ module WebSocket
|
|
42
41
|
def finishing_line
|
43
42
|
''
|
44
43
|
end
|
45
|
-
|
46
44
|
end
|
47
45
|
end
|
48
46
|
end
|
@@ -2,7 +2,6 @@ module WebSocket
|
|
2
2
|
module Handshake
|
3
3
|
module Handler
|
4
4
|
class Client < Base
|
5
|
-
|
6
5
|
private
|
7
6
|
|
8
7
|
# @see WebSocket::Handshake::Handler::Base#header_line
|
@@ -16,7 +15,6 @@ module WebSocket
|
|
16
15
|
def handshake_keys
|
17
16
|
super + @handshake.headers.to_a
|
18
17
|
end
|
19
|
-
|
20
18
|
end
|
21
19
|
end
|
22
20
|
end
|
@@ -4,7 +4,6 @@ module WebSocket
|
|
4
4
|
module Handshake
|
5
5
|
module Handler
|
6
6
|
class Client01 < Client76
|
7
|
-
|
8
7
|
private
|
9
8
|
|
10
9
|
# @see WebSocket::Handshake::Handler::Base#handshake_keys
|
@@ -13,7 +12,6 @@ module WebSocket
|
|
13
12
|
keys << ['Sec-WebSocket-Draft', @handshake.version]
|
14
13
|
keys
|
15
14
|
end
|
16
|
-
|
17
15
|
end
|
18
16
|
end
|
19
17
|
end
|
@@ -5,7 +5,6 @@ module WebSocket
|
|
5
5
|
module Handshake
|
6
6
|
module Handler
|
7
7
|
class Client04 < Client
|
8
|
-
|
9
8
|
# @see WebSocket::Handshake::Base#valid?
|
10
9
|
def valid?
|
11
10
|
super && verify_accept
|
@@ -16,8 +15,8 @@ module WebSocket
|
|
16
15
|
# @see WebSocket::Handshake::Handler::Base#handshake_keys
|
17
16
|
def handshake_keys
|
18
17
|
keys = [
|
19
|
-
|
20
|
-
|
18
|
+
%w(Upgrade websocket),
|
19
|
+
%w(Connection Upgrade)
|
21
20
|
]
|
22
21
|
host = @handshake.host
|
23
22
|
host += ":#{@handshake.port}" if @handshake.port
|
@@ -44,10 +43,9 @@ module WebSocket
|
|
44
43
|
# Verify if received header Sec-WebSocket-Accept matches generated one.
|
45
44
|
# @return [Boolean] True if accept is matching. False otherwise(appropriate error is set)
|
46
45
|
def verify_accept
|
47
|
-
|
46
|
+
fail WebSocket::Error::Handshake::InvalidAuthentication unless @handshake.headers['sec-websocket-accept'] == accept
|
48
47
|
true
|
49
48
|
end
|
50
|
-
|
51
49
|
end
|
52
50
|
end
|
53
51
|
end
|
@@ -2,14 +2,13 @@ module WebSocket
|
|
2
2
|
module Handshake
|
3
3
|
module Handler
|
4
4
|
class Client75 < Client
|
5
|
-
|
6
5
|
private
|
7
6
|
|
8
7
|
# @see WebSocket::Handshake::Handler::Base#handshake_keys
|
9
8
|
def handshake_keys
|
10
9
|
keys = [
|
11
|
-
|
12
|
-
|
10
|
+
%w(Upgrade WebSocket),
|
11
|
+
%w(Connection Upgrade)
|
13
12
|
]
|
14
13
|
host = @handshake.host
|
15
14
|
host += ":#{@handshake.port}" if @handshake.port
|
@@ -18,7 +17,6 @@ module WebSocket
|
|
18
17
|
keys += super
|
19
18
|
keys
|
20
19
|
end
|
21
|
-
|
22
20
|
end
|
23
21
|
end
|
24
22
|
end
|
@@ -4,7 +4,6 @@ module WebSocket
|
|
4
4
|
module Handshake
|
5
5
|
module Handler
|
6
6
|
class Client76 < Client75
|
7
|
-
|
8
7
|
# @see WebSocket::Handshake::Base#valid?
|
9
8
|
def valid?
|
10
9
|
super && verify_challenge
|
@@ -57,17 +56,17 @@ module WebSocket
|
|
57
56
|
[@key2_number].pack('N*') +
|
58
57
|
key3
|
59
58
|
|
60
|
-
@challenge = Digest::MD5.digest(sum)
|
59
|
+
@challenge = Digest::MD5.digest(sum).strip
|
61
60
|
end
|
62
61
|
|
63
62
|
# Verify if challenge sent by server match generated one
|
64
63
|
# @return [Boolena] True if challenge matches, false otherwise(sets appropriate error)
|
65
64
|
def verify_challenge
|
66
|
-
|
65
|
+
fail WebSocket::Error::Handshake::InvalidAuthentication unless @handshake.leftovers == challenge
|
67
66
|
true
|
68
67
|
end
|
69
68
|
|
70
|
-
NOISE_CHARS = ("\x21".."\x2f").to_a
|
69
|
+
NOISE_CHARS = ("\x21".."\x2f").to_a + ("\x3a".."\x7e").to_a
|
71
70
|
|
72
71
|
# Generate Sec-WebSocket-Key1 and Sec-WebSocket-Key2
|
73
72
|
# @param [String] name of key. Will be used to set number variable needed later. Valid values: key1, key2
|
@@ -78,23 +77,22 @@ module WebSocket
|
|
78
77
|
number = rand(max + 1)
|
79
78
|
instance_variable_set("@#{key}_number", number)
|
80
79
|
key = (number * spaces).to_s
|
81
|
-
(1 + rand(12)).times
|
80
|
+
(1 + rand(12)).times do
|
82
81
|
char = NOISE_CHARS[rand(NOISE_CHARS.size)]
|
83
82
|
pos = rand(key.size + 1)
|
84
83
|
key[pos...pos] = char
|
85
84
|
end
|
86
|
-
spaces.times
|
85
|
+
spaces.times do
|
87
86
|
pos = 1 + rand(key.size - 1)
|
88
87
|
key[pos...pos] = ' '
|
89
88
|
end
|
90
|
-
|
89
|
+
key
|
91
90
|
end
|
92
91
|
|
93
92
|
# Generate third key
|
94
93
|
def generate_key3
|
95
94
|
[rand(0x100000000)].pack('N') + [rand(0x100000000)].pack('N')
|
96
95
|
end
|
97
|
-
|
98
96
|
end
|
99
97
|
end
|
100
98
|
end
|
@@ -5,7 +5,6 @@ module WebSocket
|
|
5
5
|
module Handshake
|
6
6
|
module Handler
|
7
7
|
class Server04 < Server
|
8
|
-
|
9
8
|
# @see WebSocket::Handshake::Base#valid?
|
10
9
|
def valid?
|
11
10
|
super && verify_key
|
@@ -21,8 +20,8 @@ module WebSocket
|
|
21
20
|
# @see WebSocket::Handshake::Handler::Base#handshake_keys
|
22
21
|
def handshake_keys
|
23
22
|
[
|
24
|
-
|
25
|
-
|
23
|
+
%w(Upgrade websocket),
|
24
|
+
%w(Connection Upgrade),
|
26
25
|
['Sec-WebSocket-Accept', signature]
|
27
26
|
]
|
28
27
|
end
|
@@ -36,14 +35,13 @@ module WebSocket
|
|
36
35
|
end
|
37
36
|
|
38
37
|
def verify_key
|
39
|
-
|
38
|
+
fail WebSocket::Error::Handshake::InvalidAuthentication unless key
|
40
39
|
true
|
41
40
|
end
|
42
41
|
|
43
42
|
def key
|
44
43
|
@handshake.headers['sec-websocket-key']
|
45
44
|
end
|
46
|
-
|
47
45
|
end
|
48
46
|
end
|
49
47
|
end
|
@@ -2,7 +2,6 @@ module WebSocket
|
|
2
2
|
module Handshake
|
3
3
|
module Handler
|
4
4
|
class Server75 < Server
|
5
|
-
|
6
5
|
private
|
7
6
|
|
8
7
|
# @see WebSocket::Handshake::Handler::Base#header_line
|
@@ -13,13 +12,12 @@ module WebSocket
|
|
13
12
|
# @see WebSocket::Handshake::Handler::Base#handshake_keys
|
14
13
|
def handshake_keys
|
15
14
|
[
|
16
|
-
|
17
|
-
|
15
|
+
%w(Upgrade WebSocket),
|
16
|
+
%w(Connection Upgrade),
|
18
17
|
['WebSocket-Origin', @handshake.headers['origin']],
|
19
18
|
['WebSocket-Location', @handshake.uri]
|
20
19
|
]
|
21
20
|
end
|
22
|
-
|
23
21
|
end
|
24
22
|
end
|
25
23
|
end
|
@@ -4,10 +4,9 @@ module WebSocket
|
|
4
4
|
module Handshake
|
5
5
|
module Handler
|
6
6
|
class Server76 < Server
|
7
|
-
|
8
7
|
# @see WebSocket::Handshake::Base#valid?
|
9
8
|
def valid?
|
10
|
-
super &&
|
9
|
+
super && !finishing_line.nil?
|
11
10
|
end
|
12
11
|
|
13
12
|
private
|
@@ -25,8 +24,8 @@ module WebSocket
|
|
25
24
|
# @see WebSocket::Handshake::Handler::Base#handshake_keys
|
26
25
|
def handshake_keys
|
27
26
|
[
|
28
|
-
|
29
|
-
|
27
|
+
%w(Upgrade WebSocket),
|
28
|
+
%w(Connection Upgrade),
|
30
29
|
['Sec-WebSocket-Origin', @handshake.headers['origin']],
|
31
30
|
['Sec-WebSocket-Location', @handshake.uri]
|
32
31
|
]
|
@@ -61,18 +60,17 @@ module WebSocket
|
|
61
60
|
|
62
61
|
spaces = string.scan(/ /).size
|
63
62
|
# As per 5.2.5, abort the connection if spaces are zero.
|
64
|
-
|
63
|
+
fail WebSocket::Error::Handshake::InvalidAuthentication if spaces == 0
|
65
64
|
|
66
65
|
# As per 5.2.6, abort if numbers is not an integral multiple of spaces
|
67
|
-
|
66
|
+
fail WebSocket::Error::Handshake::InvalidAuthentication if numbers % spaces != 0
|
68
67
|
|
69
68
|
quotient = numbers / spaces
|
70
69
|
|
71
|
-
|
70
|
+
fail WebSocket::Error::Handshake::InvalidAuthentication if quotient > 2**32 - 1
|
72
71
|
|
73
|
-
|
72
|
+
quotient
|
74
73
|
end
|
75
|
-
|
76
74
|
end
|
77
75
|
end
|
78
76
|
end
|
@@ -30,7 +30,6 @@ module WebSocket
|
|
30
30
|
# # Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
|
31
31
|
#
|
32
32
|
class Server < Base
|
33
|
-
|
34
33
|
# Initialize new WebSocket Server
|
35
34
|
#
|
36
35
|
# @param [Hash] args Arguments for server
|
@@ -41,7 +40,7 @@ module WebSocket
|
|
41
40
|
# Websocket::Handshake::Server.new(secure: true)
|
42
41
|
def initialize(args = {})
|
43
42
|
super
|
44
|
-
@secure
|
43
|
+
@secure ||= false
|
45
44
|
end
|
46
45
|
|
47
46
|
# Add text of request from Client. This method will parse content immediately and update version, state and error(if neccessary)
|
@@ -60,7 +59,7 @@ module WebSocket
|
|
60
59
|
#
|
61
60
|
# EOF
|
62
61
|
def <<(data)
|
63
|
-
|
62
|
+
super
|
64
63
|
set_version if parse_data
|
65
64
|
end
|
66
65
|
rescue_method :<<
|
@@ -71,12 +70,9 @@ module WebSocket
|
|
71
70
|
# @example
|
72
71
|
# @handshake.from_rack(env)
|
73
72
|
def from_rack(env)
|
74
|
-
@headers = env.select
|
75
|
-
key =~ /\AHTTP_/
|
76
|
-
end.reduce({}) do |memo, tuple|
|
73
|
+
@headers = env.select { |key, _value| key =~ /\AHTTP_/ }.each_with_object({}) do |tuple, memo|
|
77
74
|
key, value = tuple
|
78
|
-
memo[key.gsub(/\AHTTP_/, '').
|
79
|
-
memo
|
75
|
+
memo[key.gsub(/\AHTTP_/, '').tr('_', '-').downcase] = value
|
80
76
|
end
|
81
77
|
|
82
78
|
@path = env['REQUEST_PATH']
|
@@ -90,13 +86,13 @@ module WebSocket
|
|
90
86
|
# Better safe than sorry...
|
91
87
|
if @version == 76
|
92
88
|
input = env['rack.input']
|
93
|
-
@leftovers =
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
89
|
+
@leftovers = if input.respond_to?(:readpartial)
|
90
|
+
input.readpartial
|
91
|
+
elsif input.respond_to?(:read)
|
92
|
+
input.read
|
93
|
+
else
|
94
|
+
input.to_s
|
95
|
+
end
|
100
96
|
end
|
101
97
|
|
102
98
|
@state = :finished
|
@@ -154,28 +150,27 @@ module WebSocket
|
|
154
150
|
# @return [Boolean] false if protocol number is unknown, otherwise true
|
155
151
|
def include_version
|
156
152
|
@handler = case @version
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
153
|
+
when 75 then Handler::Server75.new(self)
|
154
|
+
when 76, 0..3 then Handler::Server76.new(self)
|
155
|
+
when 4..17 then Handler::Server04.new(self)
|
156
|
+
else fail WebSocket::Error::Handshake::UnknownVersion
|
157
|
+
end
|
162
158
|
end
|
163
159
|
|
164
|
-
PATH =
|
160
|
+
PATH = %r{^(\w+) (\/[^\s]*) HTTP\/1\.1$}
|
165
161
|
|
166
162
|
# Parse first line of Client response.
|
167
163
|
# @param [String] line Line to parse
|
168
164
|
# @return [Boolean] True if parsed correctly. False otherwise
|
169
165
|
def parse_first_line(line)
|
170
166
|
line_parts = line.match(PATH)
|
171
|
-
|
167
|
+
fail WebSocket::Error::Handshake::InvalidHeader unless line_parts
|
172
168
|
method = line_parts[1].strip
|
173
|
-
|
169
|
+
fail WebSocket::Error::Handshake::GetRequestRequired unless method == 'GET'
|
174
170
|
|
175
171
|
resource_name = line_parts[2].strip
|
176
172
|
@path, @query = resource_name.split('?', 2)
|
177
173
|
end
|
178
|
-
|
179
174
|
end
|
180
175
|
end
|
181
176
|
end
|
data/lib/websocket/version.rb
CHANGED
@@ -55,7 +55,7 @@ RSpec.describe 'Incoming frame draft 03' do
|
|
55
55
|
context 'should properly decode text frame in between of continuation' do
|
56
56
|
let(:encoded_text) { "\x84\x03Hel\x03\x03abc\x00\x02lo" }
|
57
57
|
let(:frame_type) { [:pong, :text] }
|
58
|
-
let(:decoded_text) {
|
58
|
+
let(:decoded_text) { %w(abc Hello) }
|
59
59
|
|
60
60
|
it_should_behave_like 'valid_incoming_frame'
|
61
61
|
end
|
@@ -114,5 +114,4 @@ RSpec.describe 'Incoming frame draft 03' do
|
|
114
114
|
|
115
115
|
it_should_behave_like 'valid_incoming_frame'
|
116
116
|
end
|
117
|
-
|
118
117
|
end
|
@@ -55,7 +55,7 @@ RSpec.describe 'Incoming frame draft 04' do
|
|
55
55
|
context 'should properly decode text frame in between of continuation' do
|
56
56
|
let(:encoded_text) { "\x04\x03Hel\x83\x03abc\x80\x02lo" }
|
57
57
|
let(:frame_type) { [:pong, :text] }
|
58
|
-
let(:decoded_text) {
|
58
|
+
let(:decoded_text) { %w(abc Hello) }
|
59
59
|
|
60
60
|
it_should_behave_like 'valid_incoming_frame'
|
61
61
|
end
|
@@ -114,5 +114,4 @@ RSpec.describe 'Incoming frame draft 04' do
|
|
114
114
|
|
115
115
|
it_should_behave_like 'valid_incoming_frame'
|
116
116
|
end
|
117
|
-
|
118
117
|
end
|
@@ -71,7 +71,7 @@ RSpec.describe 'Incoming frame draft 05' do
|
|
71
71
|
context 'should properly decode text frame in between of continuation' do
|
72
72
|
let(:encoded_text) { "\x04\x03Hel\x83\x03abc\x80\x02lo" }
|
73
73
|
let(:frame_type) { [:pong, :text] }
|
74
|
-
let(:decoded_text) {
|
74
|
+
let(:decoded_text) { %w(abc Hello) }
|
75
75
|
|
76
76
|
it_should_behave_like 'valid_incoming_frame'
|
77
77
|
end
|
@@ -130,5 +130,4 @@ RSpec.describe 'Incoming frame draft 05' do
|
|
130
130
|
|
131
131
|
it_should_behave_like 'valid_incoming_frame'
|
132
132
|
end
|
133
|
-
|
134
133
|
end
|
@@ -88,7 +88,7 @@ RSpec.describe 'Incoming frame draft 07' do
|
|
88
88
|
context 'should properly decode text frame in between of continuation' do
|
89
89
|
let(:encoded_text) { "\x01\x03Hel\x8a\x03abc\x80\x02lo" }
|
90
90
|
let(:frame_type) { [:pong, :text] }
|
91
|
-
let(:decoded_text) {
|
91
|
+
let(:decoded_text) { %w(abc Hello) }
|
92
92
|
|
93
93
|
it_should_behave_like 'valid_incoming_frame'
|
94
94
|
end
|
@@ -147,5 +147,4 @@ RSpec.describe 'Incoming frame draft 07' do
|
|
147
147
|
|
148
148
|
it_should_behave_like 'valid_incoming_frame'
|
149
149
|
end
|
150
|
-
|
151
150
|
end
|