websocket_parser 0.1.4 → 0.1.5
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/.travis.yml +2 -1
- data/Gemfile +6 -0
- data/README.md +3 -3
- data/lib/websocket/parser.rb +6 -5
- data/lib/websocket/version.rb +1 -1
- data/lib/websocket_parser.rb +1 -1
- data/spec/spec_helper.rb +5 -1
- data/spec/websocket/handshake_spec.rb +4 -5
- data/spec/websocket/message_spec.rb +44 -14
- data/spec/websocket/parser_spec.rb +26 -27
- metadata +13 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e45c5d450a8c75baa97f7c1019935ece33763c44
|
4
|
+
data.tar.gz: 1842fd255487115f5d66a135a073bcac3e8e3350
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e543dd1f7299e1e3b08d95085597b523bc46adf09824254b93db9042e3970d5c2600184435457fa059e2b6b0f4675971a6539a348a8aefac84149505cb93c2e
|
7
|
+
data.tar.gz: 4ec4c8e0e8c877009c6b29013e0ea9ff7745add5ba23ab75f3bda51c20d892e4dcc67733edd504ea8b8c287a2eeff5747ee45055131e0b5b680fdbb5ce9ff970
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -73,11 +73,11 @@ parser.on_close do |status, message|
|
|
73
73
|
socket << WebSocket::Message.close.to_data
|
74
74
|
socket.close!
|
75
75
|
|
76
|
-
puts "Client closed connection. Status: #{status}. Reason: #{
|
76
|
+
puts "Client closed connection. Status: #{status}. Reason: #{message}"
|
77
77
|
end
|
78
78
|
|
79
|
-
parser.on_ping do
|
80
|
-
socket << WebSocket::Message.pong.to_data
|
79
|
+
parser.on_ping do |payload|
|
80
|
+
socket << WebSocket::Message.pong(payload).to_data
|
81
81
|
end
|
82
82
|
|
83
83
|
parser << socket.read(4096)
|
data/lib/websocket/parser.rb
CHANGED
@@ -30,6 +30,7 @@ module WebSocket
|
|
30
30
|
def initialize
|
31
31
|
@data = ''.force_encoding("ASCII-8BIT")
|
32
32
|
@state = :header
|
33
|
+
@current_message = nil
|
33
34
|
end
|
34
35
|
|
35
36
|
def on_message(&callback)
|
@@ -69,8 +70,8 @@ module WebSocket
|
|
69
70
|
def next_messages
|
70
71
|
Array.new.tap do |messages|
|
71
72
|
while msg = next_message do
|
72
|
-
|
73
|
-
|
73
|
+
messages << msg
|
74
|
+
end
|
74
75
|
end
|
75
76
|
end
|
76
77
|
|
@@ -114,12 +115,12 @@ module WebSocket
|
|
114
115
|
|
115
116
|
def read_extended_payload_length
|
116
117
|
if message_size == :medium && @data.size >= 2
|
117
|
-
size = unpack_bytes(2,'
|
118
|
+
size = unpack_bytes(2,'n')
|
118
119
|
ParserError.new("Wrong payload length. Expected to be greater than 125") unless size > 125
|
119
120
|
size
|
120
121
|
elsif message_size == :large && @data.size >= 4
|
121
122
|
size = unpack_bytes(8,'Q>')
|
122
|
-
|
123
|
+
ParserError.new("Wrong payload length. Expected to be greater than 65535") unless size > 65_535
|
123
124
|
size
|
124
125
|
end
|
125
126
|
end
|
@@ -251,4 +252,4 @@ module WebSocket
|
|
251
252
|
@payload = nil
|
252
253
|
end
|
253
254
|
end
|
254
|
-
end
|
255
|
+
end
|
data/lib/websocket/version.rb
CHANGED
data/lib/websocket_parser.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe WebSocket::ClientHandshake do
|
4
|
-
|
5
4
|
let :handshake_headers do
|
6
5
|
{
|
7
6
|
"Host" => "server.example.com",
|
@@ -23,8 +22,8 @@ describe WebSocket::ClientHandshake do
|
|
23
22
|
it "can generate an accept response for the client" do
|
24
23
|
response = client_handshake.accept_response
|
25
24
|
|
26
|
-
response.headers['Upgrade'].should
|
27
|
-
response.headers['Connection'].should
|
28
|
-
response.headers['Sec-WebSocket-Accept'].should
|
25
|
+
response.headers['Upgrade'].should eq('websocket')
|
26
|
+
response.headers['Connection'].should eq('Upgrade')
|
27
|
+
response.headers['Sec-WebSocket-Accept'].should eq('s3pPLMBiTxaQ9kYGzzhZRbK+xOo=')
|
29
28
|
end
|
30
|
-
end
|
29
|
+
end
|
@@ -1,21 +1,51 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe WebSocket::Message do
|
4
|
-
|
5
|
-
it "knows its binary representation" do
|
4
|
+
it "knows binary representation of messages with more than 65,535 bytes" do
|
6
5
|
text = 1500.times.collect { 'All work and no play makes Jack a dull boy.' }.join("\n\n")
|
7
6
|
message = WebSocket::Message.new(text)
|
8
7
|
data = message.to_data
|
9
8
|
|
10
9
|
# 2 bytes from header + 8 bytes from extended payload length + payload
|
11
|
-
data.size.should
|
10
|
+
data.size.should eq(2 + 8 + text.length)
|
12
11
|
|
13
12
|
first_byte, second_byte, ext_length, payload = data.unpack("CCQ>a#{text.length}")
|
14
13
|
|
15
|
-
first_byte.should
|
16
|
-
second_byte.should
|
17
|
-
ext_length.should
|
18
|
-
payload.should
|
14
|
+
first_byte.should eq(0b10000001) # Text frame with FIN bit set
|
15
|
+
second_byte.should eq(0b01111111) # Unmasked. Payload length 127.
|
16
|
+
ext_length.should eq(text.length)
|
17
|
+
payload.should eq(text)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "knows binary representation of messages between 126 and 65,535 bytes" do
|
21
|
+
text = '0'*127
|
22
|
+
data = WebSocket::Message.new(text).to_data
|
23
|
+
|
24
|
+
# 2 bytes from header + 2 bytes from extended payload length + payload
|
25
|
+
data.size.should eq(2 + 2 + text.length)
|
26
|
+
# extended payload length should respect endianness
|
27
|
+
data[2..3].should eq([0x00, 0x7F].pack('C*'))
|
28
|
+
|
29
|
+
first_byte, second_byte, ext_length, payload = data.unpack("CCna#{text.length}")
|
30
|
+
|
31
|
+
first_byte.should eq(0b10000001) # Text frame with FIN bit set
|
32
|
+
second_byte.should eq(0b01111110) # Unmasked. Payload length 126.
|
33
|
+
ext_length.should eq(text.length)
|
34
|
+
payload.should eq(text)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "knows binary representation of messages with less than 126 bytes" do
|
38
|
+
text = '0'*125
|
39
|
+
data = WebSocket::Message.new(text).to_data
|
40
|
+
|
41
|
+
# 2 bytes from header + payload
|
42
|
+
data.size.should eq(2 + text.length)
|
43
|
+
|
44
|
+
first_byte, second_byte, payload = data.unpack("CCa#{text.length}")
|
45
|
+
|
46
|
+
first_byte.should eq(0b10000001) # Text frame with FIN bit set
|
47
|
+
second_byte.should eq(0b01111101) # Unmasked. Payload length 125.
|
48
|
+
payload.should eq(text)
|
19
49
|
end
|
20
50
|
|
21
51
|
it "can be masked" do
|
@@ -30,10 +60,10 @@ describe WebSocket::Message do
|
|
30
60
|
it "allows status codes for control frames" do
|
31
61
|
msg = WebSocket::Message.close(1001, 'Bye')
|
32
62
|
|
33
|
-
msg.status_code.should
|
34
|
-
msg.payload.should
|
35
|
-
msg.status.should
|
36
|
-
msg.status_message.should
|
63
|
+
msg.status_code.should eq(1001)
|
64
|
+
msg.payload.should eq([1001, 'Bye'].pack('S<a*'))
|
65
|
+
msg.status.should eq(:peer_going_away)
|
66
|
+
msg.status_message.should eq('Bye')
|
37
67
|
end
|
38
68
|
|
39
69
|
it "does not allow a status message without status code" do
|
@@ -44,7 +74,7 @@ describe WebSocket::Message do
|
|
44
74
|
ping = WebSocket::Message.ping('Roman Ping Pong')
|
45
75
|
pong = WebSocket::Message.pong(ping.payload)
|
46
76
|
|
47
|
-
pong.type.should
|
48
|
-
pong.payload.should
|
77
|
+
pong.type.should eq(:pong)
|
78
|
+
pong.payload.should eq('Roman Ping Pong')
|
49
79
|
end
|
50
|
-
end
|
80
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe WebSocket::Parser do
|
4
|
-
|
5
4
|
let(:received_messages) { [] }
|
6
5
|
let(:received_errors) { [] }
|
7
6
|
let(:received_closes) { [] }
|
@@ -23,7 +22,7 @@ describe WebSocket::Parser do
|
|
23
22
|
it "recognizes a text message" do
|
24
23
|
parser << WebSocket::Message.new('Once upon a time').to_data
|
25
24
|
|
26
|
-
received_messages.first.should
|
25
|
+
received_messages.first.should eq('Once upon a time')
|
27
26
|
end
|
28
27
|
|
29
28
|
it "returns parsed messages on parse" do
|
@@ -35,8 +34,8 @@ describe WebSocket::Parser do
|
|
35
34
|
|
36
35
|
messages = parser << msg1 + msg2
|
37
36
|
|
38
|
-
messages[0].should
|
39
|
-
messages[1].should
|
37
|
+
messages[0].should eq('Now is the winter of our discontent')
|
38
|
+
messages[1].should eq('Made glorious summer by this sun of York')
|
40
39
|
end
|
41
40
|
|
42
41
|
it "does not return control frames" do
|
@@ -54,7 +53,7 @@ describe WebSocket::Parser do
|
|
54
53
|
|
55
54
|
parser << data
|
56
55
|
|
57
|
-
received_messages.first.should
|
56
|
+
received_messages.first.should eq('Once upon a time')
|
58
57
|
end
|
59
58
|
|
60
59
|
it "can receive succesive messages" do
|
@@ -64,52 +63,52 @@ describe WebSocket::Parser do
|
|
64
63
|
parser << msg1.to_data
|
65
64
|
parser << msg2.to_data
|
66
65
|
|
67
|
-
received_messages[0].should
|
68
|
-
received_messages[1].should
|
66
|
+
received_messages[0].should eq('Now is the winter of our discontent')
|
67
|
+
received_messages[1].should eq('Made glorious summer by this sun of York')
|
69
68
|
end
|
70
69
|
|
71
70
|
it "can receive medium size messages" do
|
72
71
|
# Medium size messages has a payload length between 127 and 65_535 bytes
|
73
72
|
|
74
73
|
text = 4.times.collect { 'All work and no play makes Jack a dull boy.' }.join("\n\n")
|
75
|
-
text.length.should > 127
|
76
|
-
text.length.should < 65_536
|
74
|
+
text.length.should be > 127
|
75
|
+
text.length.should be < 65_536
|
77
76
|
|
78
77
|
parser << WebSocket::Message.new(text).to_data
|
79
|
-
received_messages.first.should
|
78
|
+
received_messages.first.should eq(text)
|
80
79
|
end
|
81
80
|
|
82
81
|
it "can receive large size messages" do
|
83
82
|
# Large size messages has a payload length greater than 65_535 bytes
|
84
83
|
|
85
84
|
text = 1500.times.collect { 'All work and no play makes Jack a dull boy.' }.join("\n\n")
|
86
|
-
text.length.should > 65_536
|
85
|
+
text.length.should be > 65_536
|
87
86
|
|
88
87
|
parser << WebSocket::Message.new(text).to_data
|
89
88
|
|
90
89
|
# Check lengths first to avoid gigantic error message
|
91
|
-
received_messages.first.length.should
|
92
|
-
received_messages.first.should
|
90
|
+
received_messages.first.length.should eq(text.length)
|
91
|
+
received_messages.first.should eq(text)
|
93
92
|
end
|
94
93
|
|
95
94
|
it "recognizes a ping message" do
|
96
95
|
parser << WebSocket::Message.ping.to_data
|
97
96
|
|
98
|
-
received_pings.size.should
|
97
|
+
received_pings.size.should eq(1)
|
99
98
|
end
|
100
99
|
|
101
100
|
it "recognizes a pong message" do
|
102
101
|
parser << WebSocket::Message.pong.to_data
|
103
102
|
|
104
|
-
received_pongs.size.should
|
103
|
+
received_pongs.size.should eq(1)
|
105
104
|
end
|
106
105
|
|
107
106
|
it "recognizes a close message with status code and message" do
|
108
107
|
parser << WebSocket::Message.close(1001, 'Browser leaving page').to_data
|
109
108
|
|
110
109
|
status, message = received_closes.first
|
111
|
-
status.should
|
112
|
-
message.should
|
110
|
+
status.should eq(:peer_going_away) # Status code 1001
|
111
|
+
message.should eq('Browser leaving page')
|
113
112
|
end
|
114
113
|
|
115
114
|
it "recognizes a close message without status code" do
|
@@ -126,7 +125,7 @@ describe WebSocket::Parser do
|
|
126
125
|
|
127
126
|
parser << msg.to_data
|
128
127
|
|
129
|
-
received_messages.first.should
|
128
|
+
received_messages.first.should eq('Once upon a time')
|
130
129
|
end
|
131
130
|
|
132
131
|
context "examples from the spec" do
|
@@ -135,13 +134,13 @@ describe WebSocket::Parser do
|
|
135
134
|
it "recognizes single-frame unmasked text message" do
|
136
135
|
parser << [0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f].pack('C*')
|
137
136
|
|
138
|
-
received_messages.first.should
|
137
|
+
received_messages.first.should eq('Hello')
|
139
138
|
end
|
140
139
|
|
141
140
|
it "recognizes single-frame masked text message" do
|
142
141
|
parser << [0x81, 0x85, 0x37, 0xfa, 0x21, 0x3d, 0x7f, 0x9f, 0x4d, 0x51, 0x58].pack('C*')
|
143
142
|
|
144
|
-
received_messages.first.should
|
143
|
+
received_messages.first.should eq('Hello')
|
145
144
|
end
|
146
145
|
|
147
146
|
it "recognizes a fragmented unmasked text message" do
|
@@ -151,33 +150,33 @@ describe WebSocket::Parser do
|
|
151
150
|
|
152
151
|
parser << [0x80, 0x02, 0x6c, 0x6f].pack('C*') # contains "lo"
|
153
152
|
|
154
|
-
received_messages.first.should
|
153
|
+
received_messages.first.should eq('Hello')
|
155
154
|
end
|
156
155
|
|
157
156
|
it "recognizes an unnmasked ping request" do
|
158
157
|
parser << [0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f].pack('C*')
|
159
158
|
|
160
|
-
received_pings.size.should
|
159
|
+
received_pings.size.should eq(1)
|
161
160
|
end
|
162
161
|
|
163
162
|
it "recognizes a masked pong response" do
|
164
163
|
parser << [0x8a, 0x85, 0x37, 0xfa, 0x21, 0x3d, 0x7f, 0x9f, 0x4d, 0x51, 0x58].pack('C*')
|
165
164
|
|
166
|
-
received_pongs.size.should
|
165
|
+
received_pongs.size.should eq(1)
|
167
166
|
end
|
168
167
|
|
169
168
|
it "recognizes 256 bytes binary message in a single unmasked frame" do
|
170
169
|
data = Array.new(256) { rand(256) }.pack('c*')
|
171
|
-
parser << [0x82, 0x7E, 0x0100].pack('
|
170
|
+
parser << [0x82, 0x7E, 0x0100].pack('CCn') + data
|
172
171
|
|
173
|
-
received_messages.first.should
|
172
|
+
received_messages.first.should eq(data)
|
174
173
|
end
|
175
174
|
|
176
175
|
it "recoginzes 64KiB binary message in a single unmasked frame" do
|
177
176
|
data = Array.new(65536) { rand(256) }.pack('c*')
|
178
177
|
parser << [0x82, 0x7F, 0x0000000000010000].pack('CCQ>') + data
|
179
178
|
|
180
|
-
received_messages.first.should
|
179
|
+
received_messages.first.should eq(data)
|
181
180
|
end
|
182
181
|
end
|
183
|
-
end
|
182
|
+
end
|
metadata
CHANGED
@@ -1,55 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: websocket_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alberto Fernandez-Capel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-01-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: http
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
description: WebsocketParser is a RFC6455 compliant parser for websocket messages
|
@@ -59,8 +59,8 @@ executables: []
|
|
59
59
|
extensions: []
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
|
-
- .gitignore
|
63
|
-
- .travis.yml
|
62
|
+
- ".gitignore"
|
63
|
+
- ".travis.yml"
|
64
64
|
- Gemfile
|
65
65
|
- LICENSE
|
66
66
|
- README.md
|
@@ -85,17 +85,17 @@ require_paths:
|
|
85
85
|
- lib
|
86
86
|
required_ruby_version: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
|
-
- -
|
88
|
+
- - ">="
|
89
89
|
- !ruby/object:Gem::Version
|
90
90
|
version: '0'
|
91
91
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
92
|
requirements:
|
93
|
-
- -
|
93
|
+
- - ">="
|
94
94
|
- !ruby/object:Gem::Version
|
95
95
|
version: '0'
|
96
96
|
requirements: []
|
97
97
|
rubyforge_project:
|
98
|
-
rubygems_version: 2.
|
98
|
+
rubygems_version: 2.2.0
|
99
99
|
signing_key:
|
100
100
|
specification_version: 4
|
101
101
|
summary: Parse websockets messages in Ruby
|