faye-websocket 0.1.2 → 0.2.0
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.
Potentially problematic release.
This version of faye-websocket might be problematic. Click here for more details.
- data/CHANGELOG.txt +22 -0
- data/README.rdoc +24 -2
- data/examples/autobahn_client.rb +1 -2
- data/examples/index.html +7 -2
- data/examples/server.rb +2 -2
- data/ext/faye_websocket_mask/extconf.rb +6 -0
- data/ext/faye_websocket_mask/faye_websocket_mask.c +35 -0
- data/lib/faye/websocket.rb +9 -4
- data/lib/faye/websocket/client.rb +7 -5
- data/lib/faye/websocket/draft75_parser.rb +53 -24
- data/lib/faye/websocket/draft76_parser.rb +15 -1
- data/lib/faye/websocket/{protocol8_parser.rb → hybi_parser.rb} +147 -168
- data/lib/faye/websocket/hybi_parser/handshake.rb +78 -0
- data/lib/faye/websocket/hybi_parser/stream_reader.rb +29 -0
- data/spec/faye/websocket/client_spec.rb +19 -7
- data/spec/faye/websocket/draft75_parser_spec.rb +43 -13
- data/spec/faye/websocket/draft76_parser_spec.rb +34 -0
- data/spec/faye/websocket/{protocol8_parser_spec.rb → hybi_parser_spec.rb} +39 -28
- data/spec/spec_helper.rb +1 -1
- metadata +79 -95
@@ -0,0 +1,78 @@
|
|
1
|
+
module Faye
|
2
|
+
class WebSocket
|
3
|
+
class HybiParser
|
4
|
+
|
5
|
+
class Handshake
|
6
|
+
GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
|
7
|
+
|
8
|
+
attr_reader :protocol
|
9
|
+
|
10
|
+
def initialize(uri, protocols)
|
11
|
+
@uri = uri
|
12
|
+
@protocols = protocols
|
13
|
+
@key = Base64.encode64((1..16).map { rand(255).chr } * '').strip
|
14
|
+
@accept = Base64.encode64(Digest::SHA1.digest(@key + GUID)).strip
|
15
|
+
@buffer = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def request_data
|
19
|
+
hostname = @uri.host + (@uri.port ? ":#{@uri.port}" : '')
|
20
|
+
|
21
|
+
headers = [
|
22
|
+
"GET #{@uri.path}#{@uri.query ? '?' : ''}#{@uri.query} HTTP/1.1",
|
23
|
+
"Host: #{hostname}",
|
24
|
+
"Upgrade: websocket",
|
25
|
+
"Connection: Upgrade",
|
26
|
+
"Sec-WebSocket-Key: #{@key}",
|
27
|
+
"Sec-WebSocket-Version: 13"
|
28
|
+
]
|
29
|
+
|
30
|
+
if @protocols
|
31
|
+
headers << "Sec-WebSocket-Protocol: #{@protocols * ', '}"
|
32
|
+
end
|
33
|
+
|
34
|
+
(headers + ['','']).join("\r\n")
|
35
|
+
end
|
36
|
+
|
37
|
+
def parse(data)
|
38
|
+
message = []
|
39
|
+
complete = false
|
40
|
+
data.each_byte do |byte|
|
41
|
+
if complete
|
42
|
+
message << byte
|
43
|
+
else
|
44
|
+
@buffer << byte
|
45
|
+
complete ||= complete?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
message
|
49
|
+
end
|
50
|
+
|
51
|
+
def complete?
|
52
|
+
@buffer[-4..-1] == [0x0D, 0x0A, 0x0D, 0x0A]
|
53
|
+
end
|
54
|
+
|
55
|
+
def valid?
|
56
|
+
data = WebSocket.encode(@buffer)
|
57
|
+
|
58
|
+
response = Net::HTTPResponse.read_new(Net::BufferedIO.new(StringIO.new(data)))
|
59
|
+
return false unless response.code.to_i == 101
|
60
|
+
|
61
|
+
upgrade = response['Upgrade']
|
62
|
+
connection = response['Connection']
|
63
|
+
protocol = response['Sec-WebSocket-Protocol']
|
64
|
+
|
65
|
+
@protocol = @protocols && @protocols.include?(protocol) ?
|
66
|
+
protocol :
|
67
|
+
nil
|
68
|
+
|
69
|
+
upgrade and upgrade =~ /^websocket$/i and
|
70
|
+
connection and connection.split(/\s*,\s*/).include?('Upgrade') and
|
71
|
+
((!@protocols and !protocol) or @protocol) and
|
72
|
+
response['Sec-WebSocket-Accept'] == @accept
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Faye
|
2
|
+
class WebSocket
|
3
|
+
class HybiParser
|
4
|
+
|
5
|
+
class StreamReader
|
6
|
+
def initialize
|
7
|
+
@queue = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def read(length)
|
11
|
+
read_bytes(length)
|
12
|
+
end
|
13
|
+
|
14
|
+
def put(bytes)
|
15
|
+
return unless bytes and bytes.size > 0
|
16
|
+
@queue.concat(bytes)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def read_bytes(length)
|
22
|
+
return nil if length > @queue.size
|
23
|
+
@queue.shift(length)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -15,7 +15,7 @@ WebSocketSteps = EM::RSpec.async_steps do
|
|
15
15
|
EM.next_tick(&callback)
|
16
16
|
end
|
17
17
|
|
18
|
-
def open_socket(url, &callback)
|
18
|
+
def open_socket(url, protocols, &callback)
|
19
19
|
done = false
|
20
20
|
|
21
21
|
resume = lambda do |open|
|
@@ -26,7 +26,7 @@ WebSocketSteps = EM::RSpec.async_steps do
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
@ws = Faye::WebSocket::Client.new(url)
|
29
|
+
@ws = Faye::WebSocket::Client.new(url, protocols)
|
30
30
|
|
31
31
|
@ws.onopen = lambda { |e| resume.call(true) }
|
32
32
|
@ws.onclose = lambda { |e| resume.call(false) }
|
@@ -50,6 +50,11 @@ WebSocketSteps = EM::RSpec.async_steps do
|
|
50
50
|
callback.call
|
51
51
|
end
|
52
52
|
|
53
|
+
def check_protocol(protocol, &callback)
|
54
|
+
@ws.protocol.should == protocol
|
55
|
+
callback.call
|
56
|
+
end
|
57
|
+
|
53
58
|
def listen_for_message(&callback)
|
54
59
|
@ws.add_event_listener('message', lambda { |e| @message = e.data })
|
55
60
|
callback.call
|
@@ -74,6 +79,7 @@ end
|
|
74
79
|
describe Faye::WebSocket::Client do
|
75
80
|
include WebSocketSteps
|
76
81
|
|
82
|
+
let(:protocols) { ["foo", "echo"] }
|
77
83
|
let(:plain_text_url) { "ws://0.0.0.0:8000/" }
|
78
84
|
let(:secure_url) { "wss://0.0.0.0:8000/" }
|
79
85
|
|
@@ -84,23 +90,29 @@ describe Faye::WebSocket::Client do
|
|
84
90
|
|
85
91
|
shared_examples_for "socket client" do
|
86
92
|
it "can open a connection" do
|
87
|
-
open_socket(socket_url)
|
93
|
+
open_socket(socket_url, protocols)
|
88
94
|
check_open
|
95
|
+
check_protocol("echo")
|
89
96
|
end
|
90
97
|
|
91
98
|
it "cannot open a connection to the wrong host" do
|
92
|
-
open_socket(blocked_url)
|
99
|
+
open_socket(blocked_url, protocols)
|
100
|
+
check_closed
|
101
|
+
end
|
102
|
+
|
103
|
+
it "cannot open a connection with unacceptable protocols" do
|
104
|
+
open_socket(socket_url, ["foo"])
|
93
105
|
check_closed
|
94
106
|
end
|
95
107
|
|
96
108
|
it "can close the connection" do
|
97
|
-
open_socket(socket_url)
|
109
|
+
open_socket(socket_url, protocols)
|
98
110
|
close_socket
|
99
111
|
check_closed
|
100
112
|
end
|
101
113
|
|
102
114
|
describe "in the OPEN state" do
|
103
|
-
before { open_socket(socket_url) }
|
115
|
+
before { open_socket(socket_url, protocols) }
|
104
116
|
|
105
117
|
it "can send and receive messages" do
|
106
118
|
listen_for_message
|
@@ -111,7 +123,7 @@ describe Faye::WebSocket::Client do
|
|
111
123
|
|
112
124
|
describe "in the CLOSED state" do
|
113
125
|
before do
|
114
|
-
open_socket(socket_url)
|
126
|
+
open_socket(socket_url, protocols)
|
115
127
|
close_socket
|
116
128
|
end
|
117
129
|
|
@@ -11,21 +11,51 @@ describe Faye::WebSocket::Draft75Parser do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
describe :parse do
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
shared_examples_for "draft-75 parser" do
|
15
|
+
it "parses text frames" do
|
16
|
+
@web_socket.should_receive(:receive).with("Hello")
|
17
|
+
parse [0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "parses multiple frames from the same packet" do
|
21
|
+
@web_socket.should_receive(:receive).with("Hello").exactly(2)
|
22
|
+
parse [0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff, 0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
|
23
|
+
end
|
24
|
+
|
25
|
+
it "parses text frames beginning 0x00-0x7F" do
|
26
|
+
@web_socket.should_receive(:receive).with("Hello")
|
27
|
+
parse [0x66, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
|
28
|
+
end
|
29
|
+
|
30
|
+
it "ignores frames with a length header" do
|
31
|
+
@web_socket.should_not_receive(:receive)
|
32
|
+
parse [0x80, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "parses text following an ignored block" do
|
36
|
+
@web_socket.should_receive(:receive).with("Hello")
|
37
|
+
parse [0x80, 0x02, 0x48, 0x65, 0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
|
38
|
+
end
|
39
|
+
|
40
|
+
it "parses multibyte text frames" do
|
41
|
+
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
42
|
+
parse [0x00, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf, 0xff]
|
43
|
+
end
|
44
|
+
|
45
|
+
it "parses frames received in several packets" do
|
46
|
+
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
47
|
+
parse [0x00, 0x41, 0x70, 0x70, 0x6c, 0x65]
|
48
|
+
parse [0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf, 0xff]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "parses fragmented frames" do
|
52
|
+
@web_socket.should_receive(:receive).with("Hello")
|
53
|
+
parse [0x00, 0x48, 0x65, 0x6c]
|
54
|
+
parse [0x6c, 0x6f, 0xff]
|
55
|
+
end
|
17
56
|
end
|
18
57
|
|
19
|
-
|
20
|
-
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
21
|
-
parse [0x00, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf, 0xff]
|
22
|
-
end
|
23
|
-
|
24
|
-
it "parses fragmented frames" do
|
25
|
-
@web_socket.should_receive(:receive).with("Hello")
|
26
|
-
parse [0x00, 0x48, 0x65, 0x6c]
|
27
|
-
parse [0x6c, 0x6f, 0xff]
|
28
|
-
end
|
58
|
+
it_should_behave_like "draft-75 parser"
|
29
59
|
end
|
30
60
|
|
31
61
|
describe :frame do
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding=utf-8
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe Faye::WebSocket::Draft76Parser do
|
6
|
+
include EncodingHelper
|
7
|
+
|
8
|
+
before do
|
9
|
+
@web_socket = mock Faye::WebSocket
|
10
|
+
@parser = Faye::WebSocket::Draft76Parser.new(@web_socket)
|
11
|
+
@parser.instance_eval { @handshake_complete = true }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe :parse do
|
15
|
+
it_should_behave_like "draft-75 parser"
|
16
|
+
|
17
|
+
it "closes the socket if a close frame is received" do
|
18
|
+
@web_socket.should_receive(:close)
|
19
|
+
parse [0xFF, 0x00]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe :frame do
|
24
|
+
it "returns the given string formatted as a WebSocket frame" do
|
25
|
+
bytes(@parser.frame "Hello").should == [0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
|
26
|
+
end
|
27
|
+
|
28
|
+
it "encodes multibyte characters correctly" do
|
29
|
+
message = encode "Apple = "
|
30
|
+
bytes(@parser.frame message).should == [0x00, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf, 0xff]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -2,17 +2,17 @@
|
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
|
-
describe Faye::WebSocket::
|
5
|
+
describe Faye::WebSocket::HybiParser do
|
6
6
|
include EncodingHelper
|
7
|
-
|
7
|
+
|
8
8
|
before do
|
9
9
|
@web_socket = mock Faye::WebSocket
|
10
|
-
@parser = Faye::WebSocket::
|
10
|
+
@parser = Faye::WebSocket::HybiParser.new(@web_socket)
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
describe :parse do
|
14
14
|
let(:mask) { (1..4).map { rand 255 } }
|
15
|
-
|
15
|
+
|
16
16
|
def mask_message(*bytes)
|
17
17
|
output = []
|
18
18
|
bytes.each_with_index do |byte, i|
|
@@ -20,124 +20,135 @@ describe Faye::WebSocket::Protocol8Parser do
|
|
20
20
|
end
|
21
21
|
output
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
it "parses unmasked text frames" do
|
25
25
|
@web_socket.should_receive(:receive).with("Hello")
|
26
26
|
parse [0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
|
+
it "parses multiple frames from the same packet" do
|
30
|
+
@web_socket.should_receive(:receive).with("Hello").exactly(2)
|
31
|
+
parse [0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
|
32
|
+
end
|
33
|
+
|
29
34
|
it "parses empty text frames" do
|
30
35
|
@web_socket.should_receive(:receive).with("")
|
31
36
|
parse [0x81, 0x00]
|
32
37
|
end
|
33
|
-
|
38
|
+
|
34
39
|
it "parses fragmented text frames" do
|
35
40
|
@web_socket.should_receive(:receive).with("Hello")
|
36
41
|
parse [0x01, 0x03, 0x48, 0x65, 0x6c]
|
37
42
|
parse [0x80, 0x02, 0x6c, 0x6f]
|
38
43
|
end
|
39
|
-
|
44
|
+
|
40
45
|
it "parses masked text frames" do
|
41
46
|
@web_socket.should_receive(:receive).with("Hello")
|
42
47
|
parse [0x81, 0x85] + mask + mask_message(0x48, 0x65, 0x6c, 0x6c, 0x6f)
|
43
48
|
end
|
44
|
-
|
49
|
+
|
45
50
|
it "parses masked empty text frames" do
|
46
51
|
@web_socket.should_receive(:receive).with("")
|
47
52
|
parse [0x81, 0x80] + mask + mask_message()
|
48
53
|
end
|
49
|
-
|
54
|
+
|
50
55
|
it "parses masked fragmented text frames" do
|
51
56
|
@web_socket.should_receive(:receive).with("Hello")
|
52
57
|
parse [0x01, 0x81] + mask + mask_message(0x48)
|
53
58
|
parse [0x80, 0x84] + mask + mask_message(0x65, 0x6c, 0x6c, 0x6f)
|
54
59
|
end
|
55
|
-
|
60
|
+
|
56
61
|
it "closes the socket if the frame has an unrecognized opcode" do
|
57
62
|
@web_socket.should_receive(:close).with(1002, nil, false)
|
58
63
|
parse [0x83, 0x00]
|
59
64
|
end
|
60
|
-
|
65
|
+
|
61
66
|
it "closes the socket if a close frame is received" do
|
62
67
|
@web_socket.should_receive(:close).with(1000, "Hello", false)
|
63
68
|
parse [0x88, 0x07, 0x03, 0xe8, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
|
64
69
|
end
|
65
|
-
|
70
|
+
|
66
71
|
it "parses unmasked multibyte text frames" do
|
67
72
|
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
68
73
|
parse [0x81, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf]
|
69
74
|
end
|
70
|
-
|
75
|
+
|
76
|
+
it "parses frames received in several packets" do
|
77
|
+
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
78
|
+
parse [0x81, 0x0b, 0x41, 0x70, 0x70, 0x6c]
|
79
|
+
parse [0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf]
|
80
|
+
end
|
81
|
+
|
71
82
|
it "parses fragmented multibyte text frames" do
|
72
83
|
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
73
84
|
parse [0x01, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3]
|
74
85
|
parse [0x80, 0x01, 0xbf]
|
75
86
|
end
|
76
|
-
|
87
|
+
|
77
88
|
it "parses masked multibyte text frames" do
|
78
89
|
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
79
90
|
parse [0x81, 0x8b] + mask + mask_message(0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf)
|
80
91
|
end
|
81
|
-
|
92
|
+
|
82
93
|
it "parses masked fragmented multibyte text frames" do
|
83
94
|
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
84
95
|
parse [0x01, 0x8a] + mask + mask_message(0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3)
|
85
96
|
parse [0x80, 0x81] + mask + mask_message(0xbf)
|
86
97
|
end
|
87
|
-
|
98
|
+
|
88
99
|
it "parses unmasked medium-length text frames" do
|
89
100
|
@web_socket.should_receive(:receive).with("Hello" * 40)
|
90
101
|
parse [0x81, 0x7e, 0x00, 0xc8] + [0x48, 0x65, 0x6c, 0x6c, 0x6f] * 40
|
91
102
|
end
|
92
|
-
|
103
|
+
|
93
104
|
it "parses masked medium-length text frames" do
|
94
105
|
@web_socket.should_receive(:receive).with("Hello" * 40)
|
95
106
|
parse [0x81, 0xfe, 0x00, 0xc8] + mask + mask_message(*([0x48, 0x65, 0x6c, 0x6c, 0x6f] * 40))
|
96
107
|
end
|
97
|
-
|
108
|
+
|
98
109
|
it "replies to pings with a pong" do
|
99
110
|
@web_socket.should_receive(:send).with([0x4f, 0x48, 0x41, 0x49], :pong)
|
100
111
|
parse [0x89, 0x04, 0x4f, 0x48, 0x41, 0x49]
|
101
112
|
end
|
102
113
|
end
|
103
|
-
|
114
|
+
|
104
115
|
describe :frame do
|
105
116
|
it "returns the given string formatted as a WebSocket frame" do
|
106
117
|
bytes(@parser.frame "Hello").should == [0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
|
107
118
|
end
|
108
|
-
|
119
|
+
|
109
120
|
it "encodes multibyte characters correctly" do
|
110
121
|
message = encode "Apple = "
|
111
122
|
bytes(@parser.frame message).should == [0x81, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf]
|
112
123
|
end
|
113
|
-
|
124
|
+
|
114
125
|
it "encodes medium-length strings using extra length bytes" do
|
115
126
|
message = "Hello" * 40
|
116
127
|
bytes(@parser.frame message).should == [0x81, 0x7e, 0x00, 0xc8] + [0x48, 0x65, 0x6c, 0x6c, 0x6f] * 40
|
117
128
|
end
|
118
|
-
|
129
|
+
|
119
130
|
it "encodes long strings using extra length bytes" do
|
120
131
|
message = "Hello" * 13108
|
121
132
|
bytes(@parser.frame message).should == [0x81, 0x7f] +
|
122
133
|
[0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04] +
|
123
134
|
[0x48, 0x65, 0x6c, 0x6c, 0x6f] * 13108
|
124
135
|
end
|
125
|
-
|
136
|
+
|
126
137
|
it "encodes close frames with an error code" do
|
127
138
|
frame = @parser.frame "Hello", :close, 1002
|
128
139
|
bytes(frame).should == [0x88, 0x07, 0x03, 0xea, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
|
129
140
|
end
|
130
|
-
|
141
|
+
|
131
142
|
it "encodes pong frames" do
|
132
143
|
bytes(@parser.frame '', :pong).should == [0x8a, 0x00]
|
133
144
|
end
|
134
145
|
end
|
135
|
-
|
146
|
+
|
136
147
|
describe :utf8 do
|
137
148
|
it "detects valid UTF-8" do
|
138
149
|
Faye::WebSocket.valid_utf8?( [72, 101, 108, 108, 111, 45, 194, 181, 64, 195, 159, 195, 182, 195, 164, 195, 188, 195, 160, 195, 161, 45, 85, 84, 70, 45, 56, 33, 33] ).should be_true
|
139
150
|
end
|
140
|
-
|
151
|
+
|
141
152
|
it "detects invalid UTF-8" do
|
142
153
|
Faye::WebSocket.valid_utf8?( [206, 186, 225, 189, 185, 207, 131, 206, 188, 206, 181, 237, 160, 128, 101, 100, 105, 116, 101, 100] ).should be_false
|
143
154
|
end
|