websocket_parser 0.0.2 → 0.0.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.
- data/.gitignore +1 -0
- data/.travis.yml +7 -0
- data/README.md +1 -0
- data/lib/websocket/client_handshake.rb +24 -11
- data/lib/websocket/message.rb +14 -14
- data/lib/websocket/parser.rb +9 -28
- data/lib/websocket/server_handshake.rb +9 -5
- data/lib/websocket/version.rb +1 -1
- data/lib/websocket_parser.rb +2 -0
- metadata +5 -4
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# WebSocketParser
|
2
|
+
[](http://travis-ci.org/afcapel/websocket_parser)
|
2
3
|
|
3
4
|
WebsocketParser is a RFC6455 compliant parser for websocket messages written in Ruby. It
|
4
5
|
is intended to write websockets servers in Ruby, but it only handles the parsing of the
|
@@ -1,31 +1,44 @@
|
|
1
1
|
require 'digest/sha1'
|
2
|
+
require 'base64'
|
2
3
|
|
3
4
|
module WebSocket
|
4
5
|
class ClientHandshake < Http::Request
|
5
6
|
|
6
7
|
def self.accept_token_for(websocket_key)
|
7
|
-
Digest::SHA1.
|
8
|
+
Base64.encode64(Digest::SHA1.digest(websocket_key.strip + GUID)).strip
|
8
9
|
end
|
9
10
|
|
10
|
-
def
|
11
|
-
@
|
12
|
-
@uri = uri.is_a?(URI) ? uri : URI(uri.to_s)
|
13
|
-
|
14
|
-
@headers = headers
|
15
|
-
@proxy, @body, @version = proxy, body, version
|
11
|
+
def errors
|
12
|
+
@errors ||= []
|
16
13
|
end
|
17
14
|
|
18
15
|
def valid?
|
19
|
-
headers['Connection']
|
20
|
-
|
21
|
-
|
16
|
+
if headers['Connection'].downcase != 'upgrade'
|
17
|
+
errors << 'Not connection upgrade'
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
|
21
|
+
if headers['Upgrade'].downcase != 'websocket'
|
22
|
+
errors << 'Connection upgrade is not for websocket'
|
23
|
+
return false
|
24
|
+
end
|
25
|
+
|
26
|
+
# Careful: Http gem changes header capitalization,
|
27
|
+
# so Sec-WebSocket-Version becomes Sec-Websocket-Version
|
28
|
+
if headers['Sec-Websocket-Version'].to_i != PROTOCOL_VERSION
|
29
|
+
errors << "Protocol version not supported '#{headers['Sec-Websocket-Version']}'"
|
30
|
+
return false
|
31
|
+
end
|
32
|
+
|
33
|
+
return true
|
22
34
|
end
|
23
35
|
|
24
36
|
def accept_response
|
37
|
+
websocket_key = headers['Sec-Websocket-Key']
|
25
38
|
response_headers = {
|
26
39
|
'Upgrade' => 'websocket',
|
27
40
|
'Connection' => 'Upgrade',
|
28
|
-
'Sec-WebSocket-Accept' => ClientHandshake.accept_token_for(
|
41
|
+
'Sec-WebSocket-Accept' => ClientHandshake.accept_token_for(websocket_key)
|
29
42
|
}
|
30
43
|
|
31
44
|
ServerHandshake.new(101, '1.1', response_headers)
|
data/lib/websocket/message.rb
CHANGED
@@ -44,16 +44,6 @@ module WebSocket
|
|
44
44
|
@payload = WebSocket.mask(@payload, @mask_key)
|
45
45
|
end
|
46
46
|
|
47
|
-
def message_size
|
48
|
-
if payload_length < 126
|
49
|
-
:small
|
50
|
-
elsif payload_length < 65_536 # fits in 2 bytes
|
51
|
-
:medium
|
52
|
-
else
|
53
|
-
:large
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
47
|
def payload_length
|
58
48
|
@payload ? @payload.length : 0
|
59
49
|
end
|
@@ -62,10 +52,6 @@ module WebSocket
|
|
62
52
|
second_byte & 0b10000000 != 0
|
63
53
|
end
|
64
54
|
|
65
|
-
def extended_payload_length
|
66
|
-
message_size == :small ? nil : payload_length
|
67
|
-
end
|
68
|
-
|
69
55
|
def to_data
|
70
56
|
to_a.pack(pack_format)
|
71
57
|
end
|
@@ -92,6 +78,20 @@ module WebSocket
|
|
92
78
|
WebSocket.frame_format(payload_length, masked?)
|
93
79
|
end
|
94
80
|
|
81
|
+
def message_size
|
82
|
+
if payload_length < 126
|
83
|
+
:small
|
84
|
+
elsif payload_length < 65_536 # fits in 2 bytes
|
85
|
+
:medium
|
86
|
+
else
|
87
|
+
:large
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def extended_payload_length
|
92
|
+
message_size == :small ? nil : payload_length
|
93
|
+
end
|
94
|
+
|
95
95
|
def first_byte
|
96
96
|
@first_byte ||= if type == :continuation
|
97
97
|
OPCODE_VALUES[type]
|
data/lib/websocket/parser.rb
CHANGED
@@ -27,27 +27,6 @@ module WebSocket
|
|
27
27
|
class Parser
|
28
28
|
def initialize
|
29
29
|
@data = ''.force_encoding("ASCII-8BIT")
|
30
|
-
|
31
|
-
@on_message = Proc.new do |msg|
|
32
|
-
puts "Received message: #{msg}"
|
33
|
-
end
|
34
|
-
|
35
|
-
@on_error = Proc.new do |error|
|
36
|
-
puts "WebSocket error: #{error}"
|
37
|
-
end
|
38
|
-
|
39
|
-
@on_close = Proc.new do |status, message|
|
40
|
-
puts "Should close connection. Status: #{status} Message: #{message}"
|
41
|
-
end
|
42
|
-
|
43
|
-
@on_ping = Proc.new do
|
44
|
-
puts "Ping received"
|
45
|
-
end
|
46
|
-
|
47
|
-
@on_pong = Proc.new do
|
48
|
-
puts "Pong received"
|
49
|
-
end
|
50
|
-
|
51
30
|
@state = :header
|
52
31
|
end
|
53
32
|
|
@@ -84,6 +63,8 @@ module WebSocket
|
|
84
63
|
|
85
64
|
alias_method :<<, :receive
|
86
65
|
|
66
|
+
private
|
67
|
+
|
87
68
|
def read_header
|
88
69
|
return unless @data.length >= 2 # Not enough data
|
89
70
|
|
@@ -157,18 +138,18 @@ module WebSocket
|
|
157
138
|
def process_message
|
158
139
|
case opcode
|
159
140
|
when :text
|
160
|
-
@on_message.call(@current_message.force_encoding("UTF-8"))
|
141
|
+
@on_message.call(@current_message.force_encoding("UTF-8")) if @on_message
|
161
142
|
when :binary
|
162
|
-
@on_message.call(@current_message)
|
143
|
+
@on_message.call(@current_message) if @on_message
|
144
|
+
when :ping
|
145
|
+
@on_ping.call if @on_ping
|
146
|
+
when :pong
|
147
|
+
@on_pong.call if @on_ping
|
163
148
|
when :close
|
164
149
|
status_code, message = @current_message.unpack('S<a*')
|
165
150
|
status = STATUS_CODES[status_code]
|
166
151
|
|
167
|
-
@on_close.call(status, message)
|
168
|
-
when :ping
|
169
|
-
@on_ping.call
|
170
|
-
when :pong
|
171
|
-
@on_pong.call
|
152
|
+
@on_close.call(status, message) if @on_close
|
172
153
|
end
|
173
154
|
|
174
155
|
@current_message = nil
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module WebSocket
|
2
2
|
class ServerHandshake < Http::Response
|
3
|
+
CRLF = "\r\n"
|
3
4
|
|
4
5
|
def initialize(status = 101, version = "1.1", headers = {}, body = nil, &body_proc)
|
5
6
|
@status, @version, @body, @body_proc = status, version, body, body_proc
|
@@ -7,17 +8,20 @@ module WebSocket
|
|
7
8
|
end
|
8
9
|
|
9
10
|
def render(out)
|
10
|
-
|
11
|
+
out << to_data
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_data
|
15
|
+
data = "#{@version} #{@status} #{@reason}#{CRLF}"
|
11
16
|
|
12
17
|
unless @headers.empty?
|
13
|
-
|
18
|
+
data << @headers.map do |header, value|
|
14
19
|
"#{header}: #{value}"
|
15
20
|
end.join(CRLF) << CRLF
|
16
21
|
end
|
17
22
|
|
18
|
-
|
19
|
-
|
20
|
-
out << response_header
|
23
|
+
data << CRLF
|
24
|
+
data
|
21
25
|
end
|
22
26
|
end
|
23
27
|
end
|
data/lib/websocket/version.rb
CHANGED
data/lib/websocket_parser.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: websocket_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-08-
|
12
|
+
date: 2012-08-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: http
|
@@ -67,6 +67,7 @@ extensions: []
|
|
67
67
|
extra_rdoc_files: []
|
68
68
|
files:
|
69
69
|
- .gitignore
|
70
|
+
- .travis.yml
|
70
71
|
- Gemfile
|
71
72
|
- LICENSE
|
72
73
|
- README.md
|
@@ -96,7 +97,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
96
97
|
version: '0'
|
97
98
|
segments:
|
98
99
|
- 0
|
99
|
-
hash:
|
100
|
+
hash: 2288242846946475689
|
100
101
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
102
|
none: false
|
102
103
|
requirements:
|
@@ -105,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
106
|
version: '0'
|
106
107
|
segments:
|
107
108
|
- 0
|
108
|
-
hash:
|
109
|
+
hash: 2288242846946475689
|
109
110
|
requirements: []
|
110
111
|
rubyforge_project:
|
111
112
|
rubygems_version: 1.8.23
|