thin 0.6.4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of thin might be problematic. Click here for more details.

Files changed (45) hide show
  1. data/CHANGELOG +20 -0
  2. data/README +11 -12
  3. data/benchmark/abc +51 -0
  4. data/benchmark/benchmarker.rb +80 -0
  5. data/benchmark/runner +79 -0
  6. data/example/adapter.rb +3 -3
  7. data/example/thin.god +11 -7
  8. data/lib/thin.rb +17 -16
  9. data/lib/thin/command.rb +10 -4
  10. data/lib/thin/connection.rb +46 -13
  11. data/lib/thin/connectors/connector.rb +22 -10
  12. data/lib/thin/connectors/swiftiply_client.rb +55 -0
  13. data/lib/thin/controllers/cluster.rb +28 -22
  14. data/lib/thin/controllers/controller.rb +74 -14
  15. data/lib/thin/controllers/service.rb +1 -1
  16. data/lib/thin/daemonizing.rb +6 -4
  17. data/lib/thin/headers.rb +4 -0
  18. data/lib/thin/logging.rb +34 -9
  19. data/lib/thin/request.rb +31 -2
  20. data/lib/thin/response.rb +22 -7
  21. data/lib/thin/runner.rb +27 -14
  22. data/lib/thin/server.rb +55 -7
  23. data/lib/thin/version.rb +3 -3
  24. data/spec/command_spec.rb +2 -3
  25. data/spec/connection_spec.rb +15 -1
  26. data/spec/connectors/swiftiply_client_spec.rb +66 -0
  27. data/spec/controllers/cluster_spec.rb +43 -12
  28. data/spec/controllers/controller_spec.rb +16 -4
  29. data/spec/controllers/service_spec.rb +0 -1
  30. data/spec/logging_spec.rb +42 -0
  31. data/spec/request/persistent_spec.rb +35 -0
  32. data/spec/response_spec.rb +18 -0
  33. data/spec/server/pipelining_spec.rb +108 -0
  34. data/spec/server/swiftiply.yml +6 -0
  35. data/spec/server/swiftiply_spec.rb +27 -0
  36. data/spec/server/tcp_spec.rb +3 -3
  37. data/spec/server_spec.rb +22 -0
  38. data/spec/spec_helper.rb +3 -3
  39. data/tasks/gem.rake +1 -1
  40. data/tasks/spec.rake +9 -0
  41. metadata +13 -6
  42. data/benchmark/previous.rb +0 -14
  43. data/benchmark/simple.rb +0 -15
  44. data/benchmark/utils.rb +0 -75
  45. data/lib/thin_parser.bundle +0 -0
@@ -4,7 +4,13 @@ include Controllers
4
4
 
5
5
  describe Controller, 'start' do
6
6
  before do
7
- @controller = Controller.new(:address => '0.0.0.0', :port => 3000, :pid => 'thin.pid', :log => 'thin.log', :timeout => 60)
7
+ @controller = Controller.new(:address => '0.0.0.0',
8
+ :port => 3000,
9
+ :pid => 'thin.pid',
10
+ :log => 'thin.log',
11
+ :timeout => 60,
12
+ :max_conns => 2000,
13
+ :max_persistent_conns => 1000)
8
14
 
9
15
  @server = OpenStruct.new
10
16
  @adapter = OpenStruct.new
@@ -19,7 +25,8 @@ describe Controller, 'start' do
19
25
  @server.app.should == @adapter
20
26
  @server.pid_file.should == 'thin.pid'
21
27
  @server.log_file.should == 'thin.log'
22
- @server.timeout.should == 60
28
+ @server.maximum_connections.should == 2000
29
+ @server.maximum_persistent_connections.should == 1000
23
30
  end
24
31
 
25
32
  it "should start as daemon" do
@@ -62,14 +69,19 @@ describe Controller, 'start' do
62
69
  end
63
70
 
64
71
  describe Controller do
72
+ before do
73
+ @controller = Controller.new(:pid => 'thin.pid', :timeout => 10)
74
+ @controller.stub!(:wait_for_file)
75
+ end
76
+
65
77
  it "should stop" do
66
78
  Server.should_receive(:kill).with('thin.pid', 10)
67
- Controller.new(:pid => 'thin.pid', :timeout => 10).stop
79
+ @controller.stop
68
80
  end
69
81
 
70
82
  it "should restart" do
71
83
  Server.should_receive(:restart).with('thin.pid')
72
- Controller.new(:pid => 'thin.pid').restart
84
+ @controller.restart
73
85
  end
74
86
 
75
87
  it "should write configuration file" do
@@ -14,7 +14,6 @@ describe Service do
14
14
  FileUtils.mkdir_p 'tmp/sandbox'
15
15
 
16
16
  @service = Service.new(:all => 'spec/configs')
17
- @service.silent = true
18
17
  end
19
18
 
20
19
  it "should call command for each config file" do
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ class TestLogging
4
+ include Logging
5
+ end
6
+
7
+ describe Logging do
8
+ before do
9
+ Logging.silent = false
10
+ @object = TestLogging.new
11
+ end
12
+
13
+ it "should output debug when set to true" do
14
+ Logging.debug = true
15
+ @object.should_receive(:puts)
16
+ @object.debug 'hi'
17
+ end
18
+
19
+ it "should output trace when set to true" do
20
+ Logging.trace = true
21
+ @object.should_receive(:puts)
22
+ @object.trace 'hi'
23
+ end
24
+
25
+ it "should not output when silenced" do
26
+ Logging.silent = true
27
+ @object.should_not_receive(:puts)
28
+ @object.log 'hi'
29
+ end
30
+
31
+ it "should not output when silenced [deprecated]" do
32
+ @object.should_receive(:warn)
33
+ @object.silent = true
34
+
35
+ @object.should_not_receive(:puts)
36
+ @object.log 'hi'
37
+ end
38
+
39
+ after do
40
+ Logging.silent = true
41
+ end
42
+ end
@@ -0,0 +1,35 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Request, 'persistent' do
4
+ before do
5
+ @request = Request.new
6
+ end
7
+
8
+ it "should not assume that a persistent connection is maintained for HTTP version 1.0" do
9
+ @request.env['HTTP_VERSION'] = 'HTTP/1.0'
10
+ @request.should_not be_persistent
11
+ end
12
+
13
+ it "should assume that a persistent connection is maintained for HTTP version 1.0 when specified" do
14
+ @request.env['HTTP_VERSION'] = 'HTTP/1.0'
15
+ @request.env['HTTP_CONNECTION'] = 'Keep-Alive'
16
+ @request.should be_persistent
17
+ end
18
+
19
+ it "should maintain a persistent connection for HTTP/1.1 client" do
20
+ @request.env['HTTP_VERSION'] = 'HTTP/1.1'
21
+ @request.env['HTTP_CONNECTION'] = 'Keep-Alive'
22
+ @request.should be_persistent
23
+ end
24
+
25
+ it "should maintain a persistent connection for HTTP/1.1 client by default" do
26
+ @request.env['HTTP_VERSION'] = 'HTTP/1.1'
27
+ @request.should be_persistent
28
+ end
29
+
30
+ it "should not maintain a persistent connection for HTTP/1.1 client when Connection header include close" do
31
+ @request.env['HTTP_VERSION'] = 'HTTP/1.1'
32
+ @request.env['HTTP_CONNECTION'] = 'close'
33
+ @request.should_not be_persistent
34
+ end
35
+ end
@@ -63,6 +63,24 @@ EOS
63
63
  proc { @response.each { |l| l } }.should be_faster_then(0.00011)
64
64
  end
65
65
 
66
+ it "should not be persistent by default" do
67
+ @response.should_not be_persistent
68
+ end
69
+
70
+ it "should not be persistent when no Content-Length" do
71
+ @response = Response.new
72
+ @response.headers['Content-Type'] = 'text/html'
73
+ @response.body = ''
74
+
75
+ @response.persistent!
76
+ @response.should_not be_persistent
77
+ end
78
+
79
+ it "should be persistent when specified" do
80
+ @response.persistent!
81
+ @response.should be_persistent
82
+ end
83
+
66
84
  it "should be closeable" do
67
85
  @response.close
68
86
  end
@@ -0,0 +1,108 @@
1
+ require File.dirname(__FILE__) + '/../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', 'Content-Length' => body.size.to_s }, 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
+ response = socket.read
20
+ socket.close
21
+
22
+ wait_for_requests_to_complete!
23
+
24
+ response.should include('/first-1', '/second-2')
25
+ end
26
+
27
+ it "should pipeline requests by default on HTTP 1.1" do
28
+ socket = TCPSocket.new('0.0.0.0', 3333)
29
+ socket.write "GET /first HTTP/1.1\r\n\r\n"
30
+ socket.flush
31
+ socket.write "GET /second HTTP/1.1\r\nConnection: close\r\n\r\n"
32
+ response = socket.read
33
+ socket.close
34
+
35
+ wait_for_requests_to_complete!
36
+
37
+ response.should include('/first-1', '/second-2')
38
+ end
39
+
40
+ it "should not pipeline request by default on HTTP 1.0" do
41
+ socket = TCPSocket.new('0.0.0.0', 3333)
42
+ socket.write "GET /first HTTP/1.0\r\n\r\n"
43
+ socket.flush
44
+ socket.write "GET /second HTTP/1.0\r\nConnection: close\r\n\r\n"
45
+ response = socket.read
46
+ socket.close
47
+
48
+ wait_for_requests_to_complete!
49
+
50
+ response.should include('/first-1')
51
+ response.should_not include('/second-2')
52
+ end
53
+
54
+ it "should not pipeline request on same socket when connection is closed" do
55
+ socket = TCPSocket.new('0.0.0.0', 3333)
56
+ socket.write "GET /first HTTP/1.1\r\nConnection: close\r\n\r\n"
57
+ socket.flush
58
+ socket.write "GET /second HTTP/1.1\r\nConnection: close\r\n\r\n"
59
+ response = socket.read
60
+ socket.close
61
+
62
+ wait_for_requests_to_complete!
63
+
64
+ response.should include('/first-1')
65
+ response.should_not include('/second-2')
66
+ end
67
+
68
+ it "should not allow more persistent connection then maximum" do
69
+ @server.maximum_persistent_connections = 1
70
+
71
+ socket1 = TCPSocket.new('0.0.0.0', 3333)
72
+ socket1.write "GET / HTTP/1.1\r\n\r\n"
73
+ socket1.flush
74
+ socket2 = TCPSocket.new('0.0.0.0', 3333)
75
+ socket2.write "GET / HTTP/1.1\r\n\r\n"
76
+ socket2.flush
77
+
78
+ @server.connector.persistent_connection_count.should == 1
79
+ @server.connector.size.should == 2
80
+
81
+ socket1.close
82
+ socket2.close
83
+ end
84
+
85
+ it "should decrement persistent connection on close" do
86
+ socket = TCPSocket.new('0.0.0.0', 3333)
87
+ socket.write "GET / HTTP/1.1\r\n\r\n"
88
+ socket.flush
89
+
90
+ @server.connector.persistent_connection_count.should == 1
91
+
92
+ socket.write "GET / HTTP/1.1\r\nConnection: close\r\n\r\n"
93
+ socket.close
94
+
95
+ wait_for_requests_to_complete!
96
+
97
+ @server.connector.persistent_connection_count.should == 0
98
+ end
99
+
100
+ after do
101
+ stop_server
102
+ end
103
+
104
+ private
105
+ def wait_for_requests_to_complete!
106
+ sleep 0.1 until @server.connector.size == 0
107
+ end
108
+ end
@@ -0,0 +1,6 @@
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
@@ -0,0 +1,27 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Server, 'on Swiftiply' do
4
+ before do
5
+ @swiftiply = fork do
6
+ exec "swiftiply -c #{File.dirname(__FILE__)}/swiftiply.yml"
7
+ end
8
+ sleep 0.5
9
+ start_server(Connectors::SwiftiplyClient.new('0.0.0.0', 5555, nil)) do |env|
10
+ body = env.inspect + env['rack.input'].read
11
+ [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.size.to_s }, body]
12
+ end
13
+ end
14
+
15
+ it 'should GET from Net::HTTP' do
16
+ Net::HTTP.get(URI.parse("http://0.0.0.0:3333/?cthis")).should include('cthis')
17
+ end
18
+
19
+ it 'should POST from Net::HTTP' do
20
+ Net::HTTP.post_form(URI.parse("http://0.0.0.0:3333/"), :arg => 'pirate').body.should include('arg=pirate')
21
+ end
22
+
23
+ after do
24
+ stop_server
25
+ Process.kill(9, @swiftiply)
26
+ end
27
+ end
@@ -13,7 +13,7 @@ describe Server, 'on TCP socket' do
13
13
  end
14
14
 
15
15
  it 'should GET from TCPSocket' do
16
- send_data("GET /?this HTTP/1.1\r\n\r\n").
16
+ send_data("GET /?this HTTP/1.1\r\nConnection: close\r\n\r\n").
17
17
  should include("HTTP/1.1 200 OK",
18
18
  "Content-Type: text/html", "Content-Length: ",
19
19
  "Connection: close", "this")
@@ -24,7 +24,7 @@ describe Server, 'on TCP socket' do
24
24
  end
25
25
 
26
26
  it 'should return empty string on incorrect Content-Length' do
27
- send_data("POST / HTTP/1.1\r\nContent-Length: 300\r\n\r\naye").should be_empty
27
+ send_data("POST / HTTP/1.1\r\nContent-Length: 300\r\nConnection: close\r\n\r\naye").should be_empty
28
28
  end
29
29
 
30
30
  it 'should POST from Net::HTTP' do
@@ -36,7 +36,7 @@ describe Server, 'on TCP socket' do
36
36
  post('/', :big => big).should include(big)
37
37
  end
38
38
 
39
- it "should handle GET in less then #{get_request_time = 0.004} RubySecond" do
39
+ it "should handle GET in less then #{get_request_time = 0.0045} RubySecond" do
40
40
  proc { get('/') }.should be_faster_then(get_request_time)
41
41
  end
42
42
 
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + '/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 descriptor table size" do
9
+ @server.should_receive(:log).once
10
+ @server.maximum_connections = 100
11
+ @server.set_descriptor_table_size!
12
+ @server.maximum_connections.should == 100
13
+ end
14
+
15
+ it "should warn when descriptor table size too large" do
16
+ @server.stub!(:log)
17
+ @server.should_receive(:log).with(/^!!/)
18
+ @server.maximum_connections = 100_000
19
+ @server.set_descriptor_table_size!
20
+ @server.maximum_connections.should < 100_000
21
+ end
22
+ end
@@ -12,6 +12,7 @@ include Thin
12
12
 
13
13
  FileUtils.mkdir_p File.dirname(__FILE__) + '/../log'
14
14
  Command.script = File.dirname(__FILE__) + '/../bin/thin'
15
+ Logging.silent = true
15
16
 
16
17
  module Matchers
17
18
  class BeFasterThen
@@ -138,10 +139,9 @@ module Helpers
138
139
  def start_server(*args, &app)
139
140
  @server = Thin::Server.new(args[0] || '0.0.0.0', args[1] || 3333, app)
140
141
  @server.timeout = 3
141
- @server.silent = true
142
142
 
143
143
  @thread = Thread.new { @server.start }
144
- sleep 0.1 until @thread.status == 'sleep'
144
+ sleep 0.1 until @server.running? && EventMachine.reactor_running?
145
145
  end
146
146
 
147
147
  def stop_server
@@ -163,7 +163,7 @@ module Helpers
163
163
 
164
164
  def get(url)
165
165
  if @server.connector.class == Connectors::UnixServer
166
- send_data("GET #{url} HTTP/1.1\r\n\r\n")
166
+ send_data("GET #{url} HTTP/1.1\r\nConnection: close\r\n\r\n")
167
167
  else
168
168
  Net::HTTP.get(URI.parse("http://#{@server.host}:#{@server.port}" + url))
169
169
  end
@@ -18,7 +18,7 @@ spec = Gem::Specification.new do |s|
18
18
  s.add_dependency 'rack', '>= 0.2.0'
19
19
  s.add_dependency 'eventmachine', '>= 0.8.1'
20
20
  unless WIN
21
- s.add_dependency 'daemons', '>= 1.0.9'
21
+ s.add_dependency 'daemons', '>= 1.0.9'
22
22
  end
23
23
 
24
24
  s.files = %w(COPYING CHANGELOG README Rakefile) +
@@ -11,6 +11,15 @@ else
11
11
  desc "Run all examples"
12
12
  Spec::Rake::SpecTask.new('spec') do |t|
13
13
  t.spec_files = FileList['spec/**/*_spec.rb']
14
+ if WIN
15
+ t.spec_files -= [
16
+ 'spec/connectors/unix_server_spec.rb',
17
+ 'spec/controllers/service_spec.rb',
18
+ 'spec/daemonizing_spec.rb',
19
+ 'spec/server/unix_socket_spec.rb',
20
+ 'spec/server/swiftiply_spec.rb'
21
+ ]
22
+ end
14
23
  end
15
24
 
16
25
  task :check_spec_gems do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.4
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc-Andre Cournoyer
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-02-13 00:00:00 -05:00
12
+ date: 2008-02-24 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -52,9 +52,9 @@ files:
52
52
  - CHANGELOG
53
53
  - README
54
54
  - Rakefile
55
- - benchmark/previous.rb
56
- - benchmark/simple.rb
57
- - benchmark/utils.rb
55
+ - benchmark/abc
56
+ - benchmark/benchmarker.rb
57
+ - benchmark/runner
58
58
  - bin/thin
59
59
  - doc/benchmarks.txt
60
60
  - example/adapter.rb
@@ -74,6 +74,7 @@ files:
74
74
  - lib/thin/connection.rb
75
75
  - lib/thin/connectors
76
76
  - lib/thin/connectors/connector.rb
77
+ - lib/thin/connectors/swiftiply_client.rb
77
78
  - lib/thin/connectors/tcp_server.rb
78
79
  - lib/thin/connectors/unix_server.rb
79
80
  - lib/thin/controllers
@@ -93,13 +94,13 @@ files:
93
94
  - lib/thin/statuses.rb
94
95
  - lib/thin/version.rb
95
96
  - lib/thin.rb
96
- - lib/thin_parser.bundle
97
97
  - spec/command_spec.rb
98
98
  - spec/configs
99
99
  - spec/configs/cluster.yml
100
100
  - spec/configs/single.yml
101
101
  - spec/connection_spec.rb
102
102
  - spec/connectors
103
+ - spec/connectors/swiftiply_client_spec.rb
103
104
  - spec/connectors/tcp_server_spec.rb
104
105
  - spec/connectors/unix_server_spec.rb
105
106
  - spec/controllers
@@ -108,6 +109,7 @@ files:
108
109
  - spec/controllers/service_spec.rb
109
110
  - spec/daemonizing_spec.rb
110
111
  - spec/headers_spec.rb
112
+ - spec/logging_spec.rb
111
113
  - spec/rack_rails_spec.rb
112
114
  - spec/rails_app
113
115
  - spec/rails_app/app
@@ -172,14 +174,19 @@ files:
172
174
  - spec/request/mongrel_spec.rb
173
175
  - spec/request/parser_spec.rb
174
176
  - spec/request/perf_spec.rb
177
+ - spec/request/persistent_spec.rb
175
178
  - spec/request/processing_spec.rb
176
179
  - spec/response_spec.rb
177
180
  - spec/runner_spec.rb
178
181
  - spec/server
179
182
  - spec/server/builder_spec.rb
183
+ - spec/server/pipelining_spec.rb
180
184
  - spec/server/stopping_spec.rb
185
+ - spec/server/swiftiply.yml
186
+ - spec/server/swiftiply_spec.rb
181
187
  - spec/server/tcp_spec.rb
182
188
  - spec/server/unix_socket_spec.rb
189
+ - spec/server_spec.rb
183
190
  - spec/spec_helper.rb
184
191
  - tasks/announce.rake
185
192
  - tasks/deploy.rake