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 CHANGED
@@ -3,6 +3,7 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
+ .rbx
6
7
  Gemfile.lock
7
8
  InstalledFiles
8
9
  _yardoc
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - jruby-19mode # JRuby in 1.9 mode
6
+ - rbx-19mode
7
+ script: bundle exec rspec spec
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # WebSocketParser
2
+ [![Build Status](https://secure.travis-ci.org/afcapel/websocket_parser.png)](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.base64digest(websocket_key.strip + GUID)
8
+ Base64.encode64(Digest::SHA1.digest(websocket_key.strip + GUID)).strip
8
9
  end
9
10
 
10
- def initialize(method, uri, headers = {}, proxy = {}, body = nil, version = "1.1")
11
- @method = method.to_s.downcase.to_sym
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'] == 'Upgrade' &&
20
- headers['Upgrade'] == 'websocket' &&
21
- headers['Sec-WebSocket-Version'].to_i == PROTOCOL_VERSION
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(headers['Sec-WebSocket-Key'])
41
+ 'Sec-WebSocket-Accept' => ClientHandshake.accept_token_for(websocket_key)
29
42
  }
30
43
 
31
44
  ServerHandshake.new(101, '1.1', response_headers)
@@ -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]
@@ -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
- response_header = "#{@version} #{@status} #{@reason}#{CRLF}"
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
- response_header << @headers.map do |header, value|
18
+ data << @headers.map do |header, value|
14
19
  "#{header}: #{value}"
15
20
  end.join(CRLF) << CRLF
16
21
  end
17
22
 
18
- response_header << CRLF
19
-
20
- out << response_header
23
+ data << CRLF
24
+ data
21
25
  end
22
26
  end
23
27
  end
@@ -1,3 +1,3 @@
1
1
  module WebSocket
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -1,3 +1,5 @@
1
+ require "http"
2
+
1
3
  require "websocket/version"
2
4
  require "websocket/client_handshake"
3
5
  require "websocket/server_handshake"
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.2
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-08 00:00:00.000000000 Z
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: -3359756691541156568
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: -3359756691541156568
109
+ hash: 2288242846946475689
109
110
  requirements: []
110
111
  rubyforge_project:
111
112
  rubygems_version: 1.8.23