diff options
Diffstat (limited to 'lib/rack/server.rb')
-rw-r--r-- | lib/rack/server.rb | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/lib/rack/server.rb b/lib/rack/server.rb new file mode 100644 index 00000000..7d0705ad --- /dev/null +++ b/lib/rack/server.rb @@ -0,0 +1,212 @@ +require 'optparse' + +module Rack + class Server + class Options + def parse!(args) + options = {} + opt_parser = OptionParser.new("", 24, ' ') do |opts| + opts.banner = "Usage: rackup [ruby options] [rack options] [rackup config]" + + opts.separator "" + opts.separator "Ruby options:" + + lineno = 1 + opts.on("-e", "--eval LINE", "evaluate a LINE of code") { |line| + eval line, TOPLEVEL_BINDING, "-e", lineno + lineno += 1 + } + + opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") { + options[:debug] = true + } + opts.on("-w", "--warn", "turn warnings on for your script") { + options[:warn] = true + } + + opts.on("-I", "--include PATH", + "specify $LOAD_PATH (may be used more than once)") { |path| + options[:include] = path.split(":") + } + + opts.on("-r", "--require LIBRARY", + "require the library, before executing your script") { |library| + options[:require] = library + } + + opts.separator "" + opts.separator "Rack options:" + opts.on("-s", "--server SERVER", "serve using SERVER (webrick/mongrel)") { |s| + options[:server] = s + } + + opts.on("-o", "--host HOST", "listen on HOST (default: 0.0.0.0)") { |host| + options[:Host] = host + } + + opts.on("-p", "--port PORT", "use PORT (default: 9292)") { |port| + options[:Port] = port + } + + opts.on("-E", "--env ENVIRONMENT", "use ENVIRONMENT for defaults (default: development)") { |e| + options[:environment] = e + } + + opts.on("-D", "--daemonize", "run daemonized in the background") { |d| + options[:daemonize] = d ? true : false + } + + opts.on("-P", "--pid FILE", "file to store PID (default: rack.pid)") { |f| + options[:pid] = ::File.expand_path(f) + } + + opts.separator "" + opts.separator "Common options:" + + opts.on_tail("-h", "--help", "Show this message") do + puts opts + exit + end + + opts.on_tail("--version", "Show version") do + puts "Rack #{Rack.version}" + exit + end + end + opt_parser.parse! args + options[:rack_file] = args.last if args.last + options + end + end + + def self.start + new.start + end + + attr_accessor :options + + def initialize(options = nil) + @options = options + end + + def options + @options ||= parse_options(ARGV) + end + + def default_options + { + :environment => "development", + :pid => nil, + :Port => 9292, + :Host => "0.0.0.0", + :AccessLog => [], + :rack_file => ::File.expand_path("config.ru") + } + end + + def app + @app ||= begin + if !::File.exist? options[:rack_file] + abort "configuration #{options[:rack_file]} not found" + end + + app, options = Rack::Builder.parse_file(self.options[:rack_file], opt_parser) + self.options.merge! options + app + end + end + + def self.middleware + @middleware ||= begin + m = Hash.new {|h,k| h[k] = []} + m["deployment"].concat [lambda {|server| server.server =~ /CGI/ ? nil : [Rack::CommonLogger, $stderr] }] + m["development"].concat m["deployment"] + [[Rack::ShowExceptions], [Rack::Lint]] + m + end + end + + def middleware + self.class.middleware + end + + def start + if options[:debug] + $DEBUG = true + require 'pp' + p options[:server] + pp wrapped_app + pp app + end + + if options[:warn] + $-w = true + end + + if includes = options[:include] + $LOAD_PATH.unshift *includes + end + + if library = options[:require] + require library + end + + daemonize_app if options[:daemonize] + write_pid if options[:pid] + server.run wrapped_app, options + end + + def server + @_server ||= Rack::Handler.get(options[:server]) || Rack::Handler.default + end + + private + def parse_options(args) + options = default_options + + # Don't evaluate CGI ISINDEX parameters. + # http://hoohoo.ncsa.uiuc.edu/cgi/cl.html + args.clear if ENV.include?("REQUEST_METHOD") + + options.merge! opt_parser.parse! args + options + end + + def opt_parser + Options.new + end + + def build_app(app) + middleware[options[:environment]].reverse_each do |middleware| + middleware = middleware.call(self) if middleware.respond_to?(:call) + next unless middleware + klass = middleware.shift + app = klass.new(app, *middleware) + end + app + end + + def wrapped_app + @wrapped_app ||= build_app app + end + + def daemonize_app + if RUBY_VERSION < "1.9" + exit if fork + Process.setsid + exit if fork + Dir.chdir "/" + ::File.umask 0000 + STDIN.reopen "/dev/null" + STDOUT.reopen "/dev/null", "a" + STDERR.reopen "/dev/null", "a" + else + Process.daemon + end + end + + def write_pid + ::File.open(options[:pid], 'w'){ |f| f.write("#{Process.pid}") } + at_exit { ::File.delete(options[:pid]) if ::File.exist?(options[:pid]) } + end + end +end |