thin 1.3.1 → 1.4.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.
Files changed (101) hide show
  1. data/CHANGELOG +8 -0
  2. data/README.md +83 -0
  3. data/Rakefile +9 -32
  4. data/example/vlad.rake +1 -1
  5. data/lib/rack/adapter/loader.rb +0 -16
  6. data/lib/thin.rb +22 -24
  7. data/lib/thin/backends/base.rb +3 -1
  8. data/lib/thin/connection.rb +9 -8
  9. data/lib/thin/daemonizing.rb +3 -1
  10. data/lib/thin/logging.rb +1 -1
  11. data/lib/thin/runner.rb +36 -36
  12. data/lib/thin/server.rb +13 -0
  13. data/lib/thin/version.rb +3 -3
  14. metadata +5 -91
  15. data/README +0 -69
  16. data/benchmark/abc +0 -51
  17. data/benchmark/benchmarker.rb +0 -80
  18. data/benchmark/runner +0 -82
  19. data/spec/backends/swiftiply_client_spec.rb +0 -66
  20. data/spec/backends/tcp_server_spec.rb +0 -33
  21. data/spec/backends/unix_server_spec.rb +0 -37
  22. data/spec/command_spec.rb +0 -25
  23. data/spec/configs/cluster.yml +0 -9
  24. data/spec/configs/single.yml +0 -9
  25. data/spec/connection_spec.rb +0 -107
  26. data/spec/controllers/cluster_spec.rb +0 -267
  27. data/spec/controllers/controller_spec.rb +0 -129
  28. data/spec/controllers/service_spec.rb +0 -50
  29. data/spec/daemonizing_spec.rb +0 -200
  30. data/spec/headers_spec.rb +0 -40
  31. data/spec/logging_spec.rb +0 -52
  32. data/spec/perf/request_perf_spec.rb +0 -50
  33. data/spec/perf/response_perf_spec.rb +0 -19
  34. data/spec/perf/server_perf_spec.rb +0 -39
  35. data/spec/rack/loader_spec.rb +0 -42
  36. data/spec/rack/rails_adapter_spec.rb +0 -173
  37. data/spec/rails_app/app/controllers/application.rb +0 -10
  38. data/spec/rails_app/app/controllers/simple_controller.rb +0 -19
  39. data/spec/rails_app/app/helpers/application_helper.rb +0 -3
  40. data/spec/rails_app/app/views/simple/index.html.erb +0 -15
  41. data/spec/rails_app/config/boot.rb +0 -109
  42. data/spec/rails_app/config/environment.rb +0 -64
  43. data/spec/rails_app/config/environments/development.rb +0 -18
  44. data/spec/rails_app/config/environments/production.rb +0 -19
  45. data/spec/rails_app/config/environments/test.rb +0 -22
  46. data/spec/rails_app/config/initializers/inflections.rb +0 -10
  47. data/spec/rails_app/config/initializers/mime_types.rb +0 -5
  48. data/spec/rails_app/config/routes.rb +0 -35
  49. data/spec/rails_app/public/404.html +0 -30
  50. data/spec/rails_app/public/422.html +0 -30
  51. data/spec/rails_app/public/500.html +0 -30
  52. data/spec/rails_app/public/dispatch.cgi +0 -10
  53. data/spec/rails_app/public/dispatch.fcgi +0 -24
  54. data/spec/rails_app/public/dispatch.rb +0 -10
  55. data/spec/rails_app/public/favicon.ico +0 -0
  56. data/spec/rails_app/public/images/rails.png +0 -0
  57. data/spec/rails_app/public/index.html +0 -277
  58. data/spec/rails_app/public/javascripts/application.js +0 -2
  59. data/spec/rails_app/public/javascripts/controls.js +0 -963
  60. data/spec/rails_app/public/javascripts/dragdrop.js +0 -972
  61. data/spec/rails_app/public/javascripts/effects.js +0 -1120
  62. data/spec/rails_app/public/javascripts/prototype.js +0 -4225
  63. data/spec/rails_app/public/robots.txt +0 -5
  64. data/spec/rails_app/script/about +0 -3
  65. data/spec/rails_app/script/console +0 -3
  66. data/spec/rails_app/script/destroy +0 -3
  67. data/spec/rails_app/script/generate +0 -3
  68. data/spec/rails_app/script/performance/benchmarker +0 -3
  69. data/spec/rails_app/script/performance/profiler +0 -3
  70. data/spec/rails_app/script/performance/request +0 -3
  71. data/spec/rails_app/script/plugin +0 -3
  72. data/spec/rails_app/script/process/inspector +0 -3
  73. data/spec/rails_app/script/process/reaper +0 -3
  74. data/spec/rails_app/script/process/spawner +0 -3
  75. data/spec/rails_app/script/runner +0 -3
  76. data/spec/rails_app/script/server +0 -3
  77. data/spec/request/mongrel_spec.rb +0 -39
  78. data/spec/request/parser_spec.rb +0 -254
  79. data/spec/request/persistent_spec.rb +0 -35
  80. data/spec/request/processing_spec.rb +0 -50
  81. data/spec/response_spec.rb +0 -102
  82. data/spec/runner_spec.rb +0 -168
  83. data/spec/server/builder_spec.rb +0 -44
  84. data/spec/server/pipelining_spec.rb +0 -110
  85. data/spec/server/robustness_spec.rb +0 -34
  86. data/spec/server/stopping_spec.rb +0 -55
  87. data/spec/server/swiftiply.yml +0 -6
  88. data/spec/server/swiftiply_spec.rb +0 -32
  89. data/spec/server/tcp_spec.rb +0 -47
  90. data/spec/server/threaded_spec.rb +0 -27
  91. data/spec/server/unix_socket_spec.rb +0 -26
  92. data/spec/server_spec.rb +0 -100
  93. data/spec/spec_helper.rb +0 -234
  94. data/tasks/announce.rake +0 -22
  95. data/tasks/deploy.rake +0 -13
  96. data/tasks/email.erb +0 -27
  97. data/tasks/gem.rake +0 -65
  98. data/tasks/rdoc.rake +0 -25
  99. data/tasks/site.rake +0 -15
  100. data/tasks/spec.rake +0 -43
  101. data/tasks/stats.rake +0 -28
@@ -1,55 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Server, "stopping" do
4
- before do
5
- start_server do |env|
6
- [200, { 'Content-Type' => 'text/html' }, ['ok']]
7
- end
8
- @done = false
9
- end
10
-
11
- it "should wait for current requests before soft stopping" do
12
- socket = TCPSocket.new('0.0.0.0', 3333)
13
- socket.write("GET / HTTP/1.1")
14
- EventMachine.next_tick do
15
- @server.stop # Stop the server in the middle of a request
16
- socket.write("\r\n\r\n")
17
- @done = true
18
- end
19
-
20
- timeout(2) do
21
- Thread.pass until @done
22
- end
23
-
24
- out = socket.read
25
- socket.close
26
-
27
- out.should_not be_empty
28
- end
29
-
30
- it "should not accept new requests when soft stopping" do
31
- socket = TCPSocket.new('0.0.0.0', 3333)
32
- socket.write("GET / HTTP/1.1")
33
- @server.stop # Stop the server in the middle of a request
34
-
35
- EventMachine.next_tick do
36
- proc { get('/') }.should raise_error(Errno::ECONNRESET)
37
- end
38
-
39
- socket.close
40
- end
41
-
42
- it "should drop current requests when hard stopping" do
43
- socket = TCPSocket.new('0.0.0.0', 3333)
44
- socket.write("GET / HTTP/1.1")
45
- @server.stop! # Force stop the server in the middle of a request
46
-
47
- EventMachine.next_tick do
48
- socket.should be_closed
49
- end
50
- end
51
-
52
- after do
53
- stop_server
54
- end
55
- end
@@ -1,6 +0,0 @@
1
- cluster_address: 0.0.0.0
2
- cluster_port: 3333
3
- map:
4
- - incoming: 127.0.0.1
5
- outgoing: 127.0.0.1:5555
6
- default: true
@@ -1,32 +0,0 @@
1
- require 'spec_helper'
2
-
3
- if SWIFTIPLY_PATH.empty?
4
- warn "Ignoring Server on Swiftiply specs, gem install swiftiply to run"
5
- else
6
- describe Server, 'on Swiftiply' do
7
- before do
8
- @swiftiply = fork do
9
- exec "#{SWIFTIPLY_PATH} -c #{File.dirname(__FILE__)}/swiftiply.yml"
10
- end
11
- wait_for_socket('0.0.0.0', 3333)
12
- sleep 2 # HACK ooh boy, I wish I knew how to make those specs more stable...
13
- start_server('0.0.0.0', 5555, :backend => Backends::SwiftiplyClient, :wait_for_socket => false) do |env|
14
- body = env.inspect + env['rack.input'].read
15
- [200, { 'Content-Type' => 'text/html' }, body]
16
- end
17
- end
18
-
19
- it 'should GET from Net::HTTP' do
20
- Net::HTTP.get(URI.parse("http://0.0.0.0:3333/?cthis")).should include('cthis')
21
- end
22
-
23
- it 'should POST from Net::HTTP' do
24
- Net::HTTP.post_form(URI.parse("http://0.0.0.0:3333/"), :arg => 'pirate').body.should include('arg=pirate')
25
- end
26
-
27
- after do
28
- stop_server
29
- Process.kill(9, @swiftiply)
30
- end
31
- end
32
- end
@@ -1,47 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Server, 'on TCP socket' do
4
- before do
5
- start_server do |env|
6
- body = env.inspect + env['rack.input'].read
7
- [200, { 'Content-Type' => 'text/html' }, body]
8
- end
9
- end
10
-
11
- it 'should GET from Net::HTTP' do
12
- get('/?cthis').should include('cthis')
13
- end
14
-
15
- it 'should GET from TCPSocket' do
16
- status, headers, body = parse_response(send_data("GET /?this HTTP/1.0\r\nConnection: close\r\n\r\n"))
17
- status.should == 200
18
- headers['Content-Type'].should == 'text/html'
19
- headers['Connection'].should == 'close'
20
- body.should include('this')
21
- end
22
-
23
- it 'should return empty string on incomplete headers' do
24
- send_data("GET /?this HTTP/1.1\r\nHost:").should be_empty
25
- end
26
-
27
- it 'should return empty string on incorrect Content-Length' do
28
- send_data("POST / HTTP/1.1\r\nContent-Length: 300\r\nConnection: close\r\n\r\naye").should be_empty
29
- end
30
-
31
- it 'should POST from Net::HTTP' do
32
- post('/', :arg => 'pirate').should include('arg=pirate')
33
- end
34
-
35
- it 'should handle big POST' do
36
- big = 'X' * (20 * 1024)
37
- post('/', :big => big).should include(big)
38
- end
39
-
40
- it "should retreive remote address" do
41
- get('/').should include('"REMOTE_ADDR"=>"127.0.0.1"')
42
- end
43
-
44
- after do
45
- stop_server
46
- end
47
- end
@@ -1,27 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Server, 'with threads' do
4
- before do
5
- @requests = 0
6
- start_server DEFAULT_TEST_ADDRESS, DEFAULT_TEST_PORT, :threaded => true do |env|
7
- sleep env['PATH_INFO'].delete('/').to_i
8
- @requests += 1
9
- [200, { 'Content-Type' => 'text/html' }, 'hi']
10
- end
11
- end
12
-
13
- it "should process request" do
14
- get('/').should_not be_empty
15
- end
16
-
17
- it "should process requests when blocked" do
18
- slow_request = Thread.new { get('/3') }
19
- get('/').should_not be_empty
20
- @requests.should == 1
21
- slow_request.kill
22
- end
23
-
24
- after do
25
- stop_server
26
- end
27
- end
@@ -1,26 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Server, "on UNIX domain socket" do
4
- before do
5
- start_server('/tmp/thin_test.sock') do |env|
6
- [200, { 'Content-Type' => 'text/html' }, [env.inspect]]
7
- end
8
- end
9
-
10
- it "should accept GET request" do
11
- get("/?this").should include('this')
12
- end
13
-
14
- it "should retreive remote address" do
15
- get('/').should include('"REMOTE_ADDR"=>"127.0.0.1"')
16
- end
17
-
18
- it "should remove socket file after server stops" do
19
- @server.stop!
20
- File.exist?('/tmp/thin_test.sock').should be_false
21
- end
22
-
23
- after do
24
- stop_server
25
- end
26
- end
@@ -1,100 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Server do
4
- before do
5
- @server = Server.new('0.0.0.0', 3000)
6
- end
7
-
8
- it "should set maximum_connections size" do
9
- @server.maximum_connections = 100
10
- @server.config
11
- @server.maximum_connections.should == 100
12
- end
13
-
14
- it "should set lower maximum_connections size when too large" do
15
- # root users under Linux will not have a limitation on maximum
16
- # connections, so we cannot really run this test under that
17
- # condition.
18
- pending("only for non-root users") if Process.euid == 0
19
- @server.maximum_connections = 100_000
20
- @server.config
21
- @server.maximum_connections.should < 100_000
22
- end
23
-
24
- it "should default to non-threaded" do
25
- @server.should_not be_threaded
26
- end
27
-
28
- it "should set backend to threaded" do
29
- @server.threaded = true
30
- @server.backend.should be_threaded
31
- end
32
- end
33
-
34
- describe Server, "initialization" do
35
- it "should set host and port" do
36
- server = Server.new('192.168.1.1', 8080)
37
-
38
- server.host.should == '192.168.1.1'
39
- server.port.should == 8080
40
- end
41
-
42
- it "should set socket" do
43
- server = Server.new('/tmp/thin.sock')
44
-
45
- server.socket.should == '/tmp/thin.sock'
46
- end
47
-
48
- it "should set host, port and app" do
49
- app = proc {}
50
- server = Server.new('192.168.1.1', 8080, app)
51
-
52
- server.host.should_not be_nil
53
- server.app.should == app
54
- end
55
-
56
- it "should set socket and app" do
57
- app = proc {}
58
- server = Server.new('/tmp/thin.sock', app)
59
-
60
- server.socket.should_not be_nil
61
- server.app.should == app
62
- end
63
-
64
- it "should set socket, nil and app" do
65
- app = proc {}
66
- server = Server.new('/tmp/thin.sock', nil, app)
67
-
68
- server.socket.should_not be_nil
69
- server.app.should == app
70
- end
71
-
72
- it "should set host, port and backend" do
73
- server = Server.new('192.168.1.1', 8080, :backend => Thin::Backends::SwiftiplyClient)
74
-
75
- server.host.should_not be_nil
76
- server.backend.should be_kind_of(Thin::Backends::SwiftiplyClient)
77
- end
78
-
79
- it "should set host, port, app and backend" do
80
- app = proc {}
81
- server = Server.new('192.168.1.1', 8080, app, :backend => Thin::Backends::SwiftiplyClient)
82
-
83
- server.host.should_not be_nil
84
- server.app.should == app
85
- server.backend.should be_kind_of(Thin::Backends::SwiftiplyClient)
86
- end
87
-
88
- it "should set port as string" do
89
- app = proc {}
90
- server = Server.new('192.168.1.1', '8080')
91
-
92
- server.host.should == '192.168.1.1'
93
- server.port.should == 8080
94
- end
95
-
96
- it "should not register signals w/ :signals => false" do
97
- Server.should_not_receive(:setup_signals)
98
- Server.new(:signals => false)
99
- end
100
- end
@@ -1,234 +0,0 @@
1
- require 'rubygems'
2
- require 'thin'
3
- gem "rspec", "~> 1.2.9"
4
- require 'spec'
5
- require 'benchmark'
6
- require 'timeout'
7
- require 'fileutils'
8
- require 'net/http'
9
- require 'socket'
10
-
11
- include Thin
12
-
13
- FileUtils.mkdir_p File.dirname(__FILE__) + '/../log'
14
- Command.script = File.dirname(__FILE__) + '/../bin/thin'
15
- Logging.silent = true
16
-
17
- unless Object.const_defined?(:SWIFTIPLY_PATH)
18
- SWIFTIPLY_PATH = `which swiftiply`.chomp
19
- DEFAULT_TEST_ADDRESS = '0.0.0.0'
20
- DEFAULT_TEST_PORT = 3333
21
- end
22
-
23
- module Matchers
24
- class BeFasterThen
25
- def initialize(max_time)
26
- require 'benchmark_unit'
27
- @max_time = max_time
28
- end
29
-
30
- # Base on benchmark_unit/assertions#compare_benchmarks
31
- def matches?(proc)
32
- @time, multiplier = 0, 1
33
-
34
- while (@time < 0.01) do
35
- @time = Benchmark::Unit.measure do
36
- multiplier.times &proc
37
- end
38
- multiplier *= 10
39
- end
40
-
41
- multiplier /= 10
42
-
43
- iterations = (Benchmark::Unit::CLOCK_TARGET / @time).to_i * multiplier
44
- iterations = 1 if iterations < 1
45
-
46
- total = Benchmark::Unit.measure do
47
- iterations.times &proc
48
- end
49
-
50
- @time = total / iterations
51
-
52
- @time < @max_time
53
- end
54
-
55
- def failure_message(less_more=:less)
56
- "took <#{@time.inspect} RubySeconds>, should take #{less_more} than #{@max_time} RubySeconds."
57
- end
58
-
59
- def negative_failure_message
60
- failure_message :more
61
- end
62
- end
63
-
64
- class ValidateWithLint
65
- def matches?(request)
66
- @request = request
67
- Rack::Lint.new(proc{[200, {'Content-Type' => 'text/html', 'Content-Length' => '0'}, []]}).call(@request.env)
68
- true
69
- rescue Rack::Lint::LintError => e
70
- @message = e.message
71
- false
72
- end
73
-
74
- def failure_message(negation=nil)
75
- "should#{negation} validate with Rack Lint: #{@message}"
76
- end
77
-
78
- def negative_failure_message
79
- failure_message ' not'
80
- end
81
- end
82
-
83
- class TakeLessThen
84
- def initialize(time)
85
- @time = time
86
- end
87
-
88
- def matches?(proc)
89
- Timeout.timeout(@time) { proc.call }
90
- true
91
- rescue Timeout::Error
92
- false
93
- end
94
-
95
- def failure_message(negation=nil)
96
- "should#{negation} take less then #{@time} sec to run"
97
- end
98
-
99
- def negative_failure_message
100
- failure_message ' not'
101
- end
102
- end
103
-
104
- # Actual matchers that are exposed.
105
-
106
- def be_faster_then(time)
107
- BeFasterThen.new(time)
108
- end
109
-
110
- def validate_with_lint
111
- ValidateWithLint.new
112
- end
113
-
114
- def take_less_then(time)
115
- TakeLessThen.new(time)
116
- end
117
- end
118
-
119
- module Helpers
120
- # Silences any stream for the duration of the block.
121
- #
122
- # silence_stream(STDOUT) do
123
- # puts 'This will never be seen'
124
- # end
125
- #
126
- # puts 'But this will'
127
- #
128
- # (Taken from ActiveSupport)
129
- def silence_stream(stream)
130
- old_stream = stream.dup
131
- stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
132
- stream.sync = true
133
- yield
134
- ensure
135
- stream.reopen(old_stream)
136
- end
137
-
138
- def silence_warnings
139
- old_verbose, $VERBOSE = $VERBOSE, nil
140
- yield
141
- ensure
142
- $VERBOSE = old_verbose
143
- end
144
-
145
- # Create and parse a request
146
- def R(raw, convert_line_feed=false)
147
- raw.gsub!("\n", "\r\n") if convert_line_feed
148
- request = Thin::Request.new
149
- request.parse(raw)
150
- request
151
- end
152
-
153
- def start_server(address=DEFAULT_TEST_ADDRESS, port=DEFAULT_TEST_PORT, options={}, &app)
154
- @server = Thin::Server.new(address, port, options, app)
155
- @server.ssl = options[:ssl]
156
- @server.threaded = options[:threaded]
157
- @server.timeout = 3
158
-
159
- @thread = Thread.new { @server.start }
160
- if options[:wait_for_socket]
161
- wait_for_socket(address, port)
162
- else
163
- # If we can't ping the address fallback to just wait for the server to run
164
- sleep 0.01 until @server.running?
165
- end
166
- end
167
-
168
- def stop_server
169
- @server.stop!
170
- @thread.kill
171
-
172
- 100.times do
173
- break unless EM.reactor_running?
174
- sleep 0.01
175
- end
176
-
177
- raise "Reactor still running, wtf?" if EventMachine.reactor_running?
178
- end
179
-
180
- def wait_for_socket(address=DEFAULT_TEST_ADDRESS, port=DEFAULT_TEST_PORT, timeout=5)
181
- Timeout.timeout(timeout) do
182
- loop do
183
- begin
184
- if address.include?('/')
185
- UNIXSocket.new(address).close
186
- else
187
- TCPSocket.new(address, port).close
188
- end
189
- return true
190
- rescue
191
- end
192
- end
193
- end
194
- end
195
-
196
- def send_data(data)
197
- if @server.backend.class == Backends::UnixServer
198
- socket = UNIXSocket.new(@server.socket)
199
- else
200
- socket = TCPSocket.new(@server.host, @server.port)
201
- end
202
- socket.write data
203
- out = socket.read
204
- socket.close
205
- out
206
- end
207
-
208
- def parse_response(response)
209
- raw_headers, body = response.split("\r\n\r\n", 2)
210
- raw_status, raw_headers = raw_headers.split("\r\n", 2)
211
-
212
- status = raw_status.match(%r{\AHTTP/1.1\s+(\d+)\b}).captures.first.to_i
213
- headers = Hash[ *raw_headers.split("\r\n").map { |h| h.split(/:\s+/, 2) }.flatten ]
214
-
215
- [ status, headers, body ]
216
- end
217
-
218
- def get(url)
219
- if @server.backend.class == Backends::UnixServer
220
- send_data("GET #{url} HTTP/1.1\r\nConnection: close\r\n\r\n")
221
- else
222
- Net::HTTP.get(URI.parse("http://#{@server.host}:#{@server.port}" + url))
223
- end
224
- end
225
-
226
- def post(url, params={})
227
- Net::HTTP.post_form(URI.parse("http://#{@server.host}:#{@server.port}" + url), params).body
228
- end
229
- end
230
-
231
- Spec::Runner.configure do |config|
232
- config.include Matchers
233
- config.include Helpers
234
- end