This repository has been archived by the owner on Sep 10, 2021. It is now read-only.
forked from macournoyer/thin
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Rails adapter and command line script
- Loading branch information
1 parent
3f05ea8
commit 4baf38c
Showing
4 changed files
with
229 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
#!/usr/bin/env ruby | ||
require File.dirname(__FILE__) + '/../lib/thin' | ||
require 'optparse' | ||
|
||
options = { | ||
:root => Dir.pwd, | ||
:env => 'development', | ||
:host => '0.0.0.0', | ||
:port => 3000, | ||
:timeout => 60, | ||
:log_file => 'log/thin.log', | ||
:pid_file => 'tmp/pids/thin.pid' | ||
} | ||
|
||
opts = OptionParser.new do |opts| | ||
opts.banner = "Usage: thin [options] start|stop" | ||
|
||
opts.separator "" | ||
opts.separator "Server options:" | ||
|
||
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: 3000)") { |port| options[:port] = port } | ||
opts.on("-e", "--env ENV", "Rails environment (default: development)") { |env| options[:env] = env } | ||
opts.on("-c", "--chdir PATH", "listen on HOST (default: current dir)") { |dir| options[:root] = dir } | ||
opts.on("-d", "--daemonize", "Daemonize") { options[:daemonize] = true } | ||
opts.on("-l", "--log-file FILE", "File to redirect output", | ||
"(default: #{options[:log_file]})") { |file| options[:log_file] = file } | ||
opts.on("-P", "--pid-file FILE", "File to store PID", | ||
"(default: #{options[:pid_file]})") { |file| options[:pid_file] = file } | ||
opts.on("-t", "--timeout SEC", "Request or command timeout in sec", | ||
"(default: #{options[:timeout]})") { |sec| options[:timeout] = sec } | ||
opts.on("-u", "--user NAME", "User to run daemon as (use with -g)") { |user| options[:user] = user } | ||
opts.on("-g", "--group NAME", "Group to run daemon as (use with -u)") { |group| options[:group] = group } | ||
|
||
opts.separator "" | ||
opts.separator "Common options:" | ||
|
||
opts.on_tail("-h", "--help", "Show this message") do | ||
puts opts | ||
exit | ||
end | ||
|
||
opts.on_tail('-v', '--version', "Show version") do | ||
puts Thin::NAME | ||
exit | ||
end | ||
|
||
opts.parse! ARGV | ||
end | ||
|
||
case ARGV[0] | ||
|
||
when 'start' | ||
app = Rack::Adapter::Rails.new(options) | ||
server = Thin::Server.new(options[:host], options[:port], app) | ||
|
||
server.pid_file = options[:pid_file] | ||
server.log_file = options[:log_file] | ||
server.timeout = options[:timeout] | ||
|
||
if options[:daemonize] | ||
server.change_privilege options[:user], options[:group] if options[:user] && options[:group] | ||
server.daemonize | ||
end | ||
|
||
server.start! | ||
|
||
when 'stop' | ||
Thin::Server.kill options[:pid_file], options[:timeout] | ||
|
||
when nil | ||
puts "Command required" | ||
puts opts | ||
exit 1 | ||
|
||
else | ||
abort "Invalid command : #{ARGV[0]}" | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
# This as been submitted to Rack as a patch, tested and everything. | ||
# Bug Christian Neukirchen at chneukirchen@gmail.com to apply the patch! | ||
|
||
require 'cgi' | ||
|
||
# Adapter to run a Rails app with any supported Rack handler. | ||
# By default it will try to load the Rails application in the | ||
# current directory in the development environment. | ||
# Options: | ||
# root: Root directory of the Rails app | ||
# env: Rails environment to run in (development, production or test) | ||
# Based on http://fuzed.rubyforge.org/ Rails adapter | ||
module Rack | ||
module Adapter | ||
class Rails | ||
def initialize(options={}) | ||
@root = options[:root] || Dir.pwd | ||
@env = options[:env] || 'development' | ||
|
||
load_application | ||
|
||
@file_server = Rack::File.new(::File.join(RAILS_ROOT, "public")) | ||
end | ||
|
||
def load_application | ||
ENV['RAILS_ENV'] = @env | ||
|
||
require "#{@root}/config/environment" | ||
require 'dispatcher' | ||
end | ||
|
||
# TODO refactor this in File#can_serve?(path) ?? | ||
def file?(path) | ||
full_path = ::File.join(@file_server.root, Utils.unescape(path)) | ||
::File.file?(full_path) && ::File.readable?(full_path) | ||
end | ||
|
||
def call(env) | ||
# Serve the file if it's there | ||
return @file_server.call(env) if file?(env['PATH_INFO']) | ||
|
||
request = Request.new(env) | ||
response = Response.new | ||
|
||
session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS | ||
cgi = CGIWrapper.new(request, response) | ||
|
||
Dispatcher.dispatch(cgi, session_options, response) | ||
|
||
response.finish | ||
end | ||
|
||
protected | ||
|
||
class CGIWrapper < ::CGI | ||
def initialize(request, response, *args) | ||
@request = request | ||
@response = response | ||
@args = *args | ||
@input = request.body | ||
|
||
super *args | ||
end | ||
|
||
def header(options = "text/html") | ||
if options.is_a?(String) | ||
@response['Content-Type'] = options unless @response['Content-Type'] | ||
else | ||
@response['Content-Length'] = options.delete('Content-Length').to_s if options['Content-Length'] | ||
|
||
@response['Content-Type'] = options.delete('type') || "text/html" | ||
@response['Content-Type'] += "; charset=" + options.delete('charset') if options['charset'] | ||
|
||
@response['Content-Language'] = options.delete('language') if options['language'] | ||
@response['Expires'] = options.delete('expires') if options['expires'] | ||
|
||
@response.status = options.delete('Status') if options['Status'] | ||
|
||
options.each { |k,v| @response[k] = v } | ||
|
||
# Convert 'cookie' header to 'Set-Cookie' headers. | ||
# According to http://www.faqs.org/rfcs/rfc2109.html: | ||
# the Set-Cookie response header comprises the token | ||
# Set-Cookie:, followed by a comma-separated list of | ||
# one or more cookies. | ||
if cookie = @response.header.delete('Cookie') | ||
cookies = case cookie | ||
when Array then cookie.collect { |c| c.to_s }.join(', ') | ||
when Hash then cookie.collect { |_, c| c.to_s }.join(', ') | ||
else cookie.to_s | ||
end | ||
|
||
cookies << ', ' + @output_cookies.each { |c| c.to_s }.join(', ') if @output_cookies | ||
|
||
@response['Set-Cookie'] = cookies | ||
end | ||
end | ||
|
||
"" | ||
end | ||
|
||
def params | ||
@params ||= @request.params | ||
end | ||
|
||
def cookies | ||
@request.cookies | ||
end | ||
|
||
def query_string | ||
@request.query_string | ||
end | ||
|
||
# Used to wrap the normal args variable used inside CGI. | ||
def args | ||
@args | ||
end | ||
|
||
# Used to wrap the normal env_table variable used inside CGI. | ||
def env_table | ||
@request.env | ||
end | ||
|
||
# Used to wrap the normal stdinput variable used inside CGI. | ||
def stdinput | ||
@input | ||
end | ||
|
||
def stdoutput | ||
STDERR.puts "stdoutput should not be used." | ||
@response.body | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters