libwebsocket 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +4 -0
- data/README.md +4 -3
- data/lib/libwebsocket.rb +0 -1
- data/lib/libwebsocket/frame.rb +28 -155
- data/lib/libwebsocket/message.rb +1 -3
- data/lib/libwebsocket/version.rb +1 -1
- data/test/libwebsocket/{handshake → opening_handshake}/test_client.rb +0 -0
- data/test/libwebsocket/{handshake → opening_handshake}/test_server.rb +0 -0
- data/test/libwebsocket/{draft-ietf-hybi-00/test_frame.rb → test_frame.rb} +19 -25
- metadata +65 -59
- data/lib/libwebsocket/frame/error.rb +0 -99
- data/test/libwebsocket/draft-ietf-hybi-10/test_frame.rb +0 -84
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -82,7 +82,8 @@ examples directory in the repository.
|
|
82
82
|
|
83
83
|
Copyright (C) 2012, Bernard Potocki.
|
84
84
|
|
85
|
-
|
85
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
86
86
|
|
87
|
-
|
88
|
-
|
87
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
88
|
+
|
89
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/lib/libwebsocket.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
# not provide a WebSocket server or client, but is made for using in http servers
|
3
3
|
# or clients to provide WebSocket support.
|
4
4
|
module LibWebSocket
|
5
|
-
class Error < RuntimeError; end # Universal LibWebSocket error class
|
6
5
|
|
7
6
|
autoload :Cookie, "#{File.dirname(__FILE__)}/libwebsocket/cookie"
|
8
7
|
autoload :Frame, "#{File.dirname(__FILE__)}/libwebsocket/frame"
|
data/lib/libwebsocket/frame.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# -*- encoding: binary -*-
|
2
|
-
|
3
1
|
module LibWebSocket
|
4
2
|
# Construct or parse a WebSocket frame.
|
5
3
|
#
|
@@ -7,50 +5,22 @@ module LibWebSocket
|
|
7
5
|
#
|
8
6
|
# # Create frame
|
9
7
|
# frame = LibWebSocket::Frame.new('123')
|
10
|
-
# frame.
|
8
|
+
# frame.to_s # \x00123\xff
|
11
9
|
#
|
12
10
|
# # Parse frames
|
13
11
|
# frame = LibWebSocket::Frame.new
|
14
|
-
# frame.append(
|
15
|
-
# frame.next #
|
16
|
-
# frame.next #
|
12
|
+
# frame.append("123\x00foo\xff56\x00bar\xff789")
|
13
|
+
# frame.next # => foo
|
14
|
+
# frame.next # => bar
|
17
15
|
class Frame
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
TYPES = {
|
23
|
-
:text => 0x01,
|
24
|
-
:binary => 0x02,
|
25
|
-
:ping => 0x09,
|
26
|
-
:pong => 0x0a,
|
27
|
-
:close => 0x08
|
28
|
-
}
|
29
|
-
|
30
|
-
attr_accessor :buffer, :version, :max_fragments_amount, :max_payload_size, :fin, :rsv, :opcode, :masked
|
31
|
-
|
32
|
-
# Create a new Frame instance. Automatically detect if the passed data is a string or bytes.
|
33
|
-
# Options can be buffer or hash with options:
|
34
|
-
# :buffer - content of buffer
|
35
|
-
# :type - frame type(allowed values: text, binary, ping, pong, close)
|
36
|
-
# :version - protocol version(see readme for supported versions)
|
37
|
-
# :max_fragments_amount - max number of message parts per single frame
|
38
|
-
# :max_payload_size - max bytesize of single message
|
39
|
-
# @example
|
40
|
-
# LibWebSocket::Frame->new('data')
|
41
|
-
# LibWebSocket::Frame->new(:buffer => 'data', :type => 'close')
|
42
|
-
def initialize(options = '')
|
43
|
-
if options.is_a?(Hash)
|
44
|
-
options.each {|k,v| instance_variable_set("@#{k}",v) }
|
45
|
-
else
|
46
|
-
@buffer = options
|
47
|
-
end
|
17
|
+
def initialize(buffer = nil)
|
18
|
+
@buffer = buffer || ''
|
19
|
+
end
|
48
20
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
@max_fragments_amount ||= 128
|
53
|
-
@max_payload_size ||= 65536
|
21
|
+
# Create new frame without modification of current
|
22
|
+
def new(buffer = nil)
|
23
|
+
self.class.new(buffer)
|
54
24
|
end
|
55
25
|
|
56
26
|
# Append a frame chunk.
|
@@ -60,134 +30,37 @@ module LibWebSocket
|
|
60
30
|
def append(string = nil)
|
61
31
|
return unless string.is_a?(String)
|
62
32
|
|
63
|
-
|
33
|
+
@buffer += string
|
64
34
|
|
65
|
-
self.buffer += string
|
66
35
|
return self
|
67
36
|
end
|
68
37
|
|
69
38
|
# Return the next frame.
|
70
39
|
# @example
|
71
|
-
# frame.append(
|
72
|
-
# frame.
|
40
|
+
# frame.append("\x00foo")
|
41
|
+
# frame.append("\xff\x00bar\xff")
|
42
|
+
#
|
43
|
+
# frame.next; # => foo
|
44
|
+
# frame.next; # => bar
|
73
45
|
def next
|
74
|
-
|
75
|
-
return unless bytes
|
46
|
+
return unless @buffer.slice!(/^[^\x00]*\x00(.*?)\xff/m)
|
76
47
|
|
77
|
-
|
78
|
-
|
79
|
-
end
|
48
|
+
string = $1
|
49
|
+
string.force_encoding('UTF-8') if string.respond_to?(:force_encoding)
|
80
50
|
|
81
|
-
|
82
|
-
@opcode || 1
|
51
|
+
return string
|
83
52
|
end
|
84
53
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
def
|
90
|
-
|
91
|
-
# Return the next message as a UTF-8 encoded string.
|
92
|
-
def next_bytes
|
93
|
-
if ['draft-hixie-75', 'draft-ietf-hybi-00'].include? self.version
|
94
|
-
if self.buffer.slice!(/\A\xff\x00/m)
|
95
|
-
self.opcode = TYPES[:close]
|
96
|
-
return ''
|
97
|
-
end
|
98
|
-
|
99
|
-
return unless self.buffer.slice!(/^[^\x00]*\x00(.*?)\xff/m)
|
100
|
-
return $1
|
101
|
-
end
|
102
|
-
|
103
|
-
return unless self.buffer.length >= 2
|
104
|
-
|
105
|
-
while self.buffer.length > 0
|
106
|
-
hdr = self.buffer[0..0]
|
107
|
-
bits = hdr.unpack("B*").first.split(//)
|
108
|
-
|
109
|
-
self.fin = bits[0]
|
110
|
-
self.rsv = bits[1..3]
|
111
|
-
opcode = hdr.unpack('C').first & 0b00001111
|
112
|
-
offset = 1 # FIN,RSV[1-3],OPCODE
|
113
|
-
|
114
|
-
payload_len = buffer[1..1].unpack('C').first
|
115
|
-
self.masked = (payload_len & 0b10000000) >> 7
|
116
|
-
offset += 1 # + MASKED,PAYLOAD_LEN
|
117
|
-
|
118
|
-
payload_len = payload_len & 0b01111111
|
119
|
-
if payload_len == 126
|
120
|
-
return unless self.buffer.length >= offset + 2
|
121
|
-
|
122
|
-
payload_len = self.buffer[offset..offset+2].unpack('n').first
|
123
|
-
offset += 2
|
124
|
-
elsif payload_len > 126
|
125
|
-
return unless self.buffer.length >= offset + 4
|
126
|
-
bits = self.buffer[offset..offset+7].unpack('B*').first
|
127
|
-
bits.gsub!(/^./,'0') # Most significant bit must be 0.
|
128
|
-
bits = bits[32..-1] # No idea how to unpack 64-bit unsigned integer with big-endian byte order
|
129
|
-
payload_len = Array(bits).pack("B*").unpack("N").first
|
130
|
-
offset += 8
|
131
|
-
end
|
132
|
-
|
133
|
-
if payload_len > self.max_payload_size
|
134
|
-
self.buffer = ''
|
135
|
-
raise Error::MessageTooBig.new("Payload is too big. Deny big message (#{payload_len}) or increase max_payload_size (#{self.max_payload_size})")
|
136
|
-
end
|
137
|
-
|
138
|
-
mask = ''
|
139
|
-
if self.masked == 1
|
140
|
-
return unless self.buffer.length >= offset + 4
|
141
|
-
|
142
|
-
mask = self.buffer[offset..offset+4]
|
143
|
-
offset += 4
|
144
|
-
end
|
145
|
-
|
146
|
-
return if self.buffer.length < offset + payload_len
|
147
|
-
|
148
|
-
payload = self.buffer[offset..offset+payload_len-1]
|
149
|
-
payload = self.mask(payload, mask) if self.masked == 1
|
150
|
-
|
151
|
-
self.buffer[0..offset+payload_len-1] = ''
|
152
|
-
|
153
|
-
# Inject control frame
|
154
|
-
if !@fragments.empty? && (opcode & 0b1000 != 0)
|
155
|
-
self.opcode = opcode
|
156
|
-
return payload
|
157
|
-
end
|
158
|
-
|
159
|
-
if self.fin != '0'
|
160
|
-
if @fragments.empty?
|
161
|
-
self.opcode = opcode
|
162
|
-
else
|
163
|
-
self.opcode = @fragments.shift
|
164
|
-
end
|
165
|
-
|
166
|
-
payload = (@fragments + Array(payload)).join
|
167
|
-
@fragments = []
|
168
|
-
return payload
|
169
|
-
else
|
170
|
-
# Remember first fragment opcode
|
171
|
-
@fragments.push(opcode) if @fragments.empty?
|
172
|
-
|
173
|
-
@fragments.push(payload)
|
174
|
-
raise Error::PolicyViolation.new("Too many fragments") if @fragments.size > self.max_fragments_amount
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
return
|
179
|
-
end
|
54
|
+
# Construct a WebSocket frame.
|
55
|
+
# @example
|
56
|
+
# frame = LibWebSocket::Frame.new('foo')
|
57
|
+
# frame.to_s # => \x00foo\xff
|
58
|
+
def to_s
|
59
|
+
ary = ["\x00", @buffer.dup, "\xff"]
|
180
60
|
|
181
|
-
|
61
|
+
ary.collect{ |s| s.force_encoding('UTF-8') if s.respond_to?(:force_encoding) }
|
182
62
|
|
183
|
-
|
184
|
-
mask = mask.bytes.to_a
|
185
|
-
payload = payload.bytes.to_a
|
186
|
-
payload.each_with_index do |p, i|
|
187
|
-
j = i % 4
|
188
|
-
payload[i] = p ^ mask[j]
|
189
|
-
end
|
190
|
-
return payload.collect(&:chr).join
|
63
|
+
return ary.join
|
191
64
|
end
|
192
65
|
|
193
66
|
end
|
data/lib/libwebsocket/message.rb
CHANGED
@@ -126,9 +126,7 @@ module LibWebSocket
|
|
126
126
|
def append(data)
|
127
127
|
return if self.error
|
128
128
|
|
129
|
-
|
130
|
-
|
131
|
-
@buffer << data
|
129
|
+
@buffer += data
|
132
130
|
|
133
131
|
if @buffer.length > @max_message_size
|
134
132
|
self.error = 'Message is too long'
|
data/lib/libwebsocket/version.rb
CHANGED
File without changes
|
File without changes
|
@@ -1,10 +1,9 @@
|
|
1
|
-
# -*- encoding: binary -*-
|
2
1
|
require 'test_helper'
|
3
2
|
|
4
3
|
class TestFrame < Test::Unit::TestCase
|
5
4
|
|
6
|
-
def
|
7
|
-
f = LibWebSocket::Frame.new
|
5
|
+
def test_append
|
6
|
+
f = LibWebSocket::Frame.new
|
8
7
|
|
9
8
|
f.append
|
10
9
|
assert_nil f.next
|
@@ -22,11 +21,6 @@ class TestFrame < Test::Unit::TestCase
|
|
22
21
|
f.append("\xff")
|
23
22
|
assert_equal '', f.next
|
24
23
|
|
25
|
-
f.append("\xff")
|
26
|
-
f.append("\x00")
|
27
|
-
assert_equal '', f.next
|
28
|
-
assert f.close?
|
29
|
-
|
30
24
|
f.append("\x00")
|
31
25
|
assert_nil f.next
|
32
26
|
f.append("foo")
|
@@ -44,28 +38,28 @@ class TestFrame < Test::Unit::TestCase
|
|
44
38
|
assert_nil f.next
|
45
39
|
|
46
40
|
# We append bytes, but read characters
|
47
|
-
msg =
|
41
|
+
msg = "\342\230\272"
|
48
42
|
f.append("\x00" + msg + "\xff")
|
49
43
|
msg.force_encoding('UTF-8') if msg.respond_to?(:force_encoding)
|
50
44
|
assert_equal msg, f.next
|
51
45
|
end
|
52
46
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
#
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
47
|
+
def test_new
|
48
|
+
f = LibWebSocket::Frame.new
|
49
|
+
msg = "\x00\xff"
|
50
|
+
msg.force_encoding('UTF-8') if msg.respond_to?(:force_encoding)
|
51
|
+
assert_equal msg, f.to_s
|
52
|
+
|
53
|
+
f = LibWebSocket::Frame.new('123')
|
54
|
+
msg = "\x00123\xff"
|
55
|
+
msg.force_encoding('UTF-8') if msg.respond_to?(:force_encoding)
|
56
|
+
assert_equal msg, f.to_s
|
57
|
+
|
58
|
+
# We pass characters, but send bytes
|
59
|
+
f = LibWebSocket::Frame.new("\342\230\272")
|
60
|
+
msg = "\x00\342\230\272\xff"
|
61
|
+
msg.force_encoding('UTF-8') if msg.respond_to?(:force_encoding)
|
62
|
+
assert_equal msg, f.to_s
|
69
63
|
end
|
70
64
|
|
71
65
|
end
|
metadata
CHANGED
@@ -1,55 +1,60 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: libwebsocket
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 17
|
5
5
|
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 5
|
10
|
+
version: 0.1.5
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- Bernard Potocki
|
9
14
|
autorequire:
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
17
|
+
|
18
|
+
date: 2012-07-27 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
15
21
|
name: addressable
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ! '>='
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '0'
|
22
|
-
type: :runtime
|
23
22
|
prerelease: false
|
24
|
-
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
24
|
none: false
|
26
|
-
requirements:
|
27
|
-
- -
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
31
35
|
name: rake
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ! '>='
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: '0'
|
38
|
-
type: :development
|
39
36
|
prerelease: false
|
40
|
-
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
38
|
none: false
|
42
|
-
requirements:
|
43
|
-
- -
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
46
48
|
description: Universal Ruby library to handle WebSocket protocol
|
47
|
-
email:
|
49
|
+
email:
|
48
50
|
- bernard.potocki@imanel.org
|
49
51
|
executables: []
|
52
|
+
|
50
53
|
extensions: []
|
54
|
+
|
51
55
|
extra_rdoc_files: []
|
52
|
-
|
56
|
+
|
57
|
+
files:
|
53
58
|
- .gitignore
|
54
59
|
- .travis.yml
|
55
60
|
- CHANGELOG.md
|
@@ -64,7 +69,6 @@ files:
|
|
64
69
|
- lib/libwebsocket/cookie/request.rb
|
65
70
|
- lib/libwebsocket/cookie/response.rb
|
66
71
|
- lib/libwebsocket/frame.rb
|
67
|
-
- lib/libwebsocket/frame/error.rb
|
68
72
|
- lib/libwebsocket/message.rb
|
69
73
|
- lib/libwebsocket/opening_handshake.rb
|
70
74
|
- lib/libwebsocket/opening_handshake/client.rb
|
@@ -77,11 +81,10 @@ files:
|
|
77
81
|
- libwebsocket.gemspec
|
78
82
|
- test/libwebsocket/cookie/request.rb
|
79
83
|
- test/libwebsocket/cookie/response.rb
|
80
|
-
- test/libwebsocket/
|
81
|
-
- test/libwebsocket/
|
82
|
-
- test/libwebsocket/handshake/test_client.rb
|
83
|
-
- test/libwebsocket/handshake/test_server.rb
|
84
|
+
- test/libwebsocket/opening_handshake/test_client.rb
|
85
|
+
- test/libwebsocket/opening_handshake/test_server.rb
|
84
86
|
- test/libwebsocket/test_cookie.rb
|
87
|
+
- test/libwebsocket/test_frame.rb
|
85
88
|
- test/libwebsocket/test_message.rb
|
86
89
|
- test/libwebsocket/test_request_75.rb
|
87
90
|
- test/libwebsocket/test_request_76.rb
|
@@ -93,42 +96,44 @@ files:
|
|
93
96
|
- test/test_helper.rb
|
94
97
|
homepage: http://github.com/imanel/libwebsocket
|
95
98
|
licenses: []
|
99
|
+
|
96
100
|
post_install_message:
|
97
101
|
rdoc_options: []
|
98
|
-
|
102
|
+
|
103
|
+
require_paths:
|
99
104
|
- lib
|
100
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
106
|
none: false
|
102
|
-
requirements:
|
103
|
-
- -
|
104
|
-
- !ruby/object:Gem::Version
|
105
|
-
|
106
|
-
segments:
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
hash: 3
|
111
|
+
segments:
|
107
112
|
- 0
|
108
|
-
|
109
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
version: "0"
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
115
|
none: false
|
111
|
-
requirements:
|
112
|
-
- -
|
113
|
-
- !ruby/object:Gem::Version
|
114
|
-
|
115
|
-
segments:
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
hash: 3
|
120
|
+
segments:
|
116
121
|
- 0
|
117
|
-
|
122
|
+
version: "0"
|
118
123
|
requirements: []
|
124
|
+
|
119
125
|
rubyforge_project:
|
120
126
|
rubygems_version: 1.8.24
|
121
127
|
signing_key:
|
122
128
|
specification_version: 3
|
123
129
|
summary: Universal Ruby library to handle WebSocket protocol
|
124
|
-
test_files:
|
130
|
+
test_files:
|
125
131
|
- test/libwebsocket/cookie/request.rb
|
126
132
|
- test/libwebsocket/cookie/response.rb
|
127
|
-
- test/libwebsocket/
|
128
|
-
- test/libwebsocket/
|
129
|
-
- test/libwebsocket/handshake/test_client.rb
|
130
|
-
- test/libwebsocket/handshake/test_server.rb
|
133
|
+
- test/libwebsocket/opening_handshake/test_client.rb
|
134
|
+
- test/libwebsocket/opening_handshake/test_server.rb
|
131
135
|
- test/libwebsocket/test_cookie.rb
|
136
|
+
- test/libwebsocket/test_frame.rb
|
132
137
|
- test/libwebsocket/test_message.rb
|
133
138
|
- test/libwebsocket/test_request_75.rb
|
134
139
|
- test/libwebsocket/test_request_76.rb
|
@@ -138,3 +143,4 @@ test_files:
|
|
138
143
|
- test/libwebsocket/test_response_common.rb
|
139
144
|
- test/libwebsocket/test_url.rb
|
140
145
|
- test/test_helper.rb
|
146
|
+
has_rdoc:
|
@@ -1,99 +0,0 @@
|
|
1
|
-
module LibWebSocket
|
2
|
-
class Frame
|
3
|
-
|
4
|
-
# Generic close error command for frame. Should not be called directly - use one of subclasses.
|
5
|
-
# This should be catched and responded to according to clean_close? and status.
|
6
|
-
class Error < LibWebSocket::Error
|
7
|
-
|
8
|
-
# Should close frame be sent before closing?
|
9
|
-
# If so then status code should be used to build it.
|
10
|
-
def clean_close?
|
11
|
-
true
|
12
|
-
end
|
13
|
-
|
14
|
-
# Status code for closing frame.
|
15
|
-
def status_code
|
16
|
-
500 # This should not be called directly
|
17
|
-
end
|
18
|
-
|
19
|
-
# 1000 indicates a normal closure, meaning whatever purpose the
|
20
|
-
# connection was established for has been fulfilled.
|
21
|
-
class NormalClosure < Error
|
22
|
-
def status_code; 1000; end
|
23
|
-
end
|
24
|
-
|
25
|
-
# 1001 indicates that an endpoint is "going away", such as a server
|
26
|
-
# going down, or a browser having navigated away from a page.
|
27
|
-
class GoingAway < Error
|
28
|
-
def status_code; 1001; end
|
29
|
-
end
|
30
|
-
|
31
|
-
# 1002 indicates that an endpoint is terminating the connection due
|
32
|
-
# to a protocol error.
|
33
|
-
class ProtocolError < Error
|
34
|
-
def status_code; 1002; end
|
35
|
-
end
|
36
|
-
|
37
|
-
# 1003 indicates that an endpoint is terminating the connection
|
38
|
-
# because it has received a type of data it cannot accept (e.g. an
|
39
|
-
# endpoint that understands only text data MAY send this if it
|
40
|
-
# receives a binary message).
|
41
|
-
class UnsupportedData < Error
|
42
|
-
def status_code; 1003; end
|
43
|
-
end
|
44
|
-
|
45
|
-
# 1005 is a reserved value and MUST NOT be set as a status code in a
|
46
|
-
# Close control frame by an endpoint. It is designated for use in
|
47
|
-
# applications expecting a status code to indicate that no status
|
48
|
-
# code was actually present.
|
49
|
-
class NoStatusRcvd < Error
|
50
|
-
def status_code; 1005; end
|
51
|
-
end
|
52
|
-
|
53
|
-
# 1006 is a reserved value and MUST NOT be set as a status code in a
|
54
|
-
# Close control frame by an endpoint. It is designated for use in
|
55
|
-
# applications expecting a status code to indicate that the
|
56
|
-
# connection was closed abnormally, e.g. without sending or
|
57
|
-
# receiving a Close control frame.
|
58
|
-
class AbnormalClosure < Error
|
59
|
-
def status_code; 1006; end
|
60
|
-
end
|
61
|
-
|
62
|
-
# 1007 indicates that an endpoint is terminating the connection
|
63
|
-
# because it has received data within a message that was not
|
64
|
-
# consistent with the type of the message (e.g., non-UTF-8 [RFC3629]
|
65
|
-
# data within a text message).
|
66
|
-
class InvalidFramePayloadData < Error
|
67
|
-
def status_code; 1007; end
|
68
|
-
end
|
69
|
-
|
70
|
-
# 1008 indicates that an endpoint is terminating the connection
|
71
|
-
# because it has received a message that violates its policy. This
|
72
|
-
# is a generic status code that can be returned when there is no
|
73
|
-
# other more suitable status code (e.g. 1003 or 1009), or if there
|
74
|
-
# is a need to hide specific details about the policy.
|
75
|
-
class PolicyViolation < Error
|
76
|
-
def status_code; 1008; end
|
77
|
-
end
|
78
|
-
|
79
|
-
# 1009 indicates that an endpoint is terminating the connection
|
80
|
-
# because it has received a message which is too big for it to
|
81
|
-
# process.
|
82
|
-
class MessageTooBig < Error
|
83
|
-
def status_code; 1009; end
|
84
|
-
end
|
85
|
-
|
86
|
-
# 1010 indicates that an endpoint (client) is terminating the
|
87
|
-
# connection because it has expected the server to negotiate one or
|
88
|
-
# more extension, but the server didn't return them in the response
|
89
|
-
# message of the WebSocket handshake. The list of extensions which
|
90
|
-
# are needed SHOULD appear in the /reason/ part of the Close frame.
|
91
|
-
# Note that this status code is not used by the server, because it
|
92
|
-
# can fail the WebSocket handshake instead.
|
93
|
-
class MandatoryExtension < Error
|
94
|
-
def status_code; 1010; end
|
95
|
-
end
|
96
|
-
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
@@ -1,84 +0,0 @@
|
|
1
|
-
# -*- encoding: binary -*-
|
2
|
-
require 'test_helper'
|
3
|
-
|
4
|
-
class TestFrame < Test::Unit::TestCase
|
5
|
-
|
6
|
-
def test_append_ietf_hybi_10
|
7
|
-
f = LibWebSocket::Frame.new(:version => 'draft-ietf-hybi-10')
|
8
|
-
|
9
|
-
f.append
|
10
|
-
assert_nil f.next
|
11
|
-
f.append('')
|
12
|
-
assert_nil f.next
|
13
|
-
|
14
|
-
# Not masked
|
15
|
-
f.append ["810548656c6c6f"].pack('H*')
|
16
|
-
assert_equal 'Hello', f.next_bytes
|
17
|
-
assert_equal 1, f.opcode
|
18
|
-
assert f.text?
|
19
|
-
|
20
|
-
# Multi
|
21
|
-
f.append(["810548656c6c6f"].pack('H*') + ["810548656c6c6f"].pack('H*'))
|
22
|
-
assert_equal 'Hello', f.next_bytes
|
23
|
-
assert_equal 'Hello', f.next_bytes
|
24
|
-
|
25
|
-
# Masked
|
26
|
-
f.append ["818537fa213d7f9f4d5158"].pack('H*')
|
27
|
-
assert_equal 'Hello', f.next_bytes
|
28
|
-
assert_equal 1, f.opcode
|
29
|
-
|
30
|
-
# Fragments
|
31
|
-
f.append ["010348656c"].pack("H*")
|
32
|
-
assert_nil f.next_bytes
|
33
|
-
f.append ["80026c6f"].pack("H*")
|
34
|
-
assert_equal 'Hello', f.next_bytes
|
35
|
-
assert_equal 1, f.opcode
|
36
|
-
|
37
|
-
# Multi fragments
|
38
|
-
f.append(["010348656c"].pack('H*') + ["80026c6f"].pack('H*'))
|
39
|
-
assert_equal 'Hello', f.next_bytes
|
40
|
-
assert_equal 1, f.opcode
|
41
|
-
|
42
|
-
# Injected control frame (1 fragment, ping, 2 fragment)
|
43
|
-
f.append ["010348656c"].pack('H*')
|
44
|
-
f.append ["890548656c6c6f"].pack('H*')
|
45
|
-
f.append ["80026c6f"].pack('H*')
|
46
|
-
assert_equal 'Hello', f.next_bytes
|
47
|
-
assert_equal 9, f.opcode
|
48
|
-
assert_equal 'Hello', f.next_bytes
|
49
|
-
assert_equal 1, f.opcode
|
50
|
-
|
51
|
-
# Too many fragments
|
52
|
-
130.times { f.append(["010348656c"].pack('H*')) }
|
53
|
-
assert_raise(LibWebSocket::Frame::Error::PolicyViolation) { f.next_bytes }
|
54
|
-
|
55
|
-
# Ping request
|
56
|
-
f = LibWebSocket::Frame.new(:version => 'draft-ietf-hybi-10')
|
57
|
-
f.append ["890548656c6c6f"].pack('H*')
|
58
|
-
assert_equal 'Hello', f.next_bytes
|
59
|
-
assert_equal 9, f.opcode
|
60
|
-
assert f.ping?
|
61
|
-
|
62
|
-
# Ping response
|
63
|
-
f.append ["8a0548656c6c6f"].pack('H*')
|
64
|
-
assert_equal 'Hello', f.next_bytes
|
65
|
-
assert_equal 10, f.opcode
|
66
|
-
assert f.pong?
|
67
|
-
|
68
|
-
# 256 bytes
|
69
|
-
f.append ["827E0100" + '05' * 256].pack('H*')
|
70
|
-
assert_equal 256, f.next_bytes.length
|
71
|
-
assert_equal 2, f.opcode
|
72
|
-
assert f.binary?
|
73
|
-
|
74
|
-
# 64KiB
|
75
|
-
f.append ["827F0000000000010000" + '05' * 65536].pack('H*')
|
76
|
-
assert_equal 65536, f.next_bytes.length
|
77
|
-
assert_equal 2, f.opcode
|
78
|
-
|
79
|
-
# Too big frame
|
80
|
-
f.append ["827F0000000000100000" + '05' * (65536 + 1)].pack('H*')
|
81
|
-
assert_raise(LibWebSocket::Frame::Error::MessageTooBig) { f.next_bytes }
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|