faye-websocket 0.1.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/README.rdoc +132 -0
- data/examples/autobahn_client.rb +45 -0
- data/examples/client.rb +30 -0
- data/examples/index.html +35 -0
- data/examples/server.rb +43 -0
- data/lib/faye/thin_extensions.rb +75 -0
- data/lib/faye/websocket.rb +126 -0
- data/lib/faye/websocket/api.rb +110 -0
- data/lib/faye/websocket/client.rb +82 -0
- data/lib/faye/websocket/draft75_parser.rb +53 -0
- data/lib/faye/websocket/draft76_parser.rb +53 -0
- data/lib/faye/websocket/protocol8_parser.rb +324 -0
- data/spec/faye/websocket/client_spec.rb +146 -0
- data/spec/faye/websocket/draft75_parser_spec.rb +41 -0
- data/spec/faye/websocket/protocol8_parser_spec.rb +145 -0
- data/spec/server.crt +15 -0
- data/spec/server.key +15 -0
- data/spec/spec_helper.rb +50 -0
- metadata +109 -0
@@ -0,0 +1,146 @@
|
|
1
|
+
# encoding=utf-8
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
WebSocketSteps = EM::RSpec.async_steps do
|
6
|
+
def server(port, secure, &callback)
|
7
|
+
@server = EchoServer.new
|
8
|
+
@server.listen(port, 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, &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)
|
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 listen_for_message(&callback)
|
54
|
+
@ws.onmessage = lambda { |e| @message = e.data }
|
55
|
+
callback.call
|
56
|
+
end
|
57
|
+
|
58
|
+
def send_message(&callback)
|
59
|
+
@ws.send("I expect this to be echoed")
|
60
|
+
EM.add_timer(0.1, &callback)
|
61
|
+
end
|
62
|
+
|
63
|
+
def check_response(&callback)
|
64
|
+
@message.should == "I expect this to be echoed"
|
65
|
+
callback.call
|
66
|
+
end
|
67
|
+
|
68
|
+
def check_no_response(&callback)
|
69
|
+
@message.should == nil
|
70
|
+
callback.call
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe Faye::WebSocket::Client do
|
75
|
+
include WebSocketSteps
|
76
|
+
|
77
|
+
let(:plain_text_url) { "ws://0.0.0.0:8000/" }
|
78
|
+
let(:secure_url) { "wss://0.0.0.0:8000/" }
|
79
|
+
|
80
|
+
before do
|
81
|
+
Thread.new { EM.run }
|
82
|
+
sleep(0.1) until EM.reactor_running?
|
83
|
+
end
|
84
|
+
|
85
|
+
shared_examples_for "socket client" do
|
86
|
+
it "can open a connection" do
|
87
|
+
open_socket(socket_url)
|
88
|
+
check_open
|
89
|
+
end
|
90
|
+
|
91
|
+
it "cannot open a connection to the wrong host" do
|
92
|
+
open_socket(blocked_url)
|
93
|
+
check_closed
|
94
|
+
end
|
95
|
+
|
96
|
+
it "can close the connection" do
|
97
|
+
open_socket(socket_url)
|
98
|
+
close_socket
|
99
|
+
check_closed
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "in the OPEN state" do
|
103
|
+
before { open_socket(socket_url) }
|
104
|
+
|
105
|
+
it "can send and receive messages" do
|
106
|
+
listen_for_message
|
107
|
+
send_message
|
108
|
+
check_response
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "in the CLOSED state" do
|
113
|
+
before do
|
114
|
+
open_socket(socket_url)
|
115
|
+
close_socket
|
116
|
+
end
|
117
|
+
|
118
|
+
it "cannot send and receive messages" do
|
119
|
+
listen_for_message
|
120
|
+
send_message
|
121
|
+
check_no_response
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "with a plain-text server" do
|
127
|
+
let(:socket_url) { plain_text_url }
|
128
|
+
let(:blocked_url) { secure_url }
|
129
|
+
|
130
|
+
before { server 8000, false }
|
131
|
+
after { sync ; stop }
|
132
|
+
|
133
|
+
it_should_behave_like "socket client"
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "with a secure server" do
|
137
|
+
let(:socket_url) { secure_url }
|
138
|
+
let(:blocked_url) { plain_text_url }
|
139
|
+
|
140
|
+
before { server 8000, true }
|
141
|
+
after { sync ; stop }
|
142
|
+
|
143
|
+
it_should_behave_like "socket client"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
@@ -0,0 +1,41 @@
|
|
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 "parses text frames" do
|
15
|
+
@web_socket.should_receive(:receive).with("Hello")
|
16
|
+
parse [0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
|
17
|
+
end
|
18
|
+
|
19
|
+
it "parses multibyte text frames" do
|
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
|
29
|
+
end
|
30
|
+
|
31
|
+
describe :frame do
|
32
|
+
it "returns the given string formatted as a WebSocket frame" do
|
33
|
+
bytes(@parser.frame "Hello").should == [0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0xff]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "encodes multibyte characters correctly" do
|
37
|
+
message = encode "Apple = "
|
38
|
+
bytes(@parser.frame message).should == [0x00, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf, 0xff]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# encoding=utf-8
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe Faye::WebSocket::Protocol8Parser do
|
6
|
+
include EncodingHelper
|
7
|
+
|
8
|
+
before do
|
9
|
+
@web_socket = mock Faye::WebSocket
|
10
|
+
@parser = Faye::WebSocket::Protocol8Parser.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 empty text frames" do
|
30
|
+
@web_socket.should_receive(:receive).with("")
|
31
|
+
parse [0x81, 0x00]
|
32
|
+
end
|
33
|
+
|
34
|
+
it "parses fragmented text frames" do
|
35
|
+
@web_socket.should_receive(:receive).with("Hello")
|
36
|
+
parse [0x01, 0x03, 0x48, 0x65, 0x6c]
|
37
|
+
parse [0x80, 0x02, 0x6c, 0x6f]
|
38
|
+
end
|
39
|
+
|
40
|
+
it "parses masked text frames" do
|
41
|
+
@web_socket.should_receive(:receive).with("Hello")
|
42
|
+
parse [0x81, 0x85] + mask + mask_message(0x48, 0x65, 0x6c, 0x6c, 0x6f)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "parses masked empty text frames" do
|
46
|
+
@web_socket.should_receive(:receive).with("")
|
47
|
+
parse [0x81, 0x80] + mask + mask_message()
|
48
|
+
end
|
49
|
+
|
50
|
+
it "parses masked fragmented text frames" do
|
51
|
+
@web_socket.should_receive(:receive).with("Hello")
|
52
|
+
parse [0x01, 0x81] + mask + mask_message(0x48)
|
53
|
+
parse [0x80, 0x84] + mask + mask_message(0x65, 0x6c, 0x6c, 0x6f)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "closes the socket if the frame has an unrecognized opcode" do
|
57
|
+
@web_socket.should_receive(:close).with(1002, nil, false)
|
58
|
+
parse [0x83, 0x00]
|
59
|
+
end
|
60
|
+
|
61
|
+
it "closes the socket if a close frame is received" do
|
62
|
+
@web_socket.should_receive(:close).with(1000, "Hello", false)
|
63
|
+
parse [0x88, 0x07, 0x03, 0xe8, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
|
64
|
+
end
|
65
|
+
|
66
|
+
it "parses unmasked multibyte text frames" do
|
67
|
+
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
68
|
+
parse [0x81, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf]
|
69
|
+
end
|
70
|
+
|
71
|
+
it "parses fragmented multibyte text frames" do
|
72
|
+
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
73
|
+
parse [0x01, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3]
|
74
|
+
parse [0x80, 0x01, 0xbf]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "parses masked multibyte text frames" do
|
78
|
+
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
79
|
+
parse [0x81, 0x8b] + mask + mask_message(0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "parses masked fragmented multibyte text frames" do
|
83
|
+
@web_socket.should_receive(:receive).with(encode "Apple = ")
|
84
|
+
parse [0x01, 0x8a] + mask + mask_message(0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3)
|
85
|
+
parse [0x80, 0x81] + mask + mask_message(0xbf)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "parses unmasked medium-length text frames" do
|
89
|
+
@web_socket.should_receive(:receive).with("Hello" * 40)
|
90
|
+
parse [0x81, 0x7e, 0x00, 0xc8] + [0x48, 0x65, 0x6c, 0x6c, 0x6f] * 40
|
91
|
+
end
|
92
|
+
|
93
|
+
it "parses masked medium-length text frames" do
|
94
|
+
@web_socket.should_receive(:receive).with("Hello" * 40)
|
95
|
+
parse [0x81, 0xfe, 0x00, 0xc8] + mask + mask_message(*([0x48, 0x65, 0x6c, 0x6c, 0x6f] * 40))
|
96
|
+
end
|
97
|
+
|
98
|
+
it "replies to pings with a pong" do
|
99
|
+
@web_socket.should_receive(:send).with([0x4f, 0x48, 0x41, 0x49], :pong)
|
100
|
+
parse [0x89, 0x04, 0x4f, 0x48, 0x41, 0x49]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe :frame do
|
105
|
+
it "returns the given string formatted as a WebSocket frame" do
|
106
|
+
bytes(@parser.frame "Hello").should == [0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
|
107
|
+
end
|
108
|
+
|
109
|
+
it "encodes multibyte characters correctly" do
|
110
|
+
message = encode "Apple = "
|
111
|
+
bytes(@parser.frame message).should == [0x81, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0xef, 0xa3, 0xbf]
|
112
|
+
end
|
113
|
+
|
114
|
+
it "encodes medium-length strings using extra length bytes" do
|
115
|
+
message = "Hello" * 40
|
116
|
+
bytes(@parser.frame message).should == [0x81, 0x7e, 0x00, 0xc8] + [0x48, 0x65, 0x6c, 0x6c, 0x6f] * 40
|
117
|
+
end
|
118
|
+
|
119
|
+
it "encodes long strings using extra length bytes" do
|
120
|
+
message = "Hello" * 13108
|
121
|
+
bytes(@parser.frame message).should == [0x81, 0x7f] +
|
122
|
+
[0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04] +
|
123
|
+
[0x48, 0x65, 0x6c, 0x6c, 0x6f] * 13108
|
124
|
+
end
|
125
|
+
|
126
|
+
it "encodes close frames with an error code" do
|
127
|
+
frame = @parser.frame "Hello", :close, 1002
|
128
|
+
bytes(frame).should == [0x88, 0x07, 0x03, 0xea, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
|
129
|
+
end
|
130
|
+
|
131
|
+
it "encodes pong frames" do
|
132
|
+
bytes(@parser.frame '', :pong).should == [0x8a, 0x00]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe :utf8 do
|
137
|
+
it "detects valid UTF-8" do
|
138
|
+
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
|
+
end
|
140
|
+
|
141
|
+
it "detects invalid UTF-8" do
|
142
|
+
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
|
+
end
|
144
|
+
end
|
145
|
+
end
|
data/spec/server.crt
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIICZTCCAc4CCQDxyrJZrFA0vjANBgkqhkiG9w0BAQUFADB3MQswCQYDVQQGEwJV
|
3
|
+
SzEPMA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDTALBgNVBAoTBEZh
|
4
|
+
eWUxFTATBgNVBAMTDEphbWVzIENvZ2xhbjEgMB4GCSqGSIb3DQEJARYRamNvZ2xh
|
5
|
+
bkBnbWFpbC5jb20wHhcNMTEwODMwMTIzOTM2WhcNMTIwODI5MTIzOTM2WjB3MQsw
|
6
|
+
CQYDVQQGEwJVSzEPMA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDTAL
|
7
|
+
BgNVBAoTBEZheWUxFTATBgNVBAMTDEphbWVzIENvZ2xhbjEgMB4GCSqGSIb3DQEJ
|
8
|
+
ARYRamNvZ2xhbkBnbWFpbC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB
|
9
|
+
AMDjU5fAK7fvUCZIYHcGXDZD/m9bY+B/UcwGcowk0hMQGYNlLKrpiK7xXBmZpDb6
|
10
|
+
r8n+7L/epBeSumbRIm4TDzeNHhuQGYLIeGQy7JNLoPBr6GxubjuJhKOOBnCqcupR
|
11
|
+
CLGG7Zw5oL4UvtZVH6kL9XnjyokQQbxxeoV9DqtqOaHHAgMBAAEwDQYJKoZIhvcN
|
12
|
+
AQEFBQADgYEAvQjSpzE1ahaeH1CmbLwckTxvWMZfxcZOrxTruK1po3cNnDOjGqFQ
|
13
|
+
KEkNj3K5WfwTBD4QgUdYDykhDX2m6HaMz4JEbgrwQv8M8FiswIA3dyGsbOifOk8H
|
14
|
+
r3GPNKMzm4o6vrn6RGOpt9q6bsWUBUHfNpP93uU2C9QEwDua3cFjDA0=
|
15
|
+
-----END CERTIFICATE-----
|
data/spec/server.key
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIICXAIBAAKBgQDA41OXwCu371AmSGB3Blw2Q/5vW2Pgf1HMBnKMJNITEBmDZSyq
|
3
|
+
6Yiu8VwZmaQ2+q/J/uy/3qQXkrpm0SJuEw83jR4bkBmCyHhkMuyTS6Dwa+hsbm47
|
4
|
+
iYSjjgZwqnLqUQixhu2cOaC+FL7WVR+pC/V548qJEEG8cXqFfQ6rajmhxwIDAQAB
|
5
|
+
AoGABlk1DiCQD8y7mZb2PdSiwlJ4lFewsNnf6lQn/v7TPzdfb5ir4LAxBHkDLACH
|
6
|
+
jBuyH3bZefMs+W2l3u5xMKhF7uJqYcUlJdH2UwRfNG54Hn4SGAjQOK3ONer99sUf
|
7
|
+
USlsWSX1HjAAFMCBwUfKxMZA3VNQfYKTPdm0jSVf85kHO1ECQQD3s6ksm3QpfD0L
|
8
|
+
eG9EoDrqmwnEfpKoWPpz1O0i5tY9VcmhmLwS5Zpd7lB1qjTqzZk4RygU73T/BseJ
|
9
|
+
azehIHK5AkEAx1mSXt+ec8RfzVi/io6oqi2vOcACXRbOG4NQmqUWPnumdwsJjsjR
|
10
|
+
RzEoDFC2lu6448p9sgEq+CkbmgVeiyp4fwJAQnmgySve/NMuvslPcyddKGD7OhSN
|
11
|
+
30ghzrwx98/jZwqC1i9bKeccimDOjwVitjD/Ea9m/ldVGqwDGMoBX+iJYQJAEIOO
|
12
|
+
CYfyw1pQKV2huGOq+zX/nwQV7go2lrbhFX55gkGR/6iNaSOfmosq6yJAje5GqLAc
|
13
|
+
i4NnQNl+7NpnA5ZIFwJBAI1+OsZyjbRI99pYkTdOpa5IPlIb3j3JbSfjAWHLxlRY
|
14
|
+
0HLvN3Q1mE9kbB+uKH6syF/S7nALgsLgq7eHYvIaE/A=
|
15
|
+
-----END RSA PRIVATE KEY-----
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require File.expand_path('../../lib/faye/websocket', __FILE__)
|
4
|
+
require File.expand_path('../../vendor/em-rspec/lib/em-rspec', __FILE__)
|
5
|
+
|
6
|
+
Thin::Logging.silent = true
|
7
|
+
|
8
|
+
module EncodingHelper
|
9
|
+
def encode(message)
|
10
|
+
message.respond_to?(:force_encoding) ?
|
11
|
+
message.force_encoding("UTF-8") :
|
12
|
+
message
|
13
|
+
end
|
14
|
+
|
15
|
+
def bytes(string)
|
16
|
+
string.bytes.to_a
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse(bytes)
|
20
|
+
@parser.parse(bytes.pack('C*'))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class EchoServer
|
25
|
+
def call(env)
|
26
|
+
socket = Faye::WebSocket.new(env)
|
27
|
+
socket.onmessage = lambda do |event|
|
28
|
+
socket.send(event.data)
|
29
|
+
end
|
30
|
+
[-1, {}, []]
|
31
|
+
end
|
32
|
+
|
33
|
+
def listen(port, ssl = false)
|
34
|
+
Rack::Handler.get('thin').run(self, :Port => port) do |s|
|
35
|
+
if ssl
|
36
|
+
s.ssl = true
|
37
|
+
s.ssl_options = {
|
38
|
+
:private_key_file => File.expand_path('../server.key', __FILE__),
|
39
|
+
:cert_chain_file => File.expand_path('../server.crt', __FILE__)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
@server = s
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def stop
|
47
|
+
@server.stop
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: faye-websocket
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- James Coglan
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: eventmachine
|
16
|
+
requirement: &2152439260 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.12.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2152439260
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: thin
|
27
|
+
requirement: &2152438100 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '1.2'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2152438100
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
requirement: &2152437380 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.5.0
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2152437380
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rack
|
49
|
+
requirement: &2152436360 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2152436360
|
58
|
+
description:
|
59
|
+
email: jcoglan@gmail.com
|
60
|
+
executables: []
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files:
|
63
|
+
- README.rdoc
|
64
|
+
files:
|
65
|
+
- README.rdoc
|
66
|
+
- examples/autobahn_client.rb
|
67
|
+
- examples/client.rb
|
68
|
+
- examples/index.html
|
69
|
+
- examples/server.rb
|
70
|
+
- lib/faye/thin_extensions.rb
|
71
|
+
- lib/faye/websocket/api.rb
|
72
|
+
- lib/faye/websocket/client.rb
|
73
|
+
- lib/faye/websocket/draft75_parser.rb
|
74
|
+
- lib/faye/websocket/draft76_parser.rb
|
75
|
+
- lib/faye/websocket/protocol8_parser.rb
|
76
|
+
- lib/faye/websocket.rb
|
77
|
+
- spec/faye/websocket/client_spec.rb
|
78
|
+
- spec/faye/websocket/draft75_parser_spec.rb
|
79
|
+
- spec/faye/websocket/protocol8_parser_spec.rb
|
80
|
+
- spec/server.crt
|
81
|
+
- spec/server.key
|
82
|
+
- spec/spec_helper.rb
|
83
|
+
homepage: http://github.com/jcoglan/faye-websocket-ruby
|
84
|
+
licenses: []
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options:
|
87
|
+
- --main
|
88
|
+
- README.rdoc
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
requirements: []
|
104
|
+
rubyforge_project:
|
105
|
+
rubygems_version: 1.8.10
|
106
|
+
signing_key:
|
107
|
+
specification_version: 3
|
108
|
+
summary: Robust general-purpose WebSocket server and client
|
109
|
+
test_files: []
|