faye-websocket 0.4.7 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of faye-websocket might be problematic. Click here for more details.
- data/CHANGELOG.md +81 -0
- data/README.md +408 -0
- data/examples/app.rb +4 -1
- data/examples/autobahn_client.rb +8 -6
- data/examples/client.rb +2 -1
- data/examples/config.ru +6 -9
- data/{spec → examples}/rainbows.conf +0 -0
- data/examples/server.rb +10 -1
- data/lib/faye/adapters/rainbows.rb +15 -16
- data/lib/faye/adapters/rainbows_client.rb +15 -16
- data/lib/faye/adapters/thin.rb +15 -16
- data/lib/faye/eventsource.rb +38 -46
- data/lib/faye/rack_stream.rb +70 -0
- data/lib/faye/websocket.rb +39 -162
- data/lib/faye/websocket/api.rb +70 -60
- data/lib/faye/websocket/api/event.rb +1 -1
- data/lib/faye/websocket/api/event_target.rb +35 -12
- data/lib/faye/websocket/client.rb +5 -38
- metadata +62 -45
- data/CHANGELOG.txt +0 -74
- data/README.rdoc +0 -366
- data/ext/faye_websocket_mask/FayeWebsocketMaskService.java +0 -61
- data/ext/faye_websocket_mask/extconf.rb +0 -5
- data/ext/faye_websocket_mask/faye_websocket_mask.c +0 -33
- data/lib/faye/websocket/draft75_parser.rb +0 -87
- data/lib/faye/websocket/draft76_parser.rb +0 -84
- data/lib/faye/websocket/hybi_parser.rb +0 -321
- data/lib/faye/websocket/hybi_parser/handshake.rb +0 -78
- data/lib/faye/websocket/hybi_parser/stream_reader.rb +0 -29
- data/lib/faye/websocket/utf8_match.rb +0 -8
- data/spec/faye/websocket/client_spec.rb +0 -162
- data/spec/faye/websocket/draft75_parser_examples.rb +0 -48
- data/spec/faye/websocket/draft75_parser_spec.rb +0 -27
- data/spec/faye/websocket/draft76_parser_spec.rb +0 -34
- data/spec/faye/websocket/hybi_parser_spec.rb +0 -149
- data/spec/server.crt +0 -15
- data/spec/server.key +0 -15
- data/spec/spec_helper.rb +0 -68
@@ -1,78 +0,0 @@
|
|
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
|
-
path = (@uri.path == '') ? '/' : @uri.path
|
21
|
-
headers = [
|
22
|
-
"GET #{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
|
@@ -1,29 +0,0 @@
|
|
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
|
@@ -1,8 +0,0 @@
|
|
1
|
-
module Faye
|
2
|
-
class WebSocket
|
3
|
-
|
4
|
-
# http://www.w3.org/International/questions/qa-forms-utf-8.en.php
|
5
|
-
UTF8_MATCH = /^([\x00-\x7F]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})*$/
|
6
|
-
|
7
|
-
end
|
8
|
-
end
|
@@ -1,162 +0,0 @@
|
|
1
|
-
# encoding=utf-8
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
WebSocketSteps = EM::RSpec.async_steps do
|
6
|
-
def server(port, backend, secure, &callback)
|
7
|
-
@server = EchoServer.new
|
8
|
-
@server.listen(port, backend, secure)
|
9
|
-
@port = port
|
10
|
-
EM.add_timer(0.1, &callback)
|
11
|
-
end
|
12
|
-
|
13
|
-
def stop(&callback)
|
14
|
-
@server.stop
|
15
|
-
EM.next_tick(&callback)
|
16
|
-
end
|
17
|
-
|
18
|
-
def open_socket(url, protocols, &callback)
|
19
|
-
done = false
|
20
|
-
|
21
|
-
resume = lambda do |open|
|
22
|
-
unless done
|
23
|
-
done = true
|
24
|
-
@open = open
|
25
|
-
callback.call
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
@ws = Faye::WebSocket::Client.new(url, protocols)
|
30
|
-
|
31
|
-
@ws.onopen = lambda { |e| resume.call(true) }
|
32
|
-
@ws.onclose = lambda { |e| resume.call(false) }
|
33
|
-
end
|
34
|
-
|
35
|
-
def close_socket(&callback)
|
36
|
-
@ws.onclose = lambda do |e|
|
37
|
-
@open = false
|
38
|
-
callback.call
|
39
|
-
end
|
40
|
-
@ws.close
|
41
|
-
end
|
42
|
-
|
43
|
-
def check_open(&callback)
|
44
|
-
@open.should == true
|
45
|
-
callback.call
|
46
|
-
end
|
47
|
-
|
48
|
-
def check_closed(&callback)
|
49
|
-
@open.should == false
|
50
|
-
callback.call
|
51
|
-
end
|
52
|
-
|
53
|
-
def check_protocol(protocol, &callback)
|
54
|
-
@ws.protocol.should == protocol
|
55
|
-
callback.call
|
56
|
-
end
|
57
|
-
|
58
|
-
def listen_for_message(&callback)
|
59
|
-
@ws.add_event_listener('message', lambda { |e| @message = e.data })
|
60
|
-
callback.call
|
61
|
-
end
|
62
|
-
|
63
|
-
def send_message(message, &callback)
|
64
|
-
@ws.send(message)
|
65
|
-
EM.add_timer(0.1, &callback)
|
66
|
-
end
|
67
|
-
|
68
|
-
def check_response(message, &callback)
|
69
|
-
@message.should == message
|
70
|
-
callback.call
|
71
|
-
end
|
72
|
-
|
73
|
-
def check_no_response(&callback)
|
74
|
-
@message.should == nil
|
75
|
-
callback.call
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
describe Faye::WebSocket::Client do
|
80
|
-
next if Faye::WebSocket.jruby?
|
81
|
-
include WebSocketSteps
|
82
|
-
|
83
|
-
let(:protocols) { ["foo", "echo"] }
|
84
|
-
let(:plain_text_url) { "ws://0.0.0.0:8000/" }
|
85
|
-
let(:secure_url) { "wss://0.0.0.0:8000/" }
|
86
|
-
|
87
|
-
shared_examples_for "socket client" do
|
88
|
-
it "can open a connection" do
|
89
|
-
open_socket(socket_url, protocols)
|
90
|
-
check_open
|
91
|
-
check_protocol("echo")
|
92
|
-
end
|
93
|
-
|
94
|
-
it "cannot open a connection to the wrong host" do
|
95
|
-
open_socket(blocked_url, protocols)
|
96
|
-
check_closed
|
97
|
-
end
|
98
|
-
|
99
|
-
it "cannot open a connection with unacceptable protocols" do
|
100
|
-
open_socket(socket_url, ["foo"])
|
101
|
-
check_closed
|
102
|
-
end
|
103
|
-
|
104
|
-
it "can close the connection" do
|
105
|
-
open_socket(socket_url, protocols)
|
106
|
-
close_socket
|
107
|
-
check_closed
|
108
|
-
end
|
109
|
-
|
110
|
-
describe "in the OPEN state" do
|
111
|
-
before { open_socket(socket_url, protocols) }
|
112
|
-
|
113
|
-
it "can send and receive messages" do
|
114
|
-
listen_for_message
|
115
|
-
send_message "I expect this to be echoed"
|
116
|
-
check_response "I expect this to be echoed"
|
117
|
-
end
|
118
|
-
|
119
|
-
it "sends numbers as strings" do
|
120
|
-
listen_for_message
|
121
|
-
send_message 13
|
122
|
-
check_response "13"
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
describe "in the CLOSED state" do
|
127
|
-
before do
|
128
|
-
open_socket(socket_url, protocols)
|
129
|
-
close_socket
|
130
|
-
end
|
131
|
-
|
132
|
-
it "cannot send and receive messages" do
|
133
|
-
listen_for_message
|
134
|
-
send_message "I expect this to be echoed"
|
135
|
-
check_no_response
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
describe "with a plain-text Thin server" do
|
141
|
-
let(:socket_url) { plain_text_url }
|
142
|
-
let(:blocked_url) { secure_url }
|
143
|
-
|
144
|
-
before { server 8000, :thin, false }
|
145
|
-
after { stop }
|
146
|
-
|
147
|
-
it_should_behave_like "socket client"
|
148
|
-
end
|
149
|
-
|
150
|
-
describe "with a secure Thin server" do
|
151
|
-
next if Faye::WebSocket.rbx?
|
152
|
-
|
153
|
-
let(:socket_url) { secure_url }
|
154
|
-
let(:blocked_url) { plain_text_url }
|
155
|
-
|
156
|
-
before { server 8000, :thin, true }
|
157
|
-
after { stop }
|
158
|
-
|
159
|
-
it_should_behave_like "socket client"
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
@@ -1,48 +0,0 @@
|
|
1
|
-
# encoding=utf-8
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
shared_examples_for "draft-75 parser" do
|
6
|
-
it "parses text frames" do
|
7
|
-
@web_socket.should_receive(:receive).with("Hello")
|
8
|
-
parse [0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
|
9
|
-
end
|
10
|
-
|
11
|
-
it "parses multiple frames from the same packet" do
|
12
|
-
@web_socket.should_receive(:receive).with("Hello").exactly(2)
|
13
|
-
parse [0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff, 0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
|
14
|
-
end
|
15
|
-
|
16
|
-
it "parses text frames beginning 0x00-0x7F" do
|
17
|
-
@web_socket.should_receive(:receive).with("Hello")
|
18
|
-
parse [0x66, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
|
19
|
-
end
|
20
|
-
|
21
|
-
it "ignores frames with a length header" do
|
22
|
-
@web_socket.should_not_receive(:receive)
|
23
|
-
parse [0x80, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
|
24
|
-
end
|
25
|
-
|
26
|
-
it "parses text following an ignored block" do
|
27
|
-
@web_socket.should_receive(:receive).with("Hello")
|
28
|
-
parse [0x80, 0x02, 0x48, 0x65, 0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
|
29
|
-
end
|
30
|
-
|
31
|
-
it "parses multibyte text frames" do
|
32
|
-
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
33
|
-
parse [0x00, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf, 0xff]
|
34
|
-
end
|
35
|
-
|
36
|
-
it "parses frames received in several packets" do
|
37
|
-
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
38
|
-
parse [0x00, 0x41, 0x70, 0x70, 0x6c, 0x65]
|
39
|
-
parse [0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf, 0xff]
|
40
|
-
end
|
41
|
-
|
42
|
-
it "parses fragmented frames" do
|
43
|
-
@web_socket.should_receive(:receive).with("Hello")
|
44
|
-
parse [0x00, 0x48, 0x65, 0x6c]
|
45
|
-
parse [0x6c, 0x6f, 0xff]
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# encoding=utf-8
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
describe Faye::WebSocket::Draft75Parser do
|
6
|
-
include EncodingHelper
|
7
|
-
|
8
|
-
before do
|
9
|
-
@web_socket = mock Faye::WebSocket
|
10
|
-
@parser = Faye::WebSocket::Draft75Parser.new(@web_socket)
|
11
|
-
end
|
12
|
-
|
13
|
-
describe :parse do
|
14
|
-
it_should_behave_like "draft-75 parser"
|
15
|
-
end
|
16
|
-
|
17
|
-
describe :frame do
|
18
|
-
it "returns the given string formatted as a WebSocket frame" do
|
19
|
-
bytes(@parser.frame "Hello").should == [0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
|
20
|
-
end
|
21
|
-
|
22
|
-
it "encodes multibyte characters correctly" do
|
23
|
-
message = encode "Apple = "
|
24
|
-
bytes(@parser.frame message).should == [0x00, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf, 0xff]
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,34 +0,0 @@
|
|
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
|
-
|
@@ -1,149 +0,0 @@
|
|
1
|
-
# encoding=utf-8
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
describe Faye::WebSocket::HybiParser do
|
6
|
-
include EncodingHelper
|
7
|
-
|
8
|
-
before do
|
9
|
-
@web_socket = mock Faye::WebSocket
|
10
|
-
@parser = Faye::WebSocket::HybiParser.new(@web_socket)
|
11
|
-
end
|
12
|
-
|
13
|
-
describe :parse do
|
14
|
-
let(:mask) { (1..4).map { rand 255 } }
|
15
|
-
|
16
|
-
def mask_message(*bytes)
|
17
|
-
output = []
|
18
|
-
bytes.each_with_index do |byte, i|
|
19
|
-
output[i] = byte ^ mask[i % 4]
|
20
|
-
end
|
21
|
-
output
|
22
|
-
end
|
23
|
-
|
24
|
-
it "parses unmasked text frames" do
|
25
|
-
@web_socket.should_receive(:receive).with("Hello")
|
26
|
-
parse [0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
|
27
|
-
end
|
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
|
-
|
34
|
-
it "parses empty text frames" do
|
35
|
-
@web_socket.should_receive(:receive).with("")
|
36
|
-
parse [0x81, 0x00]
|
37
|
-
end
|
38
|
-
|
39
|
-
it "parses fragmented text frames" do
|
40
|
-
@web_socket.should_receive(:receive).with("Hello")
|
41
|
-
parse [0x01, 0x03, 0x48, 0x65, 0x6c]
|
42
|
-
parse [0x80, 0x02, 0x6c, 0x6f]
|
43
|
-
end
|
44
|
-
|
45
|
-
it "parses masked text frames" do
|
46
|
-
@web_socket.should_receive(:receive).with("Hello")
|
47
|
-
parse [0x81, 0x85] + mask + mask_message(0x48, 0x65, 0x6c, 0x6c, 0x6f)
|
48
|
-
end
|
49
|
-
|
50
|
-
it "parses masked empty text frames" do
|
51
|
-
@web_socket.should_receive(:receive).with("")
|
52
|
-
parse [0x81, 0x80] + mask + mask_message()
|
53
|
-
end
|
54
|
-
|
55
|
-
it "parses masked fragmented text frames" do
|
56
|
-
@web_socket.should_receive(:receive).with("Hello")
|
57
|
-
parse [0x01, 0x81] + mask + mask_message(0x48)
|
58
|
-
parse [0x80, 0x84] + mask + mask_message(0x65, 0x6c, 0x6c, 0x6f)
|
59
|
-
end
|
60
|
-
|
61
|
-
it "closes the socket if the frame has an unrecognized opcode" do
|
62
|
-
@web_socket.should_receive(:close).with(1002, nil, false)
|
63
|
-
parse [0x83, 0x00]
|
64
|
-
end
|
65
|
-
|
66
|
-
it "closes the socket if a close frame is received" do
|
67
|
-
@web_socket.should_receive(:close).with(1000, "Hello", false)
|
68
|
-
parse [0x88, 0x07, 0x03, 0xe8, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
|
69
|
-
end
|
70
|
-
|
71
|
-
it "parses unmasked multibyte text frames" do
|
72
|
-
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
73
|
-
parse [0x81, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf]
|
74
|
-
end
|
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
|
-
|
82
|
-
it "parses fragmented multibyte text frames" do
|
83
|
-
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
84
|
-
parse [0x01, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3]
|
85
|
-
parse [0x80, 0x01, 0xbf]
|
86
|
-
end
|
87
|
-
|
88
|
-
it "parses masked multibyte text frames" do
|
89
|
-
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
90
|
-
parse [0x81, 0x8b] + mask + mask_message(0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf)
|
91
|
-
end
|
92
|
-
|
93
|
-
it "parses masked fragmented multibyte text frames" do
|
94
|
-
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
95
|
-
parse [0x01, 0x8a] + mask + mask_message(0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3)
|
96
|
-
parse [0x80, 0x81] + mask + mask_message(0xbf)
|
97
|
-
end
|
98
|
-
|
99
|
-
it "parses unmasked medium-length text frames" do
|
100
|
-
@web_socket.should_receive(:receive).with("Hello" * 40)
|
101
|
-
parse [0x81, 0x7e, 0x00, 0xc8] + [0x48, 0x65, 0x6c, 0x6c, 0x6f] * 40
|
102
|
-
end
|
103
|
-
|
104
|
-
it "parses masked medium-length text frames" do
|
105
|
-
@web_socket.should_receive(:receive).with("Hello" * 40)
|
106
|
-
parse [0x81, 0xfe, 0x00, 0xc8] + mask + mask_message(*([0x48, 0x65, 0x6c, 0x6c, 0x6f] * 40))
|
107
|
-
end
|
108
|
-
|
109
|
-
it "replies to pings with a pong" do
|
110
|
-
@web_socket.should_receive(:send).with([0x4f, 0x48, 0x41, 0x49], :pong)
|
111
|
-
parse [0x89, 0x04, 0x4f, 0x48, 0x41, 0x49]
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
describe :frame do
|
116
|
-
it "returns the given string formatted as a WebSocket frame" do
|
117
|
-
bytes(@parser.frame "Hello").should == [0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
|
118
|
-
end
|
119
|
-
|
120
|
-
it "encodes multibyte characters correctly" do
|
121
|
-
message = encode "Apple = "
|
122
|
-
bytes(@parser.frame message).should == [0x81, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf]
|
123
|
-
end
|
124
|
-
|
125
|
-
it "encodes medium-length strings using extra length bytes" do
|
126
|
-
message = "Hello" * 40
|
127
|
-
bytes(@parser.frame message).should == [0x81, 0x7e, 0x00, 0xc8] + [0x48, 0x65, 0x6c, 0x6c, 0x6f] * 40
|
128
|
-
end
|
129
|
-
|
130
|
-
it "encodes close frames with an error code" do
|
131
|
-
frame = @parser.frame "Hello", :close, 1002
|
132
|
-
bytes(frame).should == [0x88, 0x07, 0x03, 0xea, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
|
133
|
-
end
|
134
|
-
|
135
|
-
it "encodes pong frames" do
|
136
|
-
bytes(@parser.frame '', :pong).should == [0x8a, 0x00]
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
describe :utf8 do
|
141
|
-
it "detects valid UTF-8" do
|
142
|
-
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
|
143
|
-
end
|
144
|
-
|
145
|
-
it "detects invalid UTF-8" do
|
146
|
-
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
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|