websocket_parser 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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 accept_response
46
- ServerHandshake.new(response_headers)
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
@@ -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
- def receive(data)
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
- process_frame if @state == :complete
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
- payload_length_field
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
- unpack_bytes(2,'S<')
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
- if fin?
132
- process_message
133
- end
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
 
@@ -1,7 +1,5 @@
1
1
  module WebSocket
2
2
  class ServerHandshake < Http::Response
3
- CRLF = "\r\n"
4
-
5
3
  def initialize(headers = {})
6
4
  @headers = headers
7
5
  end
@@ -20,6 +18,7 @@ module WebSocket
20
18
  end
21
19
 
22
20
  data << CRLF
21
+ data
23
22
  end
24
23
  end
25
24
  end
@@ -1,3 +1,3 @@
1
1
  module WebSocket
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -11,6 +11,7 @@ module WebSocket
11
11
 
12
12
  PROTOCOL_VERSION = 13 # RFC 6455
13
13
  GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
14
+ CRLF = "\r\n"
14
15
 
15
16
  # see http://tools.ietf.org/html/rfc6455#section-11.8
16
17
  OPCODES = {
@@ -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.5
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: 1607326669801376036
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: 1607326669801376036
109
+ hash: 2454613231888263104
110
110
  requirements: []
111
111
  rubyforge_project:
112
112
  rubygems_version: 1.8.23