websocket-rack 0.1.4 → 0.2.1
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/CHANGELOG.md +11 -0
- data/README.md +42 -24
- data/Rakefile +1 -1
- data/example/example.ru +5 -5
- data/lib/rack/websocket/application.rb +31 -60
- data/lib/rack/websocket/extensions/common.rb +61 -0
- data/lib/rack/websocket/extensions/thin/connection.rb +2 -50
- data/lib/rack/websocket/extensions/thin.rb +3 -3
- data/lib/rack/websocket/extensions.rb +14 -0
- data/lib/rack/websocket/handler/base.rb +41 -0
- data/lib/rack/websocket/handler/stub.rb +14 -0
- data/lib/rack/websocket/handler/thin/connection.rb +89 -0
- data/lib/rack/websocket/handler/thin/handler_factory.rb +56 -0
- data/lib/rack/websocket/handler/thin.rb +61 -0
- data/lib/rack/websocket/handler.rb +15 -38
- data/lib/rack/websocket/version.rb +5 -0
- data/lib/rack/websocket.rb +5 -31
- data/spec/spec_helper.rb +18 -0
- data/spec/support/all_drafts.rb +43 -0
- data/spec/support/all_handlers.rb +31 -0
- data/spec/support/requests.rb +100 -0
- data/spec/thin_spec.rb +46 -0
- data/websocket-rack.gemspec +4 -4
- metadata +41 -47
- data/lib/rack/websocket/connection.rb +0 -112
- data/lib/rack/websocket/debugger.rb +0 -17
- data/lib/rack/websocket/framing03.rb +0 -178
- data/lib/rack/websocket/framing76.rb +0 -115
- data/lib/rack/websocket/handler03.rb +0 -14
- data/lib/rack/websocket/handler75.rb +0 -8
- data/lib/rack/websocket/handler76.rb +0 -11
- data/lib/rack/websocket/handler_factory.rb +0 -61
- data/lib/rack/websocket/handshake75.rb +0 -21
- data/lib/rack/websocket/handshake76.rb +0 -71
- data/spec/helper.rb +0 -44
- data/spec/integration/draft03_spec.rb +0 -252
- data/spec/integration/draft76_spec.rb +0 -212
- data/spec/unit/framing_spec.rb +0 -108
- data/spec/unit/handler_spec.rb +0 -136
- data/spec/websocket_spec.rb +0 -210
data/spec/unit/handler_spec.rb
DELETED
@@ -1,136 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe "Rack::WebSocket::Handler" do
|
4
|
-
before :each do
|
5
|
-
@request = {
|
6
|
-
:port => 80,
|
7
|
-
:method => "GET",
|
8
|
-
:path => "/demo",
|
9
|
-
:headers => {
|
10
|
-
'Host' => 'example.com',
|
11
|
-
'Connection' => 'Upgrade',
|
12
|
-
'Sec-WebSocket-Key2' => '12998 5 Y3 1 .P00',
|
13
|
-
'Sec-WebSocket-Protocol' => 'sample',
|
14
|
-
'Upgrade' => 'WebSocket',
|
15
|
-
'Sec-WebSocket-Key1' => '4 @1 46546xW%0l 1 5',
|
16
|
-
'Origin' => 'http://example.com'
|
17
|
-
},
|
18
|
-
:body => '^n:ds[4U'
|
19
|
-
}
|
20
|
-
@secure_request = @request.merge(:port => 443)
|
21
|
-
|
22
|
-
@response = {
|
23
|
-
:headers => {
|
24
|
-
"Upgrade" => "WebSocket",
|
25
|
-
"Connection" => "Upgrade",
|
26
|
-
"Sec-WebSocket-Location" => "ws://example.com/demo",
|
27
|
-
"Sec-WebSocket-Origin" => "http://example.com",
|
28
|
-
"Sec-WebSocket-Protocol" => "sample"
|
29
|
-
},
|
30
|
-
:body => "8jKS\'y:G*Co,Wxa-"
|
31
|
-
}
|
32
|
-
@secure_response = @response.merge(:headers => @response[:headers].merge('Sec-WebSocket-Location' => "wss://example.com:443/demo"))
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should handle good request" do
|
36
|
-
handler(@request).should send_handshake(@response)
|
37
|
-
end
|
38
|
-
|
39
|
-
it "should handle good request to secure default port if secure mode is enabled" do
|
40
|
-
handler(@secure_request, true).should send_handshake(@secure_response)
|
41
|
-
end
|
42
|
-
|
43
|
-
it "should not handle good request to secure default port if secure mode is disabled" do
|
44
|
-
handler(@secure_request, false).should_not send_handshake(@secure_response)
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should handle good request on nondefault port" do
|
48
|
-
@request[:port] = 8081
|
49
|
-
@request[:headers]['Host'] = 'example.com:8081'
|
50
|
-
@response[:headers]['Sec-WebSocket-Location'] =
|
51
|
-
'ws://example.com:8081/demo'
|
52
|
-
|
53
|
-
handler(@request).should send_handshake(@response)
|
54
|
-
end
|
55
|
-
|
56
|
-
it "should handle good request to secure nondefault port" do
|
57
|
-
@secure_request[:port] = 8081
|
58
|
-
@secure_request[:headers]['Host'] = 'example.com:8081'
|
59
|
-
@secure_response[:headers]['Sec-WebSocket-Location'] = 'wss://example.com:8081/demo'
|
60
|
-
handler(@secure_request, true).should send_handshake(@secure_response)
|
61
|
-
end
|
62
|
-
|
63
|
-
it "should handle good request with no protocol" do
|
64
|
-
@request[:headers].delete('Sec-WebSocket-Protocol')
|
65
|
-
@response[:headers].delete("Sec-WebSocket-Protocol")
|
66
|
-
|
67
|
-
handler(@request).should send_handshake(@response)
|
68
|
-
end
|
69
|
-
|
70
|
-
it "should handle extra headers by simply ignoring them" do
|
71
|
-
@request[:headers]['EmptyValue'] = ""
|
72
|
-
@request[:headers]['AKey'] = "AValue"
|
73
|
-
|
74
|
-
handler(@request).should send_handshake(@response)
|
75
|
-
end
|
76
|
-
|
77
|
-
it "should raise error on HTTP request" do
|
78
|
-
@request[:headers] = {
|
79
|
-
'Host' => 'www.google.com',
|
80
|
-
'User-Agent' => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 GTB6 GTBA',
|
81
|
-
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
82
|
-
'Accept-Language' => 'en-us,en;q=0.5',
|
83
|
-
'Accept-Encoding' => 'gzip,deflate',
|
84
|
-
'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
|
85
|
-
'Keep-Alive' => '300',
|
86
|
-
'Connection' => 'keep-alive',
|
87
|
-
}
|
88
|
-
|
89
|
-
lambda {
|
90
|
-
handler(@request).handshake
|
91
|
-
}.should raise_error(Rack::WebSocket::HandshakeError)
|
92
|
-
end
|
93
|
-
|
94
|
-
it "should raise error on wrong method" do
|
95
|
-
@request[:method] = 'POST'
|
96
|
-
|
97
|
-
lambda {
|
98
|
-
handler(@request).handshake
|
99
|
-
}.should raise_error(Rack::WebSocket::HandshakeError)
|
100
|
-
end
|
101
|
-
|
102
|
-
it "should raise error if upgrade header incorrect" do
|
103
|
-
@request[:headers]['Upgrade'] = 'NonWebSocket'
|
104
|
-
|
105
|
-
lambda {
|
106
|
-
handler(@request).handshake
|
107
|
-
}.should raise_error(Rack::WebSocket::HandshakeError)
|
108
|
-
end
|
109
|
-
|
110
|
-
it "should raise error if Sec-WebSocket-Protocol is empty" do
|
111
|
-
@request[:headers]['Sec-WebSocket-Protocol'] = ''
|
112
|
-
|
113
|
-
lambda {
|
114
|
-
handler(@request).handshake
|
115
|
-
}.should raise_error(Rack::WebSocket::HandshakeError)
|
116
|
-
end
|
117
|
-
|
118
|
-
%w[Sec-WebSocket-Key1 Sec-WebSocket-Key2].each do |header|
|
119
|
-
it "should raise error if #{header} has zero spaces" do
|
120
|
-
@request[:headers][header] = 'nospaces'
|
121
|
-
|
122
|
-
lambda {
|
123
|
-
handler(@request).handshake
|
124
|
-
}.should raise_error(Rack::WebSocket::HandshakeError, 'Websocket Key1 or Key2 does not contain spaces - this is a symptom of a cross-protocol attack')
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
it "should raise error if spaces do not divide numbers in Sec-WebSocket-Key* " do
|
129
|
-
@request[:headers]['Sec-WebSocket-Key2'] = '12998 5 Y3 1.P00'
|
130
|
-
|
131
|
-
lambda {
|
132
|
-
handler(@request).handshake
|
133
|
-
}.should raise_error(Rack::WebSocket::HandshakeError, 'Invalid Key "12998 5 Y3 1.P00"')
|
134
|
-
end
|
135
|
-
|
136
|
-
end
|
data/spec/websocket_spec.rb
DELETED
@@ -1,210 +0,0 @@
|
|
1
|
-
# require 'helper'
|
2
|
-
#
|
3
|
-
# describe Rack::WebSocket do
|
4
|
-
#
|
5
|
-
# it "should automatically complete WebSocket handshake" do
|
6
|
-
# EM.run do
|
7
|
-
# MSG = "Hello World!"
|
8
|
-
# EventMachine.add_timer(0.1) do
|
9
|
-
# http = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get :timeout => 0
|
10
|
-
# http.errback { failed }
|
11
|
-
# http.callback { http.response_header.status.should == 101 }
|
12
|
-
#
|
13
|
-
# http.stream { |msg|
|
14
|
-
# msg.should == MSG
|
15
|
-
# EventMachine.stop
|
16
|
-
# }
|
17
|
-
# end
|
18
|
-
#
|
19
|
-
# EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
|
20
|
-
# ws.onopen {
|
21
|
-
# ws.send MSG
|
22
|
-
# }
|
23
|
-
# end
|
24
|
-
# end
|
25
|
-
# end
|
26
|
-
#
|
27
|
-
# it "should fail on non WebSocket requests" do
|
28
|
-
# EM.run do
|
29
|
-
# EventMachine.add_timer(0.1) do
|
30
|
-
# http = EventMachine::HttpRequest.new('http://127.0.0.1:12345/').get :timeout => 0
|
31
|
-
# http.errback { failed }
|
32
|
-
# http.callback {
|
33
|
-
# http.response_header.status.should == 400
|
34
|
-
# EventMachine.stop
|
35
|
-
# }
|
36
|
-
# end
|
37
|
-
#
|
38
|
-
# EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) {}
|
39
|
-
# end
|
40
|
-
# end
|
41
|
-
#
|
42
|
-
# it "should split multiple messages into separate callbacks" do
|
43
|
-
# EM.run do
|
44
|
-
# messages = %w[1 2]
|
45
|
-
# received = []
|
46
|
-
#
|
47
|
-
# EventMachine.add_timer(0.1) do
|
48
|
-
# http = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get :timeout => 0
|
49
|
-
# http.errback { failed }
|
50
|
-
# http.stream {|msg|}
|
51
|
-
# http.callback {
|
52
|
-
# http.response_header.status.should == 101
|
53
|
-
# http.send messages[0]
|
54
|
-
# http.send messages[1]
|
55
|
-
# }
|
56
|
-
# end
|
57
|
-
#
|
58
|
-
# EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
|
59
|
-
# ws.onopen {}
|
60
|
-
# ws.onclose {}
|
61
|
-
# ws.onmessage {|msg|
|
62
|
-
# msg.should == messages[received.size]
|
63
|
-
# received.push msg
|
64
|
-
#
|
65
|
-
# EventMachine.stop if received.size == messages.size
|
66
|
-
# }
|
67
|
-
# end
|
68
|
-
# end
|
69
|
-
# end
|
70
|
-
#
|
71
|
-
# it "should call onclose callback when client closes connection" do
|
72
|
-
# EM.run do
|
73
|
-
# EventMachine.add_timer(0.1) do
|
74
|
-
# http = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get :timeout => 0
|
75
|
-
# http.errback { failed }
|
76
|
-
# http.callback {
|
77
|
-
# http.response_header.status.should == 101
|
78
|
-
# http.close_connection
|
79
|
-
# }
|
80
|
-
# http.stream{|msg|}
|
81
|
-
# end
|
82
|
-
#
|
83
|
-
# EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
|
84
|
-
# ws.onopen {}
|
85
|
-
# ws.onclose {
|
86
|
-
# ws.state.should == :closed
|
87
|
-
# EventMachine.stop
|
88
|
-
# }
|
89
|
-
# end
|
90
|
-
# end
|
91
|
-
# end
|
92
|
-
#
|
93
|
-
# it "should call onerror callback with raised exception and close connection on bad handshake" do
|
94
|
-
# EM.run do
|
95
|
-
# EventMachine.add_timer(0.1) do
|
96
|
-
# http = EventMachine::HttpRequest.new('http://127.0.0.1:12345/').get :timeout => 0
|
97
|
-
# http.errback { http.response_header.status.should == 0 }
|
98
|
-
# http.callback { failed }
|
99
|
-
# end
|
100
|
-
#
|
101
|
-
# EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
|
102
|
-
# ws.onopen { failed }
|
103
|
-
# ws.onclose { EventMachine.stop }
|
104
|
-
# ws.onerror {|e|
|
105
|
-
# e.should be_an_instance_of EventMachine::WebSocket::HandshakeError
|
106
|
-
# e.message.should match('Connection and Upgrade headers required')
|
107
|
-
# EventMachine.stop
|
108
|
-
# }
|
109
|
-
# end
|
110
|
-
# end
|
111
|
-
# end
|
112
|
-
#
|
113
|
-
# it "should populate ws.request with appropriate headers" do
|
114
|
-
# EM.run do
|
115
|
-
# EventMachine.add_timer(0.1) do
|
116
|
-
# http = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get :timeout => 0
|
117
|
-
# http.errback { failed }
|
118
|
-
# http.callback {
|
119
|
-
# http.response_header.status.should == 101
|
120
|
-
# http.close_connection
|
121
|
-
# }
|
122
|
-
# http.stream { |msg| }
|
123
|
-
# end
|
124
|
-
#
|
125
|
-
# EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
|
126
|
-
# ws.onopen {
|
127
|
-
# ws.request["User-Agent"].should == "EventMachine HttpClient"
|
128
|
-
# ws.request["Connection"].should == "Upgrade"
|
129
|
-
# ws.request["Upgrade"].should == "WebSocket"
|
130
|
-
# ws.request["Path"].should == "/"
|
131
|
-
# ws.request["Origin"].should == "127.0.0.1"
|
132
|
-
# ws.request["Host"].to_s.should == "ws://127.0.0.1:12345"
|
133
|
-
# }
|
134
|
-
# ws.onclose {
|
135
|
-
# ws.state.should == :closed
|
136
|
-
# EventMachine.stop
|
137
|
-
# }
|
138
|
-
# end
|
139
|
-
# end
|
140
|
-
# end
|
141
|
-
#
|
142
|
-
# it "should allow sending and retrieving query string args passed in on the connection request." do
|
143
|
-
# EM.run do
|
144
|
-
# EventMachine.add_timer(0.1) do
|
145
|
-
# http = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get(:query => {'foo' => 'bar', 'baz' => 'qux'}, :timeout => 0)
|
146
|
-
# http.errback { failed }
|
147
|
-
# http.callback {
|
148
|
-
# http.response_header.status.should == 101
|
149
|
-
# http.close_connection
|
150
|
-
# }
|
151
|
-
# http.stream { |msg| }
|
152
|
-
# end
|
153
|
-
#
|
154
|
-
# EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
|
155
|
-
# ws.onopen {
|
156
|
-
# path, query = ws.request["Path"].split('?')
|
157
|
-
# path.should == '/'
|
158
|
-
# Hash[*query.split(/&|=/)].should == {"foo"=>"bar", "baz"=>"qux"}
|
159
|
-
# ws.request["Query"]["foo"].should == "bar"
|
160
|
-
# ws.request["Query"]["baz"].should == "qux"
|
161
|
-
# }
|
162
|
-
# ws.onclose {
|
163
|
-
# ws.state.should == :closed
|
164
|
-
# EventMachine.stop
|
165
|
-
# }
|
166
|
-
# end
|
167
|
-
# end
|
168
|
-
# end
|
169
|
-
#
|
170
|
-
# it "should ws.response['Query'] to empty hash when no query string params passed in connection URI" do
|
171
|
-
# EM.run do
|
172
|
-
# EventMachine.add_timer(0.1) do
|
173
|
-
# http = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get(:timeout => 0)
|
174
|
-
# http.errback { failed }
|
175
|
-
# http.callback {
|
176
|
-
# http.response_header.status.should == 101
|
177
|
-
# http.close_connection
|
178
|
-
# }
|
179
|
-
# http.stream { |msg| }
|
180
|
-
# end
|
181
|
-
#
|
182
|
-
# EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
|
183
|
-
# ws.onopen {
|
184
|
-
# ws.request["Path"].should == "/"
|
185
|
-
# ws.request["Query"].should == {}
|
186
|
-
# }
|
187
|
-
# ws.onclose {
|
188
|
-
# ws.state.should == :closed
|
189
|
-
# EventMachine.stop
|
190
|
-
# }
|
191
|
-
# end
|
192
|
-
# end
|
193
|
-
# end
|
194
|
-
#
|
195
|
-
# it "should raise an exception if frame sent before handshake complete" do
|
196
|
-
# EM.run {
|
197
|
-
# EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |c|
|
198
|
-
# # We're not using a real client so the handshake will not be sent
|
199
|
-
# EM.add_timer(0.1) {
|
200
|
-
# lambda {
|
201
|
-
# c.send('early message')
|
202
|
-
# }.should raise_error('Cannot send data before onopen callback')
|
203
|
-
# EM.stop
|
204
|
-
# }
|
205
|
-
# }
|
206
|
-
#
|
207
|
-
# client = EM.connect('0.0.0.0', 12345, EM::Connection)
|
208
|
-
# }
|
209
|
-
# end
|
210
|
-
# end
|