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,102 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Response do
4
- before do
5
- @response = Response.new
6
- @response.headers['Content-Type'] = 'text/html'
7
- @response.headers['Content-Length'] = '0'
8
- @response.body = ''
9
- end
10
-
11
- it 'should output headers' do
12
- @response.headers_output.should include("Content-Type: text/html", "Content-Length: 0", "Connection: close")
13
- end
14
-
15
- it 'should include server name header' do
16
- @response.headers_output.should include("Server: thin")
17
- end
18
-
19
- it 'should output head' do
20
- @response.head.should include("HTTP/1.1 200 OK", "Content-Type: text/html", "Content-Length: 0",
21
- "Connection: close", "\r\n\r\n")
22
- end
23
-
24
- it 'should allow duplicates in headers' do
25
- @response.headers['Set-Cookie'] = 'mium=7'
26
- @response.headers['Set-Cookie'] = 'hi=there'
27
-
28
- @response.head.should include("Set-Cookie: mium=7", "Set-Cookie: hi=there")
29
- end
30
-
31
- it 'should parse simple header values' do
32
- @response.headers = {
33
- 'Host' => 'localhost'
34
- }
35
-
36
- @response.head.should include("Host: localhost")
37
- end
38
-
39
- it 'should parse multiline header values in several headers' do
40
- @response.headers = {
41
- 'Set-Cookie' => "mium=7\nhi=there"
42
- }
43
-
44
- @response.head.should include("Set-Cookie: mium=7", "Set-Cookie: hi=there")
45
- end
46
-
47
- it 'should ignore nil headers' do
48
- @response.headers = nil
49
- @response.headers = { 'Host' => 'localhost' }
50
- @response.headers = { 'Set-Cookie' => nil }
51
- @response.head.should include('Host: localhost')
52
- end
53
-
54
- it 'should output body' do
55
- @response.body = ['<html>', '</html>']
56
-
57
- out = ''
58
- @response.each { |l| out << l }
59
- out.should include("\r\n\r\n<html></html>")
60
- end
61
-
62
- it 'should output String body' do
63
- @response.body = '<html></html>'
64
-
65
- out = ''
66
- @response.each { |l| out << l }
67
- out.should include("\r\n\r\n<html></html>")
68
- end
69
-
70
- it "should not be persistent by default" do
71
- @response.should_not be_persistent
72
- end
73
-
74
- it "should not be persistent when no Content-Length" do
75
- @response = Response.new
76
- @response.headers['Content-Type'] = 'text/html'
77
- @response.body = ''
78
-
79
- @response.persistent!
80
- @response.should_not be_persistent
81
- end
82
-
83
- it "should be persistent when the status code implies it should stay open" do
84
- @response = Response.new
85
- @response.status = 100
86
- # "There are no required headers for this class of status code" -- HTTP spec 10.1
87
- @response.body = ''
88
-
89
- # Specifying it as persistent in the code is NOT required
90
- # @response.persistent!
91
- @response.should be_persistent
92
- end
93
-
94
- it "should be persistent when specified" do
95
- @response.persistent!
96
- @response.should be_persistent
97
- end
98
-
99
- it "should be closeable" do
100
- @response.close
101
- end
102
- end
@@ -1,168 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Runner do
4
- it "should parse options" do
5
- runner = Runner.new(%w(start --pid test.pid --port 5000 -o 3000))
6
-
7
- runner.options[:pid].should == 'test.pid'
8
- runner.options[:port].should == 5000
9
- runner.options[:only].should == 3000
10
- end
11
-
12
- it "should parse specified command" do
13
- Runner.new(%w(start)).command.should == 'start'
14
- Runner.new(%w(stop)).command.should == 'stop'
15
- Runner.new(%w(restart)).command.should == 'restart'
16
- end
17
-
18
- it "should abort on unknow command" do
19
- runner = Runner.new(%w(poop))
20
-
21
- runner.should_receive(:abort)
22
- runner.run!
23
- end
24
-
25
- it "should exit on empty command" do
26
- runner = Runner.new([])
27
-
28
- runner.should_receive(:exit).with(1)
29
-
30
- silence_stream(STDOUT) do
31
- runner.run!
32
- end
33
- end
34
-
35
- it "should use Controller when controlling a single server" do
36
- runner = Runner.new(%w(start))
37
-
38
- controller = mock('controller')
39
- controller.should_receive(:start)
40
- Controllers::Controller.should_receive(:new).and_return(controller)
41
-
42
- runner.run!
43
- end
44
-
45
- it "should use Cluster controller when controlling multiple servers" do
46
- runner = Runner.new(%w(start --servers 3))
47
-
48
- controller = mock('cluster')
49
- controller.should_receive(:start)
50
- Controllers::Cluster.should_receive(:new).and_return(controller)
51
-
52
- runner.run!
53
- end
54
-
55
- it "should default to single server controller" do
56
- Runner.new(%w(start)).should_not be_a_cluster
57
- end
58
-
59
- it "should consider as a cluster with :servers option" do
60
- Runner.new(%w(start --servers 3)).should be_a_cluster
61
- end
62
-
63
- it "should consider as a cluster with :only option" do
64
- Runner.new(%w(start --only 3000)).should be_a_cluster
65
- end
66
-
67
- it "should warn when require a rack config file" do
68
- STDERR.stub!(:write)
69
- STDERR.should_receive(:write).with(/WARNING:/)
70
-
71
- runner = Runner.new(%w(start -r config.ru))
72
- runner.run! rescue nil
73
-
74
- runner.options[:rackup].should == 'config.ru'
75
- end
76
-
77
- it "should require file" do
78
- runner = Runner.new(%w(start -r unexisting))
79
- proc { runner.run! }.should raise_error(LoadError)
80
- end
81
-
82
- it "should remember requires" do
83
- runner = Runner.new(%w(start -r rubygems -r thin))
84
- runner.options[:require].should == %w(rubygems thin)
85
- end
86
-
87
- it "should remember debug options" do
88
- runner = Runner.new(%w(start -D -V))
89
- runner.options[:debug].should be_true
90
- runner.options[:trace].should be_true
91
- end
92
-
93
- it "should default debug and trace to false" do
94
- runner = Runner.new(%w(start))
95
- runner.options[:debug].should_not be_true
96
- runner.options[:trace].should_not be_true
97
- end
98
- end
99
-
100
- describe Runner, 'with config file' do
101
- before do
102
- @runner = Runner.new(%w(start --config spec/configs/cluster.yml))
103
- end
104
-
105
- it "should load options from file with :config option" do
106
- @runner.send :load_options_from_config_file!
107
-
108
- @runner.options[:environment].should == 'production'
109
- @runner.options[:chdir].should == 'spec/rails_app'
110
- @runner.options[:port].should == 5000
111
- @runner.options[:servers].should == 3
112
- end
113
-
114
- it "should change directory after loading config" do
115
- @orig_dir = Dir.pwd
116
-
117
- controller = mock('controller')
118
- controller.should_receive(:respond_to?).with('start').and_return(true)
119
- controller.should_receive(:start)
120
- Controllers::Cluster.should_receive(:new).and_return(controller)
121
- expected_dir = File.expand_path('spec/rails_app')
122
-
123
- begin
124
- silence_stream(STDERR) do
125
- @runner.run!
126
- end
127
-
128
- Dir.pwd.should == expected_dir
129
-
130
- ensure
131
- # any other spec using relative paths should work as expected
132
- Dir.chdir(@orig_dir)
133
- end
134
- end
135
- end
136
-
137
- describe Runner, "service" do
138
- before do
139
- Thin.stub!(:linux?).and_return(true)
140
-
141
- @controller = mock('service')
142
- Controllers::Service.stub!(:new).and_return(@controller)
143
- end
144
-
145
- it "should use Service controller when controlling all servers" do
146
- runner = Runner.new(%w(start --all))
147
-
148
- @controller.should_receive(:start)
149
-
150
- runner.run!
151
- end
152
-
153
- it "should call install with arguments" do
154
- runner = Runner.new(%w(install /etc/cool))
155
-
156
- @controller.should_receive(:install).with('/etc/cool')
157
-
158
- runner.run!
159
- end
160
-
161
- it "should call install without arguments" do
162
- runner = Runner.new(%w(install))
163
-
164
- @controller.should_receive(:install).with()
165
-
166
- runner.run!
167
- end
168
- end
@@ -1,44 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Server, 'app builder' do
4
- it "should build app from constructor" do
5
- app = proc {}
6
- server = Server.new('0.0.0.0', 3000, app)
7
-
8
- server.app.should == app
9
- end
10
-
11
- it "should build app from builder block" do
12
- server = Server.new '0.0.0.0', 3000 do
13
- run(proc { |env| :works })
14
- end
15
-
16
- server.app.call({}).should == :works
17
- end
18
-
19
- it "should use middlewares in builder block" do
20
- server = Server.new '0.0.0.0', 3000 do
21
- use Rack::ShowExceptions
22
- run(proc { |env| :works })
23
- end
24
-
25
- server.app.class.should == Rack::ShowExceptions
26
- server.app.call({}).should == :works
27
- end
28
-
29
- it "should work with Rack url mapper" do
30
- server = Server.new '0.0.0.0', 3000 do
31
- map '/test' do
32
- run(proc { |env| [200, {}, 'Found /test'] })
33
- end
34
- end
35
-
36
- default_env = { 'SCRIPT_NAME' => '' }
37
-
38
- server.app.call(default_env.update('PATH_INFO' => '/'))[0].should == 404
39
-
40
- status, headers, body = server.app.call(default_env.update('PATH_INFO' => '/test'))
41
- status.should == 200
42
- body.should == 'Found /test'
43
- end
44
- end
@@ -1,110 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Server, "HTTP pipelining" do
4
- before do
5
- calls = 0
6
- start_server do |env|
7
- calls += 1
8
- body = env['PATH_INFO'] + '-' + calls.to_s
9
- [200, { 'Content-Type' => 'text/html' }, body]
10
- end
11
- @server.maximum_persistent_connections = 1024
12
- end
13
-
14
- it "should pipeline request on same socket" do
15
- socket = TCPSocket.new('0.0.0.0', 3333)
16
- socket.write "GET /first HTTP/1.1\r\nConnection: keep-alive\r\n\r\n"
17
- socket.flush
18
- socket.write "GET /second HTTP/1.1\r\nConnection: close\r\n\r\n"
19
- socket.flush
20
- response = socket.read
21
- socket.close
22
-
23
- wait_for_requests_to_complete!
24
-
25
- response.should include('/first-1', '/second-2')
26
- end
27
-
28
- it "should pipeline requests by default on HTTP 1.1" do
29
- socket = TCPSocket.new('0.0.0.0', 3333)
30
- socket.write "GET /first HTTP/1.1\r\n\r\n"
31
- socket.flush
32
- socket.write "GET /second HTTP/1.1\r\nConnection: close\r\n\r\n"
33
- socket.flush
34
- response = socket.read
35
- socket.close
36
-
37
- wait_for_requests_to_complete!
38
-
39
- response.should include('/first-1', '/second-2')
40
- end
41
-
42
- it "should not pipeline request by default on HTTP 1.0" do
43
- socket = TCPSocket.new('0.0.0.0', 3333)
44
- socket.write "GET /first HTTP/1.0\r\n\r\n"
45
- socket.flush
46
- socket.write "GET /second HTTP/1.0\r\nConnection: close\r\n\r\n"
47
- response = socket.read
48
- socket.close
49
-
50
- wait_for_requests_to_complete!
51
-
52
- response.should include('/first-1')
53
- response.should_not include('/second-2')
54
- end
55
-
56
- it "should not pipeline request on same socket when connection is closed" do
57
- socket = TCPSocket.new('0.0.0.0', 3333)
58
- socket.write "GET /first HTTP/1.1\r\nConnection: close\r\n\r\n"
59
- socket.flush
60
- socket.write "GET /second HTTP/1.1\r\nConnection: close\r\n\r\n"
61
- response = socket.read
62
- socket.close
63
-
64
- wait_for_requests_to_complete!
65
-
66
- response.should include('/first-1')
67
- response.should_not include('/second-2')
68
- end
69
-
70
- it "should not allow more persistent connection then maximum" do
71
- @server.maximum_persistent_connections = 1
72
-
73
- socket1 = TCPSocket.new('0.0.0.0', 3333)
74
- socket1.write "GET / HTTP/1.1\r\n\r\n"
75
- socket1.flush
76
- socket2 = TCPSocket.new('0.0.0.0', 3333)
77
- socket2.write "GET / HTTP/1.1\r\n\r\n"
78
- socket2.flush
79
-
80
- @server.backend.persistent_connection_count.should == 1
81
- @server.backend.size.should == 2
82
-
83
- socket1.close
84
- socket2.close
85
- end
86
-
87
- it "should decrement persistent connection on close" do
88
- socket = TCPSocket.new('0.0.0.0', 3333)
89
- socket.write "GET / HTTP/1.1\r\n\r\n"
90
- socket.flush
91
-
92
- @server.backend.persistent_connection_count.should == 1
93
-
94
- socket.write "GET / HTTP/1.1\r\nConnection: close\r\n\r\n"
95
- socket.close
96
-
97
- wait_for_requests_to_complete!
98
-
99
- @server.backend.persistent_connection_count.should == 0
100
- end
101
-
102
- after do
103
- stop_server
104
- end
105
-
106
- private
107
- def wait_for_requests_to_complete!
108
- sleep 0.1 until @server.backend.size == 0
109
- end
110
- end
@@ -1,34 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Server, 'robustness' do
4
- before do
5
- start_server do |env|
6
- body = 'hello!'
7
- [200, { 'Content-Type' => 'text/html' }, body]
8
- end
9
- end
10
-
11
- it "should not crash when header too large" do
12
- 100.times do
13
- begin
14
- socket = TCPSocket.new(DEFAULT_TEST_ADDRESS, DEFAULT_TEST_PORT)
15
- socket.write("GET / HTTP/1.1\r\n")
16
- socket.write("Host: localhost\r\n")
17
- socket.write("Connection: close\r\n")
18
- 10000.times do
19
- socket.write("X-Foo: #{'x' * 100}\r\n")
20
- socket.flush
21
- end
22
- socket.write("\r\n")
23
- socket.read
24
- socket.close
25
- rescue Errno::EPIPE, Errno::ECONNRESET
26
- # Ignore.
27
- end
28
- end
29
- end
30
-
31
- after do
32
- stop_server
33
- end
34
- end