websocket-rack 0.1.4 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/CHANGELOG.md +11 -0
  2. data/README.md +42 -24
  3. data/Rakefile +1 -1
  4. data/example/example.ru +5 -5
  5. data/lib/rack/websocket/application.rb +31 -60
  6. data/lib/rack/websocket/extensions/common.rb +61 -0
  7. data/lib/rack/websocket/extensions/thin/connection.rb +2 -50
  8. data/lib/rack/websocket/extensions/thin.rb +3 -3
  9. data/lib/rack/websocket/extensions.rb +14 -0
  10. data/lib/rack/websocket/handler/base.rb +41 -0
  11. data/lib/rack/websocket/handler/stub.rb +14 -0
  12. data/lib/rack/websocket/handler/thin/connection.rb +89 -0
  13. data/lib/rack/websocket/handler/thin/handler_factory.rb +56 -0
  14. data/lib/rack/websocket/handler/thin.rb +61 -0
  15. data/lib/rack/websocket/handler.rb +15 -38
  16. data/lib/rack/websocket/version.rb +5 -0
  17. data/lib/rack/websocket.rb +5 -31
  18. data/spec/spec_helper.rb +18 -0
  19. data/spec/support/all_drafts.rb +43 -0
  20. data/spec/support/all_handlers.rb +31 -0
  21. data/spec/support/requests.rb +100 -0
  22. data/spec/thin_spec.rb +46 -0
  23. data/websocket-rack.gemspec +4 -4
  24. metadata +41 -47
  25. data/lib/rack/websocket/connection.rb +0 -112
  26. data/lib/rack/websocket/debugger.rb +0 -17
  27. data/lib/rack/websocket/framing03.rb +0 -178
  28. data/lib/rack/websocket/framing76.rb +0 -115
  29. data/lib/rack/websocket/handler03.rb +0 -14
  30. data/lib/rack/websocket/handler75.rb +0 -8
  31. data/lib/rack/websocket/handler76.rb +0 -11
  32. data/lib/rack/websocket/handler_factory.rb +0 -61
  33. data/lib/rack/websocket/handshake75.rb +0 -21
  34. data/lib/rack/websocket/handshake76.rb +0 -71
  35. data/spec/helper.rb +0 -44
  36. data/spec/integration/draft03_spec.rb +0 -252
  37. data/spec/integration/draft76_spec.rb +0 -212
  38. data/spec/unit/framing_spec.rb +0 -108
  39. data/spec/unit/handler_spec.rb +0 -136
  40. data/spec/websocket_spec.rb +0 -210
@@ -0,0 +1,61 @@
1
+ require 'thin'
2
+
3
+ module Rack
4
+ module WebSocket
5
+ module Handler
6
+ class Thin < Base
7
+
8
+ autoload :Connection, "#{ROOT_PATH}/websocket/handler/thin/connection"
9
+ autoload :HandlerFactory, "#{ROOT_PATH}/websocket/handler/thin/handler_factory"
10
+
11
+ def call(env)
12
+ @env = env
13
+ socket = env['async.connection']
14
+ request = request_from_env(env)
15
+ @conn = Connection.new(self, socket, :debug => @options[:debug])
16
+ @conn.dispatch(request) ? async_response : failure_response
17
+ end
18
+
19
+ def send_data(data)
20
+ if @conn
21
+ @conn.send data
22
+ else
23
+ raise WebSocketError, "WebSocket not opened"
24
+ end
25
+ end
26
+
27
+ def close_websocket
28
+ if @conn
29
+ @conn.close_websocket
30
+ else
31
+ raise WebSocketError, "WebSocket not opened"
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def request_from_env(env)
38
+ request = {}
39
+ request['Path'] = env['REQUEST_PATH'].to_s
40
+ request['Method'] = env['REQUEST_METHOD']
41
+ request['Query'] = env['QUERY_STRING'].to_s
42
+ request['body'] = env['rack.input'].read
43
+
44
+ request['Sec-WebSocket-Draft'] = env['HTTP_SEC_WEBSOCKET_DRAFT']
45
+ request['Sec-WebSocket-Key1'] = env['HTTP_SEC_WEBSOCKET_KEY1']
46
+ request['Sec-WebSocket-Key2'] = env['HTTP_SEC_WEBSOCKET_KEY2']
47
+ request['Sec-WebSocket-Protocol'] = env['HTTP_SEC_WEBSOCKET_PROTOCOL']
48
+
49
+ env.each do |key, value|
50
+ if key.match(/HTTP_(.+)/)
51
+ request[$1.capitalize.gsub('_','-')] ||= value
52
+ end
53
+ end
54
+
55
+ request
56
+ end
57
+
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,43 +1,20 @@
1
1
  module Rack
2
2
  module WebSocket
3
- class Handler
4
- include Debugger
5
-
6
- attr_reader :request, :state
7
-
8
- def initialize(connection, request, debug = false)
9
- @connection, @request = connection, request
10
- @debug = debug
11
- @state = :handshake
12
- initialize_framing
13
- end
14
-
15
- def run
16
- @connection.send_data handshake
17
- @state = :connected
18
- @connection.trigger_on_open
19
- end
20
-
21
- # Handshake response
22
- def handshake
23
- # Implemented in subclass
24
- end
25
-
26
- def receive_data(data)
27
- @data << data
28
- process_data(data)
29
- end
30
-
31
- def close_websocket
32
- # Unless redefined in a subclass, just close the connection
33
- @state = :closed
34
- @connection.close_connection_after_writing
35
- end
36
-
37
- def unbind
38
- @state = :closed
39
- @connection.trigger_on_close
3
+ module Handler
4
+
5
+ autoload :Base, "#{ROOT_PATH}/websocket/handler/base"
6
+ autoload :Stub, "#{ROOT_PATH}/websocket/handler/stub"
7
+ autoload :Thin, "#{ROOT_PATH}/websocket/handler/thin"
8
+
9
+ def self.detect(env)
10
+ server_software = env['SERVER_SOFTWARE']
11
+ if server_software.match(/\Athin /i)
12
+ Thin
13
+ else
14
+ Stub
15
+ end
40
16
  end
17
+
41
18
  end
42
19
  end
43
- end
20
+ end
@@ -0,0 +1,5 @@
1
+ module Rack
2
+ module WebSocket
3
+ VERSION = "0.2.1"
4
+ end
5
+ end
@@ -1,40 +1,14 @@
1
1
  require 'rack'
2
+ require 'em-websocket'
2
3
 
3
4
  module Rack
4
5
  module WebSocket
5
- VERSION = "0.1.4"
6
6
  ROOT_PATH = ::File.expand_path(::File.dirname(__FILE__))
7
7
 
8
- class WebSocketError < RuntimeError; end
9
- class HandshakeError < WebSocketError; end
10
- class DataError < WebSocketError; end
11
-
12
- autoload :Application, "#{ROOT_PATH}/websocket/application"
13
- autoload :Connection, "#{ROOT_PATH}/websocket/connection"
14
- autoload :Debugger, "#{ROOT_PATH}/websocket/debugger"
15
- autoload :Framing03, "#{ROOT_PATH}/websocket/framing03"
16
- autoload :Framing76, "#{ROOT_PATH}/websocket/framing76"
17
- autoload :Handler, "#{ROOT_PATH}/websocket/handler"
18
- autoload :Handler03, "#{ROOT_PATH}/websocket/handler03"
19
- autoload :Handler75, "#{ROOT_PATH}/websocket/handler75"
20
- autoload :Handler76, "#{ROOT_PATH}/websocket/handler76"
21
- autoload :HandlerFactory, "#{ROOT_PATH}/websocket/handler_factory"
22
- autoload :Handshake75, "#{ROOT_PATH}/websocket/handshake75"
23
- autoload :Handshake76, "#{ROOT_PATH}/websocket/handshake76"
24
-
25
- module Extensions
26
- autoload :Thin, "#{ROOT_PATH}/websocket/extensions/thin"
27
- end
28
-
8
+ autoload :Application, "#{ROOT_PATH}/websocket/application"
9
+ autoload :Extensions, "#{ROOT_PATH}/websocket/extensions"
10
+ autoload :Handler, "#{ROOT_PATH}/websocket/handler"
29
11
  end
30
12
  end
31
13
 
32
- ::Thin.send(:include, ::Rack::WebSocket::Extensions::Thin) if defined?(Thin)
33
-
34
- unless ''.respond_to?(:getbyte)
35
- class String
36
- def getbyte(i)
37
- self[i]
38
- end
39
- end
40
- end
14
+ Rack::WebSocket::Extensions.apply!
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+
4
+ require 'rack/websocket'
5
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
6
+
7
+ RSpec.configure do |config|
8
+ config.mock_with :mocha
9
+ end
10
+
11
+ class TestApp < Rack::WebSocket::Application
12
+ end
13
+
14
+ TEST_PORT = 8081
15
+
16
+ def new_server_connection
17
+ TCPSocket.new('localhost', TEST_PORT)
18
+ end
@@ -0,0 +1,43 @@
1
+ shared_examples_for 'all drafts' do
2
+ it "should accept incoming connection" do
3
+ conn = new_server_connection
4
+ conn.write(handshake_request)
5
+ conn.read(handshake_response.length).should eql(handshake_response)
6
+ end
7
+ it "should call 'on_open' on new connection" do
8
+ TestApp.any_instance.expects(:on_open)
9
+ conn = new_server_connection
10
+ conn.write(handshake_request)
11
+ end
12
+ it "should call 'on_open' on new connection with proper env" do
13
+ TestApp.any_instance.expects(:on_open).once.with { |env| env.class == Hash && !env.keys.empty? }
14
+ conn = new_server_connection
15
+ conn.write(handshake_request)
16
+ end
17
+ it "should call 'on_close' on connection close" do
18
+ TestApp.any_instance.expects(:on_close)
19
+ conn = new_server_connection
20
+ conn.write(handshake_request)
21
+ conn.close
22
+ end
23
+ it "should call 'on_close' on connection close with proper env" do
24
+ TestApp.any_instance.expects(:on_close).once.with { |env| env.class == Hash && !env.keys.empty? }
25
+ conn = new_server_connection
26
+ conn.write(handshake_request)
27
+ conn.close
28
+ end
29
+ it "should call 'on_message' on connection sending data" do
30
+ TestApp.any_instance.expects(:on_message)
31
+ conn = new_server_connection
32
+ conn.write(handshake_request)
33
+ conn.read(handshake_response.length)
34
+ conn.write(message)
35
+ end
36
+ it "should call 'on_message' on connection sending data with proper env and message" do
37
+ TestApp.any_instance.expects(:on_message).once.with { |env, message| env.class == Hash && !env.keys.empty? && message == 'some message' }
38
+ conn = new_server_connection
39
+ conn.write(handshake_request)
40
+ conn.read(handshake_response.length)
41
+ conn.write(message)
42
+ end
43
+ end
@@ -0,0 +1,31 @@
1
+ shared_examples_for 'all handlers' do
2
+ it "should return flash policy file" do
3
+ conn = new_server_connection
4
+ conn.write(flash_policy_request)
5
+ conn.read(flash_policy_response.length).should eql(flash_policy_response)
6
+ end
7
+
8
+ context 'for draft75' do
9
+ let(:handshake_request) { spec75_handshake_request }
10
+ let(:handshake_response) { spec75_handshake_response }
11
+ let(:message) { spec75_message }
12
+
13
+ it_should_behave_like 'all drafts'
14
+ end
15
+
16
+ context 'for draft76' do
17
+ let(:handshake_request) { spec76_handshake_request }
18
+ let(:handshake_response) { spec76_handshake_response }
19
+ let(:message) { spec76_message }
20
+
21
+ it_should_behave_like 'all drafts'
22
+ end
23
+
24
+ context 'for draft03' do
25
+ let(:handshake_request) { spec03_handshake_request }
26
+ let(:handshake_response) { spec03_handshake_response }
27
+ let(:message) { spec03_message }
28
+
29
+ it_should_behave_like 'all drafts'
30
+ end
31
+ end
@@ -0,0 +1,100 @@
1
+ def flash_policy_request
2
+ "<policy-file-request/>\000"
3
+ end
4
+
5
+ def flash_policy_response
6
+ '<?xml version="1.0"?><cross-domain-policy><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>'
7
+ end
8
+
9
+ def spec75_handshake_request
10
+ <<-EOF
11
+ GET / HTTP/1.1\r
12
+ Upgrade: WebSocket\r
13
+ Connection: Upgrade\r
14
+ Host: localhost:#{TEST_PORT}\r
15
+ Origin: http://localhost:#{TEST_PORT}\r
16
+ \r
17
+ EOF
18
+ end
19
+
20
+ def spec75_handshake_response
21
+ <<-EOF
22
+ HTTP/1.1 101 Web Socket Protocol Handshake\r
23
+ Upgrade: WebSocket\r
24
+ Connection: Upgrade\r
25
+ WebSocket-Origin: http://localhost:#{TEST_PORT}\r
26
+ WebSocket-Location: ws://localhost:#{TEST_PORT}/\r
27
+ \r
28
+ EOF
29
+ end
30
+
31
+ def spec75_message
32
+ "\x00some message\xff"
33
+ end
34
+
35
+ def spec76_handshake_request
36
+ request = <<-EOF
37
+ GET / HTTP/1.1\r
38
+ Upgrade: WebSocket\r
39
+ Connection: Upgrade\r
40
+ Host: localhost:#{TEST_PORT}\r
41
+ Origin: http://localhost:#{TEST_PORT}\r
42
+ Sec-WebSocket-Key1: 18x 6]8vM;54 *(5: { U1]8 z [ 8\r
43
+ Sec-WebSocket-Key2: 1_ tx7X d < nw 334J702) 7]o}` 0\r
44
+ \r
45
+ Tm[K T2u
46
+ EOF
47
+ request.rstrip
48
+ end
49
+
50
+ def spec76_handshake_response
51
+ response = <<-EOF
52
+ HTTP/1.1 101 WebSocket Protocol Handshake\r
53
+ Upgrade: WebSocket\r
54
+ Connection: Upgrade\r
55
+ Sec-WebSocket-Location: ws://localhost:#{TEST_PORT}/\r
56
+ Sec-WebSocket-Origin: http://localhost:#{TEST_PORT}\r
57
+ \r
58
+ fQJ,fN/4F4!~K~MH
59
+ EOF
60
+ response.rstrip
61
+ end
62
+
63
+ def spec76_message
64
+ "\x00some message\xff"
65
+ end
66
+
67
+ def spec03_handshake_request
68
+ request = <<-EOF
69
+ GET / HTTP/1.1\r
70
+ Upgrade: WebSocket\r
71
+ Connection: Upgrade\r
72
+ Host: localhost:#{TEST_PORT}\r
73
+ Origin: http://localhost:#{TEST_PORT}\r
74
+ Sec-WebSocket-Key1: 18x 6]8vM;54 *(5: { U1]8 z [ 8\r
75
+ Sec-WebSocket-Key2: 1_ tx7X d < nw 334J702) 7]o}` 0\r
76
+ Sec-WebSocket-Protocol: sample\r
77
+ Sec-WebSocket-Draft: 3\r
78
+ \r
79
+ Tm[K T2u
80
+ EOF
81
+ request.rstrip
82
+ end
83
+
84
+ def spec03_handshake_response
85
+ response = <<-EOF
86
+ HTTP/1.1 101 WebSocket Protocol Handshake\r
87
+ Upgrade: WebSocket\r
88
+ Connection: Upgrade\r
89
+ Sec-WebSocket-Location: ws://localhost:#{TEST_PORT}/\r
90
+ Sec-WebSocket-Origin: http://localhost:#{TEST_PORT}\r
91
+ Sec-WebSocket-Protocol: sample\r
92
+ \r
93
+ fQJ,fN/4F4!~K~MH
94
+ EOF
95
+ response.rstrip
96
+ end
97
+
98
+ def spec03_message
99
+ "\x04\x0Csome message"
100
+ end
data/spec/thin_spec.rb ADDED
@@ -0,0 +1,46 @@
1
+ require 'thin'
2
+ require 'spec_helper'
3
+
4
+ describe 'Thin handler' do
5
+ let(:app) { TestApp.new }
6
+
7
+ before(:all) { silent_thin }
8
+ before { start_thin_server(app) }
9
+ after { stop_thin_server }
10
+
11
+ it "should include extensions" do
12
+ ::Thin::Connection.include?(::Rack::WebSocket::Extensions::Common).should be_true
13
+ ::Thin::Connection.include?(::Rack::WebSocket::Extensions::Thin::Connection).should be_true
14
+ end
15
+
16
+ it_should_behave_like 'all handlers'
17
+ end
18
+
19
+ def start_thin_server(app, options = {})
20
+ @server = Thin::Server.new('0.0.0.0', TEST_PORT, options, app)
21
+ @server.ssl = options[:ssl]
22
+ # @server.threaded = options[:threaded]
23
+ # @server.timeout = 3
24
+
25
+ @thread = Thread.new { @server.start }
26
+ sleep 1 until @server.running?
27
+ end
28
+
29
+ def stop_thin_server
30
+ sleep 0.1
31
+ @server.stop!
32
+ @thread.kill
33
+ raise "Reactor still running, wtf?" if EventMachine.reactor_running?
34
+ end
35
+
36
+ def silent_thin
37
+ ::Thin::Logging.silent = true
38
+ if EM::VERSION < "1.0.0"
39
+ begin
40
+ old_verbose, $VERBOSE = $VERBOSE, nil
41
+ ::Thin::Server.const_set 'DEFAULT_TIMEOUT', 0
42
+ ensure
43
+ $VERBOSE = old_verbose
44
+ end
45
+ end
46
+ end
@@ -1,6 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  $:.push File.expand_path("../lib", __FILE__)
3
- require "rack/websocket"
3
+ require "rack/websocket/version"
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "websocket-rack"
@@ -13,10 +13,10 @@ Gem::Specification.new do |s|
13
13
  s.description = %q{Rack-based WebSocket server}
14
14
 
15
15
  s.add_dependency 'rack'
16
- s.add_dependency 'addressable', '>= 2.1.1'
17
- s.add_dependency 'eventmachine', '>= 0.12.9'
18
- s.add_dependency 'thin'
16
+ s.add_dependency 'em-websocket', '~> 0.2.1'
17
+ s.add_dependency 'thin' # Temporary until we support more servers
19
18
  s.add_development_dependency 'rspec', '~> 2.4.0'
19
+ s.add_development_dependency 'mocha'
20
20
 
21
21
  s.files = `git ls-files`.split("\n")
22
22
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: websocket-rack
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
+ - 2
8
9
  - 1
9
- - 4
10
- version: 0.1.4
10
+ version: 0.2.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Bernard Potocki
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-03-13 00:00:00 +01:00
18
+ date: 2011-04-01 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -33,65 +33,63 @@ dependencies:
33
33
  type: :runtime
34
34
  version_requirements: *id001
35
35
  - !ruby/object:Gem::Dependency
36
- name: addressable
36
+ name: em-websocket
37
37
  prerelease: false
38
38
  requirement: &id002 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
- - - ">="
41
+ - - ~>
42
42
  - !ruby/object:Gem::Version
43
- hash: 9
43
+ hash: 21
44
44
  segments:
45
+ - 0
45
46
  - 2
46
47
  - 1
47
- - 1
48
- version: 2.1.1
48
+ version: 0.2.1
49
49
  type: :runtime
50
50
  version_requirements: *id002
51
51
  - !ruby/object:Gem::Dependency
52
- name: eventmachine
52
+ name: thin
53
53
  prerelease: false
54
54
  requirement: &id003 !ruby/object:Gem::Requirement
55
55
  none: false
56
56
  requirements:
57
57
  - - ">="
58
58
  - !ruby/object:Gem::Version
59
- hash: 61
59
+ hash: 3
60
60
  segments:
61
61
  - 0
62
- - 12
63
- - 9
64
- version: 0.12.9
62
+ version: "0"
65
63
  type: :runtime
66
64
  version_requirements: *id003
67
65
  - !ruby/object:Gem::Dependency
68
- name: thin
66
+ name: rspec
69
67
  prerelease: false
70
68
  requirement: &id004 !ruby/object:Gem::Requirement
71
69
  none: false
72
70
  requirements:
73
- - - ">="
71
+ - - ~>
74
72
  - !ruby/object:Gem::Version
75
- hash: 3
73
+ hash: 31
76
74
  segments:
75
+ - 2
76
+ - 4
77
77
  - 0
78
- version: "0"
79
- type: :runtime
78
+ version: 2.4.0
79
+ type: :development
80
80
  version_requirements: *id004
81
81
  - !ruby/object:Gem::Dependency
82
- name: rspec
82
+ name: mocha
83
83
  prerelease: false
84
84
  requirement: &id005 !ruby/object:Gem::Requirement
85
85
  none: false
86
86
  requirements:
87
- - - ~>
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- hash: 31
89
+ hash: 3
90
90
  segments:
91
- - 2
92
- - 4
93
91
  - 0
94
- version: 2.4.0
92
+ version: "0"
95
93
  type: :development
96
94
  version_requirements: *id005
97
95
  description: Rack-based WebSocket server
@@ -118,25 +116,22 @@ files:
118
116
  - example/html/web_socket.js
119
117
  - lib/rack/websocket.rb
120
118
  - lib/rack/websocket/application.rb
121
- - lib/rack/websocket/connection.rb
122
- - lib/rack/websocket/debugger.rb
119
+ - lib/rack/websocket/extensions.rb
120
+ - lib/rack/websocket/extensions/common.rb
123
121
  - lib/rack/websocket/extensions/thin.rb
124
122
  - lib/rack/websocket/extensions/thin/connection.rb
125
- - lib/rack/websocket/framing03.rb
126
- - lib/rack/websocket/framing76.rb
127
123
  - lib/rack/websocket/handler.rb
128
- - lib/rack/websocket/handler03.rb
129
- - lib/rack/websocket/handler75.rb
130
- - lib/rack/websocket/handler76.rb
131
- - lib/rack/websocket/handler_factory.rb
132
- - lib/rack/websocket/handshake75.rb
133
- - lib/rack/websocket/handshake76.rb
134
- - spec/helper.rb
135
- - spec/integration/draft03_spec.rb
136
- - spec/integration/draft76_spec.rb
137
- - spec/unit/framing_spec.rb
138
- - spec/unit/handler_spec.rb
139
- - spec/websocket_spec.rb
124
+ - lib/rack/websocket/handler/base.rb
125
+ - lib/rack/websocket/handler/stub.rb
126
+ - lib/rack/websocket/handler/thin.rb
127
+ - lib/rack/websocket/handler/thin/connection.rb
128
+ - lib/rack/websocket/handler/thin/handler_factory.rb
129
+ - lib/rack/websocket/version.rb
130
+ - spec/spec_helper.rb
131
+ - spec/support/all_drafts.rb
132
+ - spec/support/all_handlers.rb
133
+ - spec/support/requests.rb
134
+ - spec/thin_spec.rb
140
135
  - websocket-rack.gemspec
141
136
  has_rdoc: true
142
137
  homepage: http://github.com/imanel/websocket-rack
@@ -173,9 +168,8 @@ signing_key:
173
168
  specification_version: 3
174
169
  summary: Rack-based WebSocket server
175
170
  test_files:
176
- - spec/helper.rb
177
- - spec/integration/draft03_spec.rb
178
- - spec/integration/draft76_spec.rb
179
- - spec/unit/framing_spec.rb
180
- - spec/unit/handler_spec.rb
181
- - spec/websocket_spec.rb
171
+ - spec/spec_helper.rb
172
+ - spec/support/all_drafts.rb
173
+ - spec/support/all_handlers.rb
174
+ - spec/support/requests.rb
175
+ - spec/thin_spec.rb