thin 0.6.2 → 0.6.3

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 (49) hide show
  1. data/CHANGELOG +34 -0
  2. data/bin/thin +2 -164
  3. data/example/config.ru +4 -1
  4. data/example/ramaze.ru +12 -0
  5. data/example/thin.god +70 -66
  6. data/example/vlad.rake +61 -0
  7. data/lib/rack/adapter/rails.rb +0 -3
  8. data/lib/rack/handler/thin.rb +6 -1
  9. data/lib/thin.rb +13 -4
  10. data/lib/thin/command.rb +9 -5
  11. data/lib/thin/connection.rb +5 -14
  12. data/lib/thin/connectors/connector.rb +61 -0
  13. data/lib/thin/connectors/tcp_server.rb +29 -0
  14. data/lib/thin/connectors/unix_server.rb +48 -0
  15. data/lib/thin/controllers/cluster.rb +115 -0
  16. data/lib/thin/controllers/controller.rb +85 -0
  17. data/lib/thin/controllers/service.rb +73 -0
  18. data/lib/thin/controllers/service.sh.erb +39 -0
  19. data/lib/thin/daemonizing.rb +9 -4
  20. data/lib/thin/headers.rb +2 -2
  21. data/lib/thin/runner.rb +166 -0
  22. data/lib/thin/server.rb +109 -89
  23. data/lib/thin/stats.html.erb +216 -0
  24. data/lib/thin/stats.rb +1 -249
  25. data/lib/thin/version.rb +10 -3
  26. data/spec/command_spec.rb +0 -1
  27. data/spec/configs/cluster.yml +9 -0
  28. data/spec/configs/single.yml +9 -0
  29. data/spec/{cluster_spec.rb → controllers/cluster_spec.rb} +22 -10
  30. data/spec/controllers/controller_spec.rb +85 -0
  31. data/spec/controllers/service_spec.rb +51 -0
  32. data/spec/daemonizing_spec.rb +73 -9
  33. data/spec/request/mongrel_spec.rb +39 -0
  34. data/spec/{request_spec.rb → request/parser_spec.rb} +11 -143
  35. data/spec/request/perf_spec.rb +50 -0
  36. data/spec/request/processing_spec.rb +46 -0
  37. data/spec/runner_spec.rb +135 -0
  38. data/spec/server/builder_spec.rb +38 -0
  39. data/spec/server/stopping_spec.rb +45 -0
  40. data/spec/server/tcp_spec.rb +54 -0
  41. data/spec/server/unix_socket_spec.rb +30 -0
  42. data/spec/spec_helper.rb +49 -16
  43. data/tasks/announce.rake +7 -3
  44. data/tasks/email.erb +8 -18
  45. data/tasks/gem.rake +8 -1
  46. data/tasks/stats.rake +21 -8
  47. metadata +33 -6
  48. data/lib/thin/cluster.rb +0 -123
  49. data/spec/server_spec.rb +0 -200
@@ -0,0 +1,38 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Server, 'app builder' do
4
+ it "should build app from constructor" do
5
+ server = Server.new('0.0.0.0', 3000, :works)
6
+
7
+ server.app.should == :works
8
+ end
9
+
10
+ it "should build app from builder block" do
11
+ server = Server.new '0.0.0.0', 3000 do
12
+ run(proc { |env| :works })
13
+ end
14
+
15
+ server.app.call({}).should == :works
16
+ end
17
+
18
+ it "should use middlewares in builder block" do
19
+ server = Server.new '0.0.0.0', 3000 do
20
+ use Rack::ShowExceptions
21
+ run(proc { |env| :works })
22
+ end
23
+
24
+ server.app.class.should == Rack::ShowExceptions
25
+ server.app.call({}).should == :works
26
+ end
27
+
28
+ it "should work with Rack url mapper" do
29
+ server = Server.new '0.0.0.0', 3000 do
30
+ map '/test' do
31
+ run(proc { |env| :works })
32
+ end
33
+ end
34
+
35
+ server.app.call({})[0].should == 404
36
+ server.app.call({'PATH_INFO' => '/test'}).should == :works
37
+ end
38
+ end
@@ -0,0 +1,45 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Server, "stopping" do
4
+ before do
5
+ start_server do |env|
6
+ [200, { 'Content-Type' => 'text/html', 'Content-Length' => '2' }, ['ok']]
7
+ end
8
+ end
9
+
10
+ it "should wait for current requests before soft stopping" do
11
+ socket = TCPSocket.new('0.0.0.0', 3333)
12
+ socket.write("GET / HTTP/1.1")
13
+ @server.stop # Stop the server in the middle of a request
14
+ socket.write("\r\n\r\n")
15
+
16
+ out = socket.read
17
+ socket.close
18
+
19
+ out.should_not be_empty
20
+ end
21
+
22
+ it "should not accept new requests when soft stopping" do
23
+ socket = TCPSocket.new('0.0.0.0', 3333)
24
+ socket.write("GET / HTTP/1.1")
25
+ @server.stop # Stop the server in the middle of a request
26
+
27
+ EventMachine.next_tick do
28
+ proc { get('/') }.should raise_error(Errno::ECONNRESET)
29
+ end
30
+
31
+ socket.close
32
+ end
33
+
34
+ it "should drop current requests when hard stopping" do
35
+ socket = TCPSocket.new('0.0.0.0', 3333)
36
+ socket.write("GET / HTTP/1.1")
37
+ @server.stop! # Force stop the server in the middle of a request
38
+
39
+ EventMachine.next_tick { socket.should be_closed }
40
+ end
41
+
42
+ after do
43
+ stop_server
44
+ end
45
+ end
@@ -0,0 +1,54 @@
1
+ require File.dirname(__FILE__) + '/../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', 'Content-Length' => body.size.to_s }, 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
+ send_data("GET /?this HTTP/1.1\r\n\r\n").
17
+ should include("HTTP/1.1 200 OK",
18
+ "Content-Type: text/html", "Content-Length: ",
19
+ "Connection: close", "this")
20
+ end
21
+
22
+ it 'should return empty string on incomplete headers' do
23
+ send_data("GET /?this HTTP/1.1\r\nHost:").should be_empty
24
+ end
25
+
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
28
+ end
29
+
30
+ it 'should POST from Net::HTTP' do
31
+ post('/', :arg => 'pirate').should include('arg=pirate')
32
+ end
33
+
34
+ it 'should handle big POST' do
35
+ big = 'X' * (20 * 1024)
36
+ post('/', :big => big).should include(big)
37
+ end
38
+
39
+ it "should handle GET in less then #{get_request_time = 0.004} RubySecond" do
40
+ proc { get('/') }.should be_faster_then(get_request_time)
41
+ end
42
+
43
+ it "should handle POST in less then #{post_request_time = 0.007} RubySecond" do
44
+ proc { post('/', :file => 'X' * 1000) }.should be_faster_then(post_request_time)
45
+ end
46
+
47
+ it "should retreive remote address" do
48
+ get('/').should include('"REMOTE_ADDR"=>"127.0.0.1"')
49
+ end
50
+
51
+ after do
52
+ stop_server
53
+ end
54
+ end
@@ -0,0 +1,30 @@
1
+ require File.dirname(__FILE__) + '/../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', 'Content-Length' => env.inspect.size.to_s }, [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"=>""') # Is that right?
16
+ end
17
+
18
+ it "should handle GET in less then #{get_request_time = 0.002} RubySecond" do
19
+ proc { get('/') }.should be_faster_then(get_request_time)
20
+ end
21
+
22
+ it "should remove socket file after server stops" do
23
+ @server.stop!
24
+ File.exist?('/tmp/thin_test.sock').should be_false
25
+ end
26
+
27
+ after do
28
+ stop_server
29
+ end
30
+ end
data/spec/spec_helper.rb CHANGED
@@ -5,26 +5,13 @@ require 'benchmark'
5
5
  require 'timeout'
6
6
  require 'fileutils'
7
7
  require 'benchmark_unit'
8
+ require 'net/http'
9
+ require 'socket'
8
10
 
9
11
  include Thin
10
12
 
11
13
  FileUtils.mkdir_p File.dirname(__FILE__) + '/../log'
12
-
13
- class TestRequest < Thin::Request
14
- def initialize(path, verb='GET', params={})
15
- @path = path
16
- @verb = verb.to_s.upcase
17
- @params = {
18
- 'HTTP_HOST' => 'localhost:3000',
19
- 'REQUEST_URI' => @path,
20
- 'REQUEST_PATH' => @path,
21
- 'REQUEST_METHOD' => @verb,
22
- 'SCRIPT_NAME' => @path
23
- }.merge(params)
24
-
25
- @body = "#{@verb} #{path} HTTP/1.1"
26
- end
27
- end
14
+ Command.script = File.dirname(__FILE__) + '/../bin/thin'
28
15
 
29
16
  module Matchers
30
17
  class BeFasterThen
@@ -139,6 +126,52 @@ module Helpers
139
126
  ensure
140
127
  stream.reopen(old_stream)
141
128
  end
129
+
130
+ # Create and parse a request
131
+ def R(raw, convert_line_feed=false)
132
+ raw.gsub!("\n", "\r\n") if convert_line_feed
133
+ request = Thin::Request.new
134
+ request.parse(raw)
135
+ request
136
+ end
137
+
138
+ def start_server(*args, &app)
139
+ @server = Thin::Server.new(args[0] || '0.0.0.0', args[1] || 3333, app)
140
+ @server.timeout = 3
141
+ @server.silent = true
142
+
143
+ @thread = Thread.new { @server.start }
144
+ sleep 0.1 until @thread.status == 'sleep'
145
+ end
146
+
147
+ def stop_server
148
+ @server.stop!
149
+ @thread.kill
150
+ end
151
+
152
+ def send_data(data)
153
+ if @server.connector.class == Connectors::UnixServer
154
+ socket = UNIXSocket.new(@server.socket)
155
+ else
156
+ socket = TCPSocket.new(@server.host, @server.port)
157
+ end
158
+ socket.write data
159
+ out = socket.read
160
+ socket.close
161
+ out
162
+ end
163
+
164
+ def get(url)
165
+ if @server.connector.class == Connectors::UnixServer
166
+ send_data("GET #{url} HTTP/1.1\r\n\r\n")
167
+ else
168
+ Net::HTTP.get(URI.parse("http://#{@server.host}:#{@server.port}" + url))
169
+ end
170
+ end
171
+
172
+ def post(url, params={})
173
+ Net::HTTP.post_form(URI.parse("http://#{@server.host}:#{@server.port}" + url), params).body
174
+ end
142
175
  end
143
176
 
144
177
  Spec::Runner.configure do |config|
data/tasks/announce.rake CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'erb'
2
2
 
3
3
  MSG_TEMPLATE = File.dirname(__FILE__) + '/email.erb'
4
- SEND_TO = %w(thin-ruby@googlegroups.com eventmachine-talk@rubyforge.org Rubymtl@lists.artengine.ca ruby-talk@ruby-lang.org)
4
+ SEND_TO = %w(thin-ruby@googlegroups.com eventmachine-talk@rubyforge.org Rubymtl@lists.artengine.ca ruby-talk@ruby-lang.org montreal-on-rails@googlegroups.com)
5
5
 
6
6
  desc 'Generate a template for the new version annoucement'
7
7
  task :ann do
@@ -9,10 +9,14 @@ task :ann do
9
9
 
10
10
  body = <<END_OF_MESSAGE
11
11
  To: #{SEND_TO.join(', ')}
12
- Subject: [ANN] Thin #{Thin::VERSION::STRING} #{Thin::VERSION::CODENAME} released
12
+ Subject: [ANN] Thin #{Thin::VERSION::STRING} #{Thin::VERSION::CODENAME} release
13
13
 
14
14
  #{msg}
15
15
  END_OF_MESSAGE
16
16
 
17
- puts body
17
+ `echo "#{body}" | mate`
18
+ end
19
+
20
+ def changelog
21
+ File.read('CHANGELOG').split("==")[1].split("\n")[1..-1].join("\n")
18
22
  end
data/tasks/email.erb CHANGED
@@ -6,37 +6,27 @@ http://code.macournoyer.com/thin/
6
6
 
7
7
  == What's new?
8
8
 
9
- Bug fix in daemon mode and speed boost for all!
10
-
11
- * Don't read the full body, use direct streaming when sending response.
12
- See: Response#each
13
- As a result, the Content-Length can not be calculated anymore.
14
- You have to do set this in your adapter. All frameworks do it anyway.
15
- It improve memory usage and boost speed for low concurrency.
16
- Thanks to Kent Sibilev and Ezra for their help on that one.
17
- * Add 'Server' response header
18
- * Fix --user and --group option not changing daemon process privileges
9
+ <%= changelog %>
19
10
 
20
11
  == Get it!
21
12
 
22
13
  sudo gem install thin
23
14
 
24
- Might take some time for the gem mirrors to be updated, try adding
25
- --source http://code.macournoyer.com to the command if it doesn't work
15
+ Or using my mirror:
26
16
 
27
- If you installed a previous alpha version (if you have <%= Thin::VERSION::STRING %> already installed)
28
- uninstall it before: sudo gem uninstall thin
17
+ sudo gem install thin --source http://code.macournoyer.com
29
18
 
30
19
  WARNING:
31
- Thin is still alpha software, if you use it on your server you understand the
32
- risks that are involved.
20
+ Thin is still alpha software, if you use it on your server you understand the
21
+ risks that are involved.
33
22
 
34
23
  == Contribute
35
24
 
36
25
  If you're using Thin, let me know and I'll put your site on http://code.macournoyer.com/thin/users/
37
26
 
38
- Thin is driven by an active community of passionate coders and benchmarkers. Please join us, contribute
39
- or share some ideas in Thin Google Group: http://groups.google.com/group/thin-ruby/topics
27
+ Thin is driven by an active community of passionate coders and benchmarkers.
28
+ Please join us, contribute or share some ideas in Thin Google Group:
29
+ http://groups.google.com/group/thin-ruby/topics
40
30
 
41
31
  Also on IRC: #thin on freenode
42
32
 
data/tasks/gem.rake CHANGED
@@ -74,7 +74,14 @@ namespace :gem do
74
74
  sh "rubyforge add_file thin thin #{Thin::VERSION::STRING} pkg/#{spec.full_name}.gem"
75
75
  sh "rubyforge add_file thin thin #{Thin::VERSION::STRING} pkg/#{spec.full_name}-x86-mswin32-60.gem"
76
76
  end
77
- end
77
+ end
78
+
79
+ desc 'Download the Windows gem from Kevin repo'
80
+ task 'download:win' => 'pkg' do
81
+ cd 'pkg' do
82
+ `wget http://rubygems.bantamtech.com/ruby18/gems/#{spec.full_name}-x86-mswin32-60.gem`
83
+ end
84
+ end
78
85
  end
79
86
 
80
87
  task :install => [:clobber, :compile, :package] do
data/tasks/stats.rake CHANGED
@@ -3,13 +3,26 @@ task :stats do
3
3
  line_count = proc do |path|
4
4
  Dir[path].collect { |f| File.open(f).readlines.reject { |l| l =~ /(^\s*(\#|\/\*))|^\s*$/ }.size }.inject(0){ |sum,n| sum += n }
5
5
  end
6
- lib = line_count['lib/**/*.rb']
7
- ext = line_count['ext/**/*.{c,h}']
8
- spec = line_count['spec/**/*.rb']
9
- ratio = '%1.2f' % (spec.to_f / lib.to_f)
6
+ comment_count = proc do |path|
7
+ Dir[path].collect { |f| File.open(f).readlines.select { |l| l =~ /^\s*\#/ }.size }.inject(0) { |sum,n| sum += n }
8
+ end
9
+ lib = line_count['lib/**/*.rb']
10
+ comment = comment_count['lib/**/*.rb']
11
+ ext = line_count['ext/**/*.{c,h}']
12
+ spec = line_count['spec/**/*.rb']
13
+
14
+ comment_ratio = '%1.2f' % (comment.to_f / lib.to_f)
15
+ spec_ratio = '%1.2f' % (spec.to_f / lib.to_f)
10
16
 
11
- puts "#{lib.to_s.rjust(6)} LOC of lib"
12
- puts "#{ext.to_s.rjust(6)} LOC of ext"
13
- puts "#{spec.to_s.rjust(6)} LOC of spec"
14
- puts "#{ratio.to_s.rjust(6)} ratio lib/spec"
17
+ puts '/======================\\'
18
+ puts '| Part LOC |'
19
+ puts '|======================|'
20
+ puts "| lib #{lib.to_s.ljust(5)}|"
21
+ puts "| lib comments #{comment.to_s.ljust(5)}|"
22
+ puts "| ext #{ext.to_s.ljust(5)}|"
23
+ puts "| spec #{spec.to_s.ljust(5)}|"
24
+ puts '| ratios: |'
25
+ puts "| lib/comment #{comment_ratio.to_s.ljust(5)}|"
26
+ puts "| lib/spec #{spec_ratio.to_s.ljust(5)}|"
27
+ puts '\======================/'
15
28
  end
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.2
4
+ version: 0.6.3
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-01-30 00:00:00 -05:00
12
+ date: 2008-02-07 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -61,28 +61,46 @@ files:
61
61
  - example/config.ru
62
62
  - example/monit_sockets
63
63
  - example/monit_unixsock
64
+ - example/ramaze.ru
64
65
  - example/thin.god
66
+ - example/vlad.rake
65
67
  - lib/rack
66
68
  - lib/rack/adapter
67
69
  - lib/rack/adapter/rails.rb
68
70
  - lib/rack/handler
69
71
  - lib/rack/handler/thin.rb
70
72
  - lib/thin
71
- - lib/thin/cluster.rb
72
73
  - lib/thin/command.rb
73
74
  - lib/thin/connection.rb
75
+ - lib/thin/connectors
76
+ - lib/thin/connectors/connector.rb
77
+ - lib/thin/connectors/tcp_server.rb
78
+ - lib/thin/connectors/unix_server.rb
79
+ - lib/thin/controllers
80
+ - lib/thin/controllers/cluster.rb
81
+ - lib/thin/controllers/controller.rb
82
+ - lib/thin/controllers/service.rb
83
+ - lib/thin/controllers/service.sh.erb
74
84
  - lib/thin/daemonizing.rb
75
85
  - lib/thin/headers.rb
76
86
  - lib/thin/logging.rb
77
87
  - lib/thin/request.rb
78
88
  - lib/thin/response.rb
89
+ - lib/thin/runner.rb
79
90
  - lib/thin/server.rb
91
+ - lib/thin/stats.html.erb
80
92
  - lib/thin/stats.rb
81
93
  - lib/thin/statuses.rb
82
94
  - lib/thin/version.rb
83
95
  - lib/thin.rb
84
- - spec/cluster_spec.rb
85
96
  - spec/command_spec.rb
97
+ - spec/configs
98
+ - spec/configs/cluster.yml
99
+ - spec/configs/single.yml
100
+ - spec/controllers
101
+ - spec/controllers/cluster_spec.rb
102
+ - spec/controllers/controller_spec.rb
103
+ - spec/controllers/service_spec.rb
86
104
  - spec/daemonizing_spec.rb
87
105
  - spec/headers_spec.rb
88
106
  - spec/rack_rails_spec.rb
@@ -144,9 +162,18 @@ files:
144
162
  - spec/rails_app/script/server
145
163
  - spec/rails_app/tmp
146
164
  - spec/rails_app/tmp/pids
147
- - spec/request_spec.rb
165
+ - spec/request
166
+ - spec/request/mongrel_spec.rb
167
+ - spec/request/parser_spec.rb
168
+ - spec/request/perf_spec.rb
169
+ - spec/request/processing_spec.rb
148
170
  - spec/response_spec.rb
149
- - spec/server_spec.rb
171
+ - spec/runner_spec.rb
172
+ - spec/server
173
+ - spec/server/builder_spec.rb
174
+ - spec/server/stopping_spec.rb
175
+ - spec/server/tcp_spec.rb
176
+ - spec/server/unix_socket_spec.rb
150
177
  - spec/spec_helper.rb
151
178
  - tasks/announce.rake
152
179
  - tasks/deploy.rake