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