websocket_parser 0.0.5 → 0.0.6
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/README.md +26 -1
- data/lib/websocket/client_handshake.rb +11 -2
- data/lib/websocket/parser.rb +33 -12
- data/lib/websocket/server_handshake.rb +1 -2
- data/lib/websocket/version.rb +1 -1
- data/lib/websocket_parser.rb +1 -0
- data/spec/websocket/parser_spec.rb +13 -0
- metadata +3 -3
data/README.md
CHANGED
@@ -19,7 +19,32 @@ Or install it yourself as:
|
|
19
19
|
|
20
20
|
$ gem install websocket_parser
|
21
21
|
|
22
|
-
## Usage
|
22
|
+
## Usage. TMTOWTDI.
|
23
|
+
|
24
|
+
### Use return values
|
25
|
+
|
26
|
+
The simplest way to use the websocket parser is to create a new one, fetch
|
27
|
+
it with data and call the parse methods.
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'websocket_parser'
|
31
|
+
|
32
|
+
parser = WebSocket::Parser.new
|
33
|
+
|
34
|
+
parser.append data
|
35
|
+
|
36
|
+
parser.parse # return next message or nil
|
37
|
+
parser.parse_all # return all parsed messages
|
38
|
+
|
39
|
+
```
|
40
|
+
|
41
|
+
The returned messages are instances of WebSocket::Message and can be either text messages
|
42
|
+
or control frames. Check WebSocket::Message#type to know the kind of a message.
|
43
|
+
|
44
|
+
### Use callbacks
|
45
|
+
|
46
|
+
In addition to return values, you can register callbacks to get notified when a certain event
|
47
|
+
happens.
|
23
48
|
|
24
49
|
```ruby
|
25
50
|
require 'websocket_parser'
|
@@ -33,6 +33,10 @@ module WebSocket
|
|
33
33
|
return true
|
34
34
|
end
|
35
35
|
|
36
|
+
def accept_response
|
37
|
+
ServerHandshake.new(response_headers)
|
38
|
+
end
|
39
|
+
|
36
40
|
def response_headers
|
37
41
|
websocket_key = headers['Sec-Websocket-Key']
|
38
42
|
{
|
@@ -42,8 +46,13 @@ module WebSocket
|
|
42
46
|
}
|
43
47
|
end
|
44
48
|
|
45
|
-
def
|
46
|
-
|
49
|
+
def to_data
|
50
|
+
data = "#{method.to_s.upcase} #{uri.path} HTTP/#{version}#{CRLF}"
|
51
|
+
@headers.each do |field, value|
|
52
|
+
data << "#{field}: #{value}#{CRLF}"
|
53
|
+
end
|
54
|
+
data << CRLF
|
55
|
+
data
|
47
56
|
end
|
48
57
|
end
|
49
58
|
end
|
data/lib/websocket/parser.rb
CHANGED
@@ -25,6 +25,8 @@ module WebSocket
|
|
25
25
|
# for more info on the frame format see: http://tools.ietf.org/html/rfc6455#section-5
|
26
26
|
#
|
27
27
|
class Parser
|
28
|
+
attr_writer :on_message, :on_error, :on_close, :on_ping, :on_pong
|
29
|
+
|
28
30
|
def initialize
|
29
31
|
@data = ''.force_encoding("ASCII-8BIT")
|
30
32
|
@state = :header
|
@@ -50,19 +52,37 @@ module WebSocket
|
|
50
52
|
@on_pong = callback
|
51
53
|
end
|
52
54
|
|
53
|
-
|
55
|
+
# Stores the data in a buffer for later parsing
|
56
|
+
def append(data)
|
54
57
|
@data << data
|
58
|
+
end
|
55
59
|
|
60
|
+
# Receive data and parse it return an array of parsed messages
|
61
|
+
def receive(data)
|
62
|
+
append(data) && next_messages
|
63
|
+
end
|
64
|
+
|
65
|
+
alias_method :<<, :receive
|
66
|
+
|
67
|
+
# Parse all messages in buffer
|
68
|
+
def next_messages
|
69
|
+
Array.new.tap do |messages|
|
70
|
+
while msg = next_message do
|
71
|
+
messages << msg
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Parse next message in buffer
|
77
|
+
def next_message
|
56
78
|
read_header if @state == :header
|
57
79
|
read_payload_length if @state == :payload_length
|
58
80
|
read_mask_key if @state == :mask
|
59
81
|
read_payload if @state == :payload
|
60
82
|
|
61
|
-
|
83
|
+
@state == :complete ? process_frame! : nil
|
62
84
|
end
|
63
85
|
|
64
|
-
alias_method :<<, :receive
|
65
|
-
|
66
86
|
private
|
67
87
|
|
68
88
|
def read_header
|
@@ -74,7 +94,7 @@ module WebSocket
|
|
74
94
|
|
75
95
|
def read_payload_length
|
76
96
|
@payload_length = if message_size == :small
|
77
|
-
|
97
|
+
payload_length_field
|
78
98
|
else
|
79
99
|
read_extended_payload_length
|
80
100
|
end
|
@@ -86,7 +106,7 @@ module WebSocket
|
|
86
106
|
|
87
107
|
def read_extended_payload_length
|
88
108
|
if message_size == :medium && @data.size >= 2
|
89
|
-
|
109
|
+
unpack_bytes(2,'S<')
|
90
110
|
elsif message_size == :large && @data.size >= 4
|
91
111
|
unpack_bytes(8,'Q<')
|
92
112
|
end
|
@@ -121,21 +141,23 @@ module WebSocket
|
|
121
141
|
[:close, :ping, :pong].include?(opcode)
|
122
142
|
end
|
123
143
|
|
124
|
-
def process_frame
|
144
|
+
def process_frame!
|
125
145
|
if @current_message
|
126
146
|
@current_message << @payload
|
127
147
|
else
|
128
148
|
@current_message = @payload
|
129
149
|
end
|
130
150
|
|
131
|
-
|
132
|
-
|
133
|
-
|
151
|
+
completed_message = fin? ? @current_message :nil
|
152
|
+
|
153
|
+
process_message! if fin?
|
134
154
|
|
135
155
|
reset_frame!
|
156
|
+
|
157
|
+
completed_message
|
136
158
|
end
|
137
159
|
|
138
|
-
def process_message
|
160
|
+
def process_message!
|
139
161
|
case opcode
|
140
162
|
when :text
|
141
163
|
@on_message.call(@current_message.force_encoding("UTF-8")) if @on_message
|
@@ -151,7 +173,6 @@ module WebSocket
|
|
151
173
|
|
152
174
|
@on_close.call(status, message) if @on_close
|
153
175
|
end
|
154
|
-
|
155
176
|
@current_message = nil
|
156
177
|
end
|
157
178
|
|
data/lib/websocket/version.rb
CHANGED
data/lib/websocket_parser.rb
CHANGED
@@ -26,6 +26,19 @@ describe WebSocket::Parser do
|
|
26
26
|
received_messages.first.should == 'Once upon a time'
|
27
27
|
end
|
28
28
|
|
29
|
+
it "returns parsed messages on parse" do
|
30
|
+
msg1 = WebSocket::Message.new('Now is the winter of our discontent').to_data
|
31
|
+
msg2 = WebSocket::Message.new('Made glorious summer by this sun of York').to_data
|
32
|
+
|
33
|
+
messages = parser << msg1.slice!(0,5)
|
34
|
+
messages.should be_empty # We don't have a complete message yet
|
35
|
+
|
36
|
+
messages = parser << msg1 + msg2
|
37
|
+
|
38
|
+
messages[0].should == 'Now is the winter of our discontent'
|
39
|
+
messages[1].should == 'Made glorious summer by this sun of York'
|
40
|
+
end
|
41
|
+
|
29
42
|
it "can receive a message in parts" do
|
30
43
|
data = WebSocket::Message.new('Once upon a time').to_data
|
31
44
|
parser << data.slice!(0, 5)
|
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.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -97,7 +97,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
97
97
|
version: '0'
|
98
98
|
segments:
|
99
99
|
- 0
|
100
|
-
hash:
|
100
|
+
hash: 2454613231888263104
|
101
101
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
102
|
none: false
|
103
103
|
requirements:
|
@@ -106,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
106
106
|
version: '0'
|
107
107
|
segments:
|
108
108
|
- 0
|
109
|
-
hash:
|
109
|
+
hash: 2454613231888263104
|
110
110
|
requirements: []
|
111
111
|
rubyforge_project:
|
112
112
|
rubygems_version: 1.8.23
|