thin 1.8.2 → 2.0.0.pre
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.
- data/.gitignore +9 -0
- data/CHANGELOG +29 -116
- data/Gemfile +8 -0
- data/README.md +44 -78
- data/Rakefile +28 -18
- data/bin/thin +4 -4
- data/examples/async.ru +21 -0
- data/examples/thin.conf.rb +39 -0
- data/lib/thin/async.rb +108 -0
- data/lib/thin/backends/prefork.rb +44 -0
- data/lib/thin/backends/single_process.rb +28 -0
- data/lib/thin/chunked_body.rb +28 -0
- data/lib/thin/configurator.rb +118 -0
- data/lib/thin/connection.rb +246 -172
- data/lib/thin/listener.rb +114 -0
- data/lib/thin/request.rb +94 -76
- data/lib/thin/response.rb +112 -45
- data/lib/thin/runner.rb +134 -197
- data/lib/thin/server.rb +203 -252
- data/lib/thin/system.rb +49 -0
- data/lib/thin/version.rb +12 -27
- data/lib/thin.rb +2 -44
- data/man/index.txt +3 -0
- data/man/thin-conf.5.ronn +121 -0
- data/man/thin.1.ronn +105 -0
- data/site/.gitignore +2 -0
- data/site/README.md +21 -0
- data/site/Rakefile +20 -0
- data/site/config.ru +4 -0
- data/site/public/images/grid.png +0 -0
- data/site/public/javascripts/dd_belatedpng.js +13 -0
- data/site/public/javascripts/modernizr-1.6.min.js +30 -0
- data/site/public/man/thin-conf.5.html +220 -0
- data/site/public/man/thin.1.html +177 -0
- data/site/site/assets/javascripts/main.coffee +2 -0
- data/site/site/assets/stylesheets/_config.scss +55 -0
- data/site/site/assets/stylesheets/main.scss +24 -0
- data/site/site/helpers.rb +17 -0
- data/site/site/layouts/base.erb +55 -0
- data/site/site/layouts/default.erb +17 -0
- data/site/site/pages/about.md +5 -0
- data/site/site/pages/index.erb +10 -0
- data/site/site/partials/.gitkeep +0 -0
- data/test/fixtures/big.txt +1 -0
- data/test/fixtures/small.txt +1 -0
- data/test/fixtures/thin.conf.rb +15 -0
- data/test/integration/async_test.rb +35 -0
- data/test/integration/big_request_test.rb +30 -0
- data/test/integration/config.ru +57 -0
- data/test/integration/daemonize_test.rb +26 -0
- data/test/integration/env_test.rb +44 -0
- data/test/integration/error_test.rb +37 -0
- data/test/integration/file_sending_test.rb +24 -0
- data/test/integration/keep_alive_test.rb +35 -0
- data/test/integration/robustness_test.rb +37 -0
- data/test/integration/single_process_test.rb +15 -0
- data/test/integration/socket_family_test.rb +38 -0
- data/test/integration/worker_test.rb +22 -0
- data/test/test_helper.rb +195 -0
- data/test/unit/configurator_test.rb +43 -0
- data/test/unit/connection_test.rb +94 -0
- data/test/unit/listener_test.rb +74 -0
- data/test/unit/request_test.rb +74 -0
- data/test/unit/response_test.rb +90 -0
- data/test/unit/server_test.rb +29 -0
- data/test/unit/system_test.rb +17 -0
- data/thin.gemspec +26 -0
- data/v2.todo +21 -0
- metadata +138 -93
- checksums.yaml +0 -7
- data/example/adapter.rb +0 -32
- data/example/async_app.ru +0 -126
- data/example/async_chat.ru +0 -247
- data/example/async_tailer.ru +0 -100
- data/example/config.ru +0 -22
- data/example/monit_sockets +0 -20
- data/example/monit_unixsock +0 -20
- data/example/myapp.rb +0 -1
- data/example/ramaze.ru +0 -12
- data/example/thin.god +0 -80
- data/example/thin_solaris_smf.erb +0 -36
- data/example/thin_solaris_smf.readme.txt +0 -150
- data/example/vlad.rake +0 -72
- data/ext/thin_parser/common.rl +0 -59
- data/ext/thin_parser/ext_help.h +0 -14
- data/ext/thin_parser/extconf.rb +0 -6
- data/ext/thin_parser/parser.c +0 -1447
- data/ext/thin_parser/parser.h +0 -49
- data/ext/thin_parser/parser.rl +0 -152
- data/ext/thin_parser/thin.c +0 -435
- data/lib/rack/adapter/loader.rb +0 -75
- data/lib/rack/adapter/rails.rb +0 -178
- data/lib/rack/handler/thin.rb +0 -38
- data/lib/thin/backends/base.rb +0 -169
- data/lib/thin/backends/swiftiply_client.rb +0 -66
- data/lib/thin/backends/tcp_server.rb +0 -34
- data/lib/thin/backends/unix_server.rb +0 -56
- data/lib/thin/command.rb +0 -53
- data/lib/thin/controllers/cluster.rb +0 -178
- data/lib/thin/controllers/controller.rb +0 -189
- data/lib/thin/controllers/service.rb +0 -76
- data/lib/thin/controllers/service.sh.erb +0 -39
- data/lib/thin/daemonizing.rb +0 -199
- data/lib/thin/headers.rb +0 -47
- data/lib/thin/logging.rb +0 -174
- data/lib/thin/stats.html.erb +0 -216
- data/lib/thin/stats.rb +0 -52
- data/lib/thin/statuses.rb +0 -48
data/lib/thin/runner.rb
CHANGED
@@ -1,238 +1,175 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
|
4
|
-
require
|
1
|
+
require "optparse"
|
2
|
+
require "rack"
|
3
|
+
|
4
|
+
require "thin/configurator"
|
5
5
|
|
6
6
|
module Thin
|
7
|
-
#
|
8
|
-
# Parse options and send command to the correct Controller.
|
7
|
+
# Command line runner. Mimic Rack's +rackup+.
|
9
8
|
class Runner
|
10
|
-
|
11
|
-
|
9
|
+
class OptionsParser
|
10
|
+
def parse!(args)
|
11
|
+
options = {}
|
12
|
+
opt_parser = OptionParser.new("", 24, ' ') do |opts|
|
13
|
+
opts.banner = "Usage: thin [ruby options] [thin options] [rackup config]"
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
+
opts.separator ""
|
16
|
+
opts.separator "Ruby options:"
|
17
|
+
|
18
|
+
lineno = 1
|
19
|
+
opts.on("-e", "--eval LINE", "evaluate a LINE of code") { |line|
|
20
|
+
eval line, TOPLEVEL_BINDING, "-e", lineno
|
21
|
+
lineno += 1
|
22
|
+
}
|
23
|
+
|
24
|
+
opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") {
|
25
|
+
$DEBUG = true
|
26
|
+
}
|
27
|
+
opts.on("-w", "--warn", "turn warnings on for your script") {
|
28
|
+
$-w = true
|
29
|
+
}
|
30
|
+
|
31
|
+
opts.on("-I", "--include PATH",
|
32
|
+
"specify $LOAD_PATH (may be used more than once)") { |path|
|
33
|
+
$LOAD_PATH.unshift *path.split(":")
|
34
|
+
}
|
35
|
+
|
36
|
+
opts.on("-r", "--require LIBRARY",
|
37
|
+
"require the library, before executing your script") { |library|
|
38
|
+
require library
|
39
|
+
}
|
15
40
|
|
16
|
-
|
17
|
-
|
41
|
+
opts.separator ""
|
42
|
+
opts.separator "Thin options:"
|
18
43
|
|
19
|
-
|
20
|
-
|
44
|
+
opts.on("-o", "--host HOST", "bind to HOST") { |host|
|
45
|
+
options[:host] = host
|
46
|
+
}
|
21
47
|
|
22
|
-
|
23
|
-
|
48
|
+
opts.on("-p", "--port PORT", "use PORT (default: 9292)") { |port|
|
49
|
+
options[:port] = port
|
50
|
+
}
|
24
51
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
commands += LINUX_ONLY_COMMANDS if Thin.linux?
|
29
|
-
commands
|
30
|
-
end
|
52
|
+
opts.on("-E", "--env ENVIRONMENT", "use ENVIRONMENT for defaults (default: development)") { |e|
|
53
|
+
options[:environment] = e
|
54
|
+
}
|
31
55
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
# Default options values
|
36
|
-
@options = {
|
37
|
-
:chdir => Dir.pwd,
|
38
|
-
:environment => ENV['RACK_ENV'] || 'development',
|
39
|
-
:address => '0.0.0.0',
|
40
|
-
:port => Server::DEFAULT_PORT,
|
41
|
-
:timeout => Server::DEFAULT_TIMEOUT,
|
42
|
-
:log => File.join(Dir.pwd, 'log/thin.log'),
|
43
|
-
:pid => 'tmp/pids/thin.pid',
|
44
|
-
:max_conns => Server::DEFAULT_MAXIMUM_CONNECTIONS,
|
45
|
-
:max_persistent_conns => Server::DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS,
|
46
|
-
:require => [],
|
47
|
-
:wait => Controllers::Cluster::DEFAULT_WAIT_TIME,
|
48
|
-
:threadpool_size => 20
|
49
|
-
}
|
56
|
+
opts.on("-D", "--daemonize", "run daemonized in the background") { |d|
|
57
|
+
options[:daemonize] = d ? true : false
|
58
|
+
}
|
50
59
|
|
51
|
-
|
52
|
-
|
60
|
+
opts.on("-P", "--pid FILE", "file to store PID (default: thin.pid)") { |f|
|
61
|
+
options[:pid] = ::File.expand_path(f)
|
62
|
+
}
|
53
63
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
# +option+ keys are used to build the command line to launch other processes,
|
58
|
-
# see <tt>lib/thin/command.rb</tt>.
|
59
|
-
@parser ||= OptionParser.new do |opts|
|
60
|
-
opts.banner = "Usage: thin [options] #{self.class.commands.join('|')}"
|
61
|
-
|
62
|
-
opts.separator ""
|
63
|
-
opts.separator "Server options:"
|
64
|
-
|
65
|
-
opts.on("-a", "--address HOST", "bind to HOST address " +
|
66
|
-
"(default: #{@options[:address]})") { |host| @options[:address] = host }
|
67
|
-
opts.on("-p", "--port PORT", "use PORT (default: #{@options[:port]})") { |port| @options[:port] = port.to_i }
|
68
|
-
opts.on("-S", "--socket FILE", "bind to unix domain socket") { |file| @options[:socket] = file }
|
69
|
-
opts.on("-y", "--swiftiply [KEY]", "Run using swiftiply") { |key| @options[:swiftiply] = key }
|
70
|
-
opts.on("-A", "--adapter NAME", "Rack adapter to use (default: autodetect)",
|
71
|
-
"(#{Rack::ADAPTERS.map{|(a,b)|a}.join(', ')})") { |name| @options[:adapter] = name }
|
72
|
-
opts.on("-R", "--rackup FILE", "Load a Rack config file instead of " +
|
73
|
-
"Rack adapter") { |file| @options[:rackup] = file }
|
74
|
-
opts.on("-c", "--chdir DIR", "Change to dir before starting") { |dir| @options[:chdir] = File.expand_path(dir) }
|
75
|
-
opts.on( "--stats PATH", "Mount the Stats adapter under PATH") { |path| @options[:stats] = path }
|
76
|
-
|
77
|
-
opts.separator ""
|
78
|
-
opts.separator "SSL options:"
|
79
|
-
|
80
|
-
opts.on( "--ssl", "Enables SSL") { @options[:ssl] = true }
|
81
|
-
opts.on( "--ssl-key-file PATH", "Path to private key") { |path| @options[:ssl_key_file] = path }
|
82
|
-
opts.on( "--ssl-cert-file PATH", "Path to certificate") { |path| @options[:ssl_cert_file] = path }
|
83
|
-
opts.on( "--ssl-disable-verify", "Disables (optional) client cert requests") { @options[:ssl_disable_verify] = true }
|
84
|
-
opts.on( "--ssl-version VERSION", "TLSv1, TLSv1_1, TLSv1_2") { |version| @options[:ssl_version] = version }
|
85
|
-
opts.on( "--ssl-cipher-list STRING", "Example: HIGH:!ADH:!RC4:-MEDIUM:-LOW:-EXP:-CAMELLIA") { |cipher| @options[:ssl_cipher_list] = cipher }
|
86
|
-
|
87
|
-
opts.separator ""
|
88
|
-
opts.separator "Adapter options:"
|
89
|
-
opts.on("-e", "--environment ENV", "Framework environment " +
|
90
|
-
"(default: #{@options[:environment]})") { |env| @options[:environment] = env }
|
91
|
-
opts.on( "--prefix PATH", "Mount the app under PATH (start with /)") { |path| @options[:prefix] = path }
|
92
|
-
|
93
|
-
unless Thin.win? # Daemonizing not supported on Windows
|
94
|
-
opts.separator ""
|
95
|
-
opts.separator "Daemon options:"
|
64
|
+
opts.on("-l", "--log FILE", "file to log to (default: stdout)") { |f|
|
65
|
+
options[:log] = ::File.expand_path(f)
|
66
|
+
}
|
96
67
|
|
97
|
-
opts.on("-
|
98
|
-
|
99
|
-
|
100
|
-
opts.on("-P", "--pid FILE", "File to store PID " +
|
101
|
-
"(default: #{@options[:pid]})") { |file| @options[:pid] = file }
|
102
|
-
opts.on("-u", "--user NAME", "User to run daemon as (use with -g)") { |user| @options[:user] = user }
|
103
|
-
opts.on("-g", "--group NAME", "Group to run daemon as (use with -u)") { |group| @options[:group] = group }
|
104
|
-
opts.on( "--tag NAME", "Additional text to display in process listing") { |tag| @options[:tag] = tag }
|
68
|
+
opts.on("-c", "--config FILE", "Thin configuration file.") { |file|
|
69
|
+
options[:thin_config] = file
|
70
|
+
}
|
105
71
|
|
106
72
|
opts.separator ""
|
107
|
-
opts.separator "
|
108
|
-
|
109
|
-
opts.
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
opts.
|
73
|
+
opts.separator "Common options:"
|
74
|
+
|
75
|
+
opts.on_tail("-h", "-?", "--help", "Show this message") do
|
76
|
+
puts opts
|
77
|
+
exit
|
78
|
+
end
|
79
|
+
|
80
|
+
opts.on_tail("--version", "Show version") do
|
81
|
+
puts Thin::SERVER
|
82
|
+
exit
|
83
|
+
end
|
115
84
|
end
|
116
85
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
opts.on("-f", "--force", "Force the execution of the command") { @options[:force] = true }
|
124
|
-
opts.on( "--max-conns NUM", "Maximum number of open file descriptors " +
|
125
|
-
"(default: #{@options[:max_conns]})",
|
126
|
-
"Might require sudo to set higher than 1024") { |num| @options[:max_conns] = num.to_i } unless Thin.win?
|
127
|
-
opts.on( "--max-persistent-conns NUM",
|
128
|
-
"Maximum number of persistent connections",
|
129
|
-
"(default: #{@options[:max_persistent_conns]})") { |num| @options[:max_persistent_conns] = num.to_i }
|
130
|
-
opts.on( "--threaded", "Call the Rack application in threads " +
|
131
|
-
"[experimental]") { @options[:threaded] = true }
|
132
|
-
opts.on( "--threadpool-size NUM", "Sets the size of the EventMachine threadpool.",
|
133
|
-
"(default: #{@options[:threadpool_size]})") { |num| @options[:threadpool_size] = num.to_i }
|
134
|
-
opts.on( "--no-epoll", "Disable the use of epoll") { @options[:no_epoll] = true } if Thin.linux?
|
135
|
-
|
136
|
-
opts.separator ""
|
137
|
-
opts.separator "Common options:"
|
138
|
-
|
139
|
-
opts.on_tail("-r", "--require FILE", "require the library") { |file| @options[:require] << file }
|
140
|
-
opts.on_tail("-q", "--quiet", "Silence all logging") { @options[:quiet] = true }
|
141
|
-
opts.on_tail("-D", "--debug", "Enable debug logging") { @options[:debug] = true }
|
142
|
-
opts.on_tail("-V", "--trace", "Set tracing on (log raw request/response)") { @options[:trace] = true }
|
143
|
-
opts.on_tail("-h", "--help", "Show this message") { puts opts; exit }
|
144
|
-
opts.on_tail('-v', '--version', "Show version") { puts Thin::SERVER; exit }
|
145
|
-
end
|
146
|
-
end
|
86
|
+
begin
|
87
|
+
opt_parser.parse! args
|
88
|
+
rescue OptionParser::InvalidOption => e
|
89
|
+
warn e.message
|
90
|
+
abort opt_parser.to_s
|
91
|
+
end
|
147
92
|
|
148
|
-
|
149
|
-
def parse!
|
150
|
-
parser.parse! @argv
|
151
|
-
@command = @argv.shift
|
152
|
-
@arguments = @argv
|
153
|
-
end
|
93
|
+
options[:config] = args.last if args.last
|
154
94
|
|
155
|
-
|
156
|
-
# Exits on error.
|
157
|
-
def run!
|
158
|
-
if self.class.commands.include?(@command)
|
159
|
-
run_command
|
160
|
-
elsif @command.nil?
|
161
|
-
puts "Command required"
|
162
|
-
puts @parser
|
163
|
-
exit 1
|
164
|
-
else
|
165
|
-
abort "Unknown command: #{@command}. Use one of #{self.class.commands.join(', ')}"
|
95
|
+
options
|
166
96
|
end
|
167
97
|
end
|
168
98
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
99
|
+
def default_options
|
100
|
+
{
|
101
|
+
:environment => ENV['RACK_ENV'] || "development",
|
102
|
+
:port => 9292,
|
103
|
+
:config => "config.ru"
|
104
|
+
}
|
105
|
+
end
|
176
106
|
|
177
|
-
|
178
|
-
|
179
|
-
Dir.chdir(@options[:chdir]) unless CONFIGLESS_COMMANDS.include?(@command)
|
107
|
+
def run(args)
|
108
|
+
options = default_options.dup
|
180
109
|
|
181
|
-
|
110
|
+
parser = OptionsParser.new
|
111
|
+
options.update parser.parse!(args)
|
182
112
|
|
183
|
-
#
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
Logging.level = Logger::DEBUG if @options[:debug]
|
113
|
+
# Parse in file options like rackup
|
114
|
+
shebang = File.open(options[:config]) { |f| f.readline }
|
115
|
+
if shebang[/^#\\(.*)/]
|
116
|
+
options.update parser.parse! $1.split(/\s+/)
|
188
117
|
end
|
189
118
|
|
190
|
-
|
191
|
-
|
192
|
-
|
119
|
+
ENV["RACK_ENV"] = options[:environment]
|
120
|
+
options[:config] = ::File.expand_path(options[:config])
|
121
|
+
|
122
|
+
# Configure the server
|
123
|
+
server = Server.new do
|
124
|
+
# This is passed as a block so it can be loaded inside workers if preload_app disabled.
|
125
|
+
build_app(options[:config], options[:environment])
|
193
126
|
end
|
194
127
|
|
195
|
-
|
196
|
-
|
197
|
-
when service? then Controllers::Service.new(@options)
|
198
|
-
else Controllers::Controller.new(@options)
|
128
|
+
if options[:thin_config]
|
129
|
+
Configurator.load(options[:thin_config]).apply(server)
|
199
130
|
end
|
200
131
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
rescue RunnerError => e
|
205
|
-
abort e.message
|
206
|
-
end
|
207
|
-
else
|
208
|
-
abort "Invalid options for command: #{@command}"
|
132
|
+
# If no listeners yet, use the one from the options
|
133
|
+
if !options.has_key?(:thin_config) || server.listeners.empty?
|
134
|
+
server.listen [options[:host], options[:port]].compact.join(":")
|
209
135
|
end
|
210
|
-
end
|
211
136
|
|
212
|
-
|
213
|
-
|
214
|
-
|
137
|
+
server.pid_path = options[:pid] if options[:pid]
|
138
|
+
server.log_path = options[:log] if options[:log]
|
139
|
+
server.worker_processes = options[:workers] if options[:workers]
|
140
|
+
server.timeout = options[:timeout] if options[:timeout]
|
141
|
+
|
142
|
+
# Start the server
|
143
|
+
server.start(options[:daemonize])
|
215
144
|
end
|
216
145
|
|
217
|
-
|
218
|
-
|
219
|
-
@options.has_key?(:all) || @command == 'install'
|
146
|
+
def self.run(args)
|
147
|
+
new.run(args)
|
220
148
|
end
|
221
149
|
|
222
150
|
private
|
223
|
-
def
|
224
|
-
|
225
|
-
|
226
|
-
|
151
|
+
def build_app(config, environment)
|
152
|
+
inner_app = Rack::Builder.parse_file(config).first
|
153
|
+
|
154
|
+
Rack::Builder.new do
|
155
|
+
case environment
|
156
|
+
when "development"
|
157
|
+
use Rack::ContentLength
|
158
|
+
use Rack::Chunked
|
159
|
+
use Rack::CommonLogger
|
160
|
+
use Rack::ShowExceptions
|
161
|
+
use Rack::Lint
|
162
|
+
|
163
|
+
when "deployment"
|
164
|
+
use Rack::ContentLength
|
165
|
+
use Rack::Chunked
|
166
|
+
use Rack::CommonLogger
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
run inner_app
|
171
|
+
end.to_app
|
227
172
|
end
|
228
173
|
|
229
|
-
def ruby_require(file)
|
230
|
-
if File.extname(file) == '.ru'
|
231
|
-
warn 'WARNING: Use the -R option to load a Rack config file'
|
232
|
-
@options[:rackup] = file
|
233
|
-
else
|
234
|
-
require file
|
235
|
-
end
|
236
|
-
end
|
237
174
|
end
|
238
175
|
end
|