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
data/lib/thin/cluster.rb DELETED
@@ -1,123 +0,0 @@
1
- module Thin
2
- # Control a set of servers.
3
- # * Generate start and stop commands and run them.
4
- # * Inject the port or socket number in the pid and log filenames.
5
- # Servers are started throught the +thin+ command-line script.
6
- class Cluster
7
- include Logging
8
-
9
- # Path to the +thin+ script used to control the servers.
10
- # Leave this to default to use the one in the path.
11
- attr_accessor :script
12
-
13
- # Number of servers in the cluster.
14
- attr_accessor :size
15
-
16
- # Command line options passed to the thin script
17
- attr_accessor :options
18
-
19
- # Create a new cluster of servers launched using +options+.
20
- def initialize(options)
21
- @options = options.merge(:daemonize => true)
22
- @size = @options.delete(:servers)
23
- @only = @options.delete(:only)
24
- @script = $PROGRAM_NAME
25
-
26
- if socket
27
- @options.delete(:address)
28
- @options.delete(:port)
29
- end
30
- end
31
-
32
- def first_port; @options[:port] end
33
- def address; @options[:address] end
34
- def socket; @options[:socket] end
35
- def pid_file; @options[:pid] end
36
- def log_file; @options[:log] end
37
-
38
- # Start the servers
39
- def start
40
- with_each_server { |port| start_server port }
41
- end
42
-
43
- # Start a single server
44
- def start_server(number)
45
- log "Starting server on #{server_id(number)} ... "
46
-
47
- run :start, @options, number
48
- end
49
-
50
- # Stop the servers
51
- def stop
52
- with_each_server { |n| stop_server n }
53
- end
54
-
55
- # Stop a single server
56
- def stop_server(number)
57
- log "Stopping server on #{server_id(number)} ... "
58
-
59
- run :stop, @options, number
60
- end
61
-
62
- # Stop and start the servers.
63
- def restart
64
- stop
65
- sleep 0.1 # Let's breath a bit shall we ?
66
- start
67
- end
68
-
69
- def server_id(number)
70
- if socket
71
- socket_for(number)
72
- else
73
- [address, number].join(':')
74
- end
75
- end
76
-
77
- def log_file_for(number)
78
- include_server_number log_file, number
79
- end
80
-
81
- def pid_file_for(number)
82
- include_server_number pid_file, number
83
- end
84
-
85
- def socket_for(number)
86
- include_server_number socket, number
87
- end
88
-
89
- def pid_for(number)
90
- File.read(pid_file_for(number)).chomp.to_i
91
- end
92
-
93
- private
94
- # Send the command to the +thin+ script
95
- def run(cmd, options, number)
96
- cmd_options = options.dup
97
- cmd_options.merge!(:pid => pid_file_for(number), :log => log_file_for(number))
98
- if socket
99
- cmd_options.merge!(:socket => socket_for(number))
100
- else
101
- cmd_options.merge!(:port => number)
102
- end
103
- Command.run(cmd, cmd_options)
104
- end
105
-
106
- def with_each_server
107
- if @only
108
- yield @only
109
- else
110
- @size.times do |n|
111
- yield socket ? n : (first_port + n)
112
- end
113
- end
114
- end
115
-
116
- # Add the server port or number in the filename
117
- # so each instance get its own file
118
- def include_server_number(path, number)
119
- ext = File.extname(path)
120
- path.gsub(/#{ext}$/, ".#{number}#{ext}")
121
- end
122
- end
123
- end
data/spec/server_spec.rb DELETED
@@ -1,200 +0,0 @@
1
- require File.dirname(__FILE__) + '/spec_helper'
2
- require 'net/http'
3
- require 'socket'
4
-
5
- describe Server do
6
- before do
7
- app = proc do |env|
8
- body = ''
9
- body << env.inspect
10
- body << env['rack.input'].read
11
- [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.size.to_s }, body]
12
- end
13
- @server = Thin::Server.new('0.0.0.0', 3333, app)
14
- @server.timeout = 3
15
- @server.silent = true
16
-
17
- @thread = Thread.new { @server.start }
18
- sleep 0.1 until @thread.status == 'sleep'
19
- end
20
-
21
- it 'should GET from Net::HTTP' do
22
- get('/?cthis').should include('cthis')
23
- end
24
-
25
- it 'should GET from TCPSocket' do
26
- raw("GET /?this HTTP/1.1\r\n\r\n").
27
- should include("HTTP/1.1 200 OK",
28
- "Content-Type: text/html", "Content-Length: ",
29
- "Connection: close", "this")
30
- end
31
-
32
- it 'should return empty string on incomplete headers' do
33
- raw("GET /?this HTTP/1.1\r\nHost:").should be_empty
34
- end
35
-
36
- it 'should return empty string on incorrect Content-Length' do
37
- raw("POST / HTTP/1.1\r\nContent-Length: 300\r\n\r\naye").should be_empty
38
- end
39
-
40
- it 'should POST from Net::HTTP' do
41
- post('/', :arg => 'pirate').should include('arg=pirate')
42
- end
43
-
44
- it 'should handle big POST' do
45
- big = 'X' * (20 * 1024)
46
- post('/', :big => big).should include(big)
47
- end
48
-
49
- it "should handle GET in less then #{get_request_time = 0.004} RubySecond" do
50
- proc { get('/') }.should be_faster_then(get_request_time)
51
- end
52
-
53
- it "should handle POST in less then #{post_request_time = 0.007} RubySecond" do
54
- proc { post('/', :file => 'X' * 1000) }.should be_faster_then(post_request_time)
55
- end
56
-
57
- it "should retreive remote address" do
58
- get('/').should include('"REMOTE_ADDR"=>"127.0.0.1"')
59
- end
60
-
61
- it "should wait for current requests before soft stopping" do
62
- socket = TCPSocket.new('0.0.0.0', 3333)
63
- socket.write("GET / HTTP/1.1")
64
- @server.stop # Stop the server in the middle of a request
65
- socket.write("\r\n\r\n")
66
-
67
- out = socket.read
68
- socket.close
69
-
70
- out.should_not be_empty
71
- end
72
-
73
- it "should not accept new requests when soft stopping" do
74
- socket = TCPSocket.new('0.0.0.0', 3333)
75
- socket.write("GET / HTTP/1.1")
76
- @server.stop # Stop the server in the middle of a request
77
-
78
- EventMachine.next_tick do
79
- proc { get('/') }.should raise_error(Errno::ECONNRESET)
80
- end
81
-
82
- socket.close
83
- end
84
-
85
- it "should drop current requests when hard stopping" do
86
- socket = TCPSocket.new('0.0.0.0', 3333)
87
- socket.write("GET / HTTP/1.1")
88
- @server.stop! # Force stop the server in the middle of a request
89
-
90
- EventMachine.next_tick { socket.should be_closed }
91
- end
92
-
93
- after do
94
- @server.stop!
95
- @thread.kill
96
- end
97
-
98
- private
99
- def get(url)
100
- Net::HTTP.get(URI.parse('http://0.0.0.0:3333' + url))
101
- end
102
-
103
- def raw(data)
104
- socket = TCPSocket.new('0.0.0.0', 3333)
105
- socket.write data
106
- out = socket.read
107
- socket.close
108
- out
109
- end
110
-
111
- def post(url, params={})
112
- Net::HTTP.post_form(URI.parse('http://0.0.0.0:3333' + url), params).body
113
- end
114
- end
115
-
116
- describe Server, 'app configuration' do
117
- it "should build app from constructor" do
118
- server = Server.new('0.0.0.0', 3000, :works)
119
-
120
- server.app.should == :works
121
- end
122
-
123
- it "should build app from builder block" do
124
- server = Server.new '0.0.0.0', 3000 do
125
- run(proc { |env| :works })
126
- end
127
-
128
- server.app.call({}).should == :works
129
- end
130
-
131
- it "should use middlewares in builder block" do
132
- server = Server.new '0.0.0.0', 3000 do
133
- use Rack::ShowExceptions
134
- run(proc { |env| :works })
135
- end
136
-
137
- server.app.class.should == Rack::ShowExceptions
138
- server.app.call({}).should == :works
139
- end
140
-
141
- it "should work with Rack url mapper" do
142
- server = Server.new '0.0.0.0', 3000 do
143
- map '/test' do
144
- run(proc { |env| :works })
145
- end
146
- end
147
-
148
- server.app.call({})[0].should == 404
149
- server.app.call({'PATH_INFO' => '/test'}).should == :works
150
- end
151
- end
152
-
153
- describe Server, "on UNIX domain socket" do
154
- before do
155
- app = proc do |env|
156
- [200, { 'Content-Type' => 'text/html' }, [env.inspect]]
157
- end
158
- @server = Thin::Server.new('/tmp/thin_test.sock', nil, app)
159
- @server.timeout = 3
160
- @server.silent = true
161
-
162
- @thread = Thread.new { @server.start }
163
- sleep 0.1 until @thread.status == 'sleep'
164
- end
165
-
166
- it "should accept GET request" do
167
- get("/?this").should include('this')
168
- end
169
-
170
- it "should retreive remote address" do
171
- get('/').should include('"REMOTE_ADDR"=>""') # Is that right?
172
- end
173
-
174
- it "should handle GET in less then #{get_request_time = 0.002} RubySecond" do
175
- proc { get('/') }.should be_faster_then(get_request_time)
176
- end
177
-
178
- it "should remove socket file after server stops" do
179
- @server.stop!
180
- File.exist?('/tmp/thin_test.sock').should be_false
181
- end
182
-
183
- after do
184
- @server.stop!
185
- @thread.kill
186
- end
187
-
188
- private
189
- def get(url)
190
- send_data("GET #{url} HTTP/1.1\r\n\r\n")
191
- end
192
-
193
- def send_data(data)
194
- socket = UNIXSocket.new('/tmp/thin_test.sock')
195
- socket.write data
196
- out = socket.read
197
- socket.close
198
- out
199
- end
200
- end