2006-06-30 16:42:12 -04:00
|
|
|
# Copyright (c) 2005 Zed A. Shaw
|
|
|
|
# You can redistribute it and/or modify it under the same terms as Ruby.
|
|
|
|
#
|
|
|
|
# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
|
|
|
|
# for more information.
|
2006-05-21 10:46:42 -04:00
|
|
|
|
2006-02-28 02:04:41 -05:00
|
|
|
require 'mongrel'
|
2006-03-07 19:52:20 -05:00
|
|
|
require 'cgi'
|
|
|
|
|
2006-08-22 02:01:35 -04:00
|
|
|
|
2006-03-26 15:01:50 -05:00
|
|
|
module Mongrel
|
|
|
|
module Rails
|
2006-03-27 01:10:07 -05:00
|
|
|
# Implements a handler that can run Rails and serve files out of the
|
|
|
|
# Rails application's public directory. This lets you run your Rails
|
|
|
|
# application with Mongrel during development and testing, then use it
|
|
|
|
# also in production behind a server that's better at serving the
|
|
|
|
# static files.
|
|
|
|
#
|
|
|
|
# The RailsHandler takes a mime_map parameter which is a simple suffix=mimetype
|
|
|
|
# mapping that it should add to the list of valid mime types.
|
|
|
|
#
|
|
|
|
# It also supports page caching directly and will try to resolve a request
|
|
|
|
# in the following order:
|
|
|
|
#
|
|
|
|
# * If the requested exact PATH_INFO exists as a file then serve it.
|
|
|
|
# * If it exists at PATH_INFO+".html" exists then serve that.
|
2006-05-20 17:21:29 -04:00
|
|
|
# * Finally, construct a Mongrel::CGIWrapper and run Dispatcher.dispatch to have Rails go.
|
2006-03-27 01:10:07 -05:00
|
|
|
#
|
|
|
|
# This means that if you are using page caching it will actually work with Mongrel
|
2006-09-26 17:25:44 -04:00
|
|
|
# and you should see a decent speed boost (but not as fast as if you use a static
|
|
|
|
# server like Apache or Litespeed).
|
2006-03-27 01:10:07 -05:00
|
|
|
class RailsHandler < Mongrel::HttpHandler
|
|
|
|
attr_reader :files
|
|
|
|
attr_reader :guard
|
2006-06-05 05:35:34 -04:00
|
|
|
@@file_only_methods = ["GET","HEAD"]
|
2006-05-19 22:56:30 -04:00
|
|
|
|
2006-03-27 01:10:07 -05:00
|
|
|
def initialize(dir, mime_map = {})
|
|
|
|
@files = Mongrel::DirHandler.new(dir,false)
|
2006-11-20 11:52:24 -05:00
|
|
|
@guard = Mutex.new
|
2006-05-19 22:56:30 -04:00
|
|
|
|
2006-09-26 17:25:44 -04:00
|
|
|
# Register the requested MIME types
|
2006-03-27 01:10:07 -05:00
|
|
|
mime_map.each {|k,v| Mongrel::DirHandler::add_mime_type(k,v) }
|
|
|
|
end
|
2006-05-19 22:56:30 -04:00
|
|
|
|
2006-03-27 01:10:07 -05:00
|
|
|
# Attempts to resolve the request as follows:
|
|
|
|
#
|
|
|
|
# * If the requested exact PATH_INFO exists as a file then serve it.
|
|
|
|
# * If it exists at PATH_INFO+".html" exists then serve that.
|
2006-05-20 17:21:29 -04:00
|
|
|
# * Finally, construct a Mongrel::CGIWrapper and run Dispatcher.dispatch to have Rails go.
|
2006-03-27 01:10:07 -05:00
|
|
|
def process(request, response)
|
2007-10-15 14:24:08 -04:00
|
|
|
return if response.socket.closed?
|
|
|
|
|
|
|
|
path_info = request.params[Mongrel::Const::PATH_INFO]
|
2007-10-15 14:27:15 -04:00
|
|
|
rest_operator = request.params[Mongrel::Const::REQUEST_URI][/^#{Regexp.escape path_info}(;[^\?]+)/, 1].to_s
|
2007-10-15 14:24:08 -04:00
|
|
|
path_info.chomp!("/")
|
|
|
|
|
2007-10-15 14:27:15 -04:00
|
|
|
page_cached = path_info + rest_operator + ActionController::Base.page_cache_extension
|
2006-06-05 05:35:34 -04:00
|
|
|
get_or_head = @@file_only_methods.include? request.params[Mongrel::Const::REQUEST_METHOD]
|
2006-05-19 22:56:30 -04:00
|
|
|
|
2006-06-05 05:35:34 -04:00
|
|
|
if get_or_head and @files.can_serve(path_info)
|
2006-05-19 22:56:30 -04:00
|
|
|
# File exists as-is so serve it up
|
2006-03-27 01:10:07 -05:00
|
|
|
@files.process(request,response)
|
2006-06-05 05:35:34 -04:00
|
|
|
elsif get_or_head and @files.can_serve(page_cached)
|
2006-09-26 17:25:44 -04:00
|
|
|
# Possible cached page, serve it up
|
2006-03-27 01:10:07 -05:00
|
|
|
request.params[Mongrel::Const::PATH_INFO] = page_cached
|
|
|
|
@files.process(request,response)
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
cgi = Mongrel::CGIWrapper.new(request, response)
|
|
|
|
cgi.handler = self
|
2006-09-26 17:25:44 -04:00
|
|
|
# We don't want the output to be really final until we're out of the lock
|
2006-08-12 15:47:22 -04:00
|
|
|
cgi.default_really_final = false
|
2006-08-12 15:01:06 -04:00
|
|
|
|
2006-11-15 17:16:44 -05:00
|
|
|
@guard.synchronize {
|
2007-03-10 04:47:08 -05:00
|
|
|
@active_request_path = request.params[Mongrel::Const::PATH_INFO]
|
2006-08-25 23:05:05 -04:00
|
|
|
Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, response.body)
|
2006-09-22 04:16:54 -04:00
|
|
|
@active_request_path = nil
|
2006-08-25 23:05:05 -04:00
|
|
|
}
|
2006-08-12 15:01:06 -04:00
|
|
|
|
2006-03-27 01:10:07 -05:00
|
|
|
# This finalizes the output using the proper HttpResponse way
|
2006-08-12 19:12:46 -04:00
|
|
|
cgi.out("text/html",true) {""}
|
2006-03-27 01:10:07 -05:00
|
|
|
rescue Errno::EPIPE
|
2006-09-03 15:47:53 -04:00
|
|
|
response.socket.close
|
2006-03-27 01:10:07 -05:00
|
|
|
rescue Object => rails_error
|
2006-08-03 16:49:11 -04:00
|
|
|
STDERR.puts "#{Time.now}: Error calling Dispatcher.dispatch #{rails_error.inspect}"
|
2006-03-27 01:10:07 -05:00
|
|
|
STDERR.puts rails_error.backtrace.join("\n")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2006-05-19 22:56:30 -04:00
|
|
|
|
2006-03-27 01:10:07 -05:00
|
|
|
# Does the internal reload for Rails. It might work for most cases, but
|
|
|
|
# sometimes you get exceptions. In that case just do a real restart.
|
|
|
|
def reload!
|
2006-08-12 15:10:57 -04:00
|
|
|
begin
|
2006-11-15 17:16:44 -05:00
|
|
|
@guard.synchronize {
|
2006-08-25 23:05:05 -04:00
|
|
|
$".replace $orig_dollar_quote
|
|
|
|
GC.start
|
|
|
|
Dispatcher.reset_application!
|
|
|
|
ActionController::Routing::Routes.reload
|
|
|
|
}
|
2006-03-27 01:10:07 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2006-03-26 15:01:50 -05:00
|
|
|
# Creates Rails specific configuration options for people to use
|
|
|
|
# instead of the base Configurator.
|
|
|
|
class RailsConfigurator < Mongrel::Configurator
|
2006-05-19 22:56:30 -04:00
|
|
|
|
2006-03-26 15:01:50 -05:00
|
|
|
# Creates a single rails handler and returns it so you
|
2006-09-26 17:25:44 -04:00
|
|
|
# can add it to a URI. You can actually attach it to
|
2006-03-26 15:01:50 -05:00
|
|
|
# as many URIs as you want, but this returns the
|
|
|
|
# same RailsHandler for each call.
|
|
|
|
#
|
|
|
|
# Requires the following options:
|
|
|
|
#
|
|
|
|
# * :docroot => The public dir to serve from.
|
|
|
|
# * :environment => Rails environment to use.
|
2006-03-27 21:56:33 -05:00
|
|
|
# * :cwd => The change to working directory
|
2006-03-26 15:01:50 -05:00
|
|
|
#
|
|
|
|
# And understands the following optional settings:
|
|
|
|
#
|
|
|
|
# * :mime => A map of mime types.
|
|
|
|
#
|
|
|
|
# Because of how Rails is designed you can only have
|
|
|
|
# one installed per Ruby interpreter (talk to them
|
|
|
|
# about thread safety). Because of this the first
|
|
|
|
# time you call this function it does all the config
|
2006-09-26 17:25:44 -04:00
|
|
|
# needed to get your Rails working. After that
|
2006-03-26 15:01:50 -05:00
|
|
|
# it returns the one handler you've configured.
|
2006-09-26 17:25:44 -04:00
|
|
|
# This lets you attach Rails to any URI(s) you want,
|
|
|
|
# but it still protects you from threads destroying
|
2006-03-26 15:01:50 -05:00
|
|
|
# your handler.
|
|
|
|
def rails(options={})
|
2006-05-19 22:56:30 -04:00
|
|
|
|
2006-03-26 15:01:50 -05:00
|
|
|
return @rails_handler if @rails_handler
|
2006-05-19 22:56:30 -04:00
|
|
|
|
2006-03-26 15:01:50 -05:00
|
|
|
ops = resolve_defaults(options)
|
2006-05-19 22:56:30 -04:00
|
|
|
|
2006-03-26 15:01:50 -05:00
|
|
|
# fix up some defaults
|
|
|
|
ops[:environment] ||= "development"
|
|
|
|
ops[:docroot] ||= "public"
|
|
|
|
ops[:mime] ||= {}
|
2006-05-19 22:56:30 -04:00
|
|
|
|
2006-03-26 15:01:50 -05:00
|
|
|
$orig_dollar_quote = $".clone
|
|
|
|
ENV['RAILS_ENV'] = ops[:environment]
|
2006-04-03 11:22:17 -04:00
|
|
|
env_location = "#{ops[:cwd]}/config/environment"
|
|
|
|
require env_location
|
2006-03-26 15:01:50 -05:00
|
|
|
require 'dispatcher'
|
|
|
|
require 'mongrel/rails'
|
2006-05-19 22:56:30 -04:00
|
|
|
|
2006-07-14 12:13:51 -04:00
|
|
|
ActionController::AbstractRequest.relative_url_root = ops[:prefix] if ops[:prefix]
|
2006-07-13 18:34:59 -04:00
|
|
|
|
2006-03-26 15:01:50 -05:00
|
|
|
@rails_handler = RailsHandler.new(ops[:docroot], ops[:mime])
|
|
|
|
end
|
2006-05-19 22:56:30 -04:00
|
|
|
|
2006-09-26 17:25:44 -04:00
|
|
|
# Reloads Rails. This isn't too reliable really, but it
|
|
|
|
# should work for most minimal reload purposes. The only reliable
|
|
|
|
# way to reload properly is to stop and then start the process.
|
2006-03-26 15:01:50 -05:00
|
|
|
def reload!
|
|
|
|
if not @rails_handler
|
|
|
|
raise "Rails was not configured. Read the docs for RailsConfigurator."
|
2006-02-28 02:04:41 -05:00
|
|
|
end
|
2006-05-19 22:56:30 -04:00
|
|
|
|
2006-09-26 17:25:44 -04:00
|
|
|
log "Reloading Rails..."
|
2006-03-26 15:01:50 -05:00
|
|
|
@rails_handler.reload!
|
2006-09-26 17:25:44 -04:00
|
|
|
log "Done reloading Rails."
|
2006-05-19 22:56:30 -04:00
|
|
|
|
2006-02-28 02:04:41 -05:00
|
|
|
end
|
2006-05-19 22:56:30 -04:00
|
|
|
|
2006-03-26 15:01:50 -05:00
|
|
|
# Takes the exact same configuration as Mongrel::Configurator (and actually calls that)
|
|
|
|
# but sets up the additional HUP handler to call reload!.
|
|
|
|
def setup_rails_signals(options={})
|
|
|
|
ops = resolve_defaults(options)
|
2006-05-20 03:56:38 -04:00
|
|
|
setup_signals(options)
|
2006-06-05 05:35:34 -04:00
|
|
|
|
2010-04-28 01:34:31 -04:00
|
|
|
unless RbConfig::CONFIG['host_os'] =~ /mingw|mswin/
|
2006-03-26 15:01:50 -05:00
|
|
|
# rails reload
|
2006-05-19 22:56:30 -04:00
|
|
|
trap("HUP") { log "HUP signal received."; reload! }
|
|
|
|
|
2006-03-26 15:01:50 -05:00
|
|
|
log "Rails signals registered. HUP => reload (without restart). It might not work well."
|
|
|
|
end
|
|
|
|
end
|
2006-03-25 16:15:30 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|