mirror of
https://github.com/github/rails.git
synced 2026-01-13 16:48:06 -05:00
Compare commits
35 Commits
CVE-2013-6
...
github35
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3766b1b377 | ||
|
|
d3f87776a3 | ||
|
|
18c7c1f753 | ||
|
|
f63b0340ff | ||
|
|
7224ee1419 | ||
|
|
0c52ae6df3 | ||
|
|
f8b7cd2df7 | ||
|
|
c73ba86136 | ||
|
|
98fa5dd465 | ||
|
|
fa41bedf6b | ||
|
|
0a8282c557 | ||
|
|
d4a4facfcc | ||
|
|
dd4146854a | ||
|
|
cedf026a14 | ||
|
|
7ac3b0fa4f | ||
|
|
31cd7ea26d | ||
|
|
df387ab385 | ||
|
|
0118959601 | ||
|
|
83448c7de5 | ||
|
|
8f99d00868 | ||
|
|
987b61bd1d | ||
|
|
f05e54a9f3 | ||
|
|
b9918117bb | ||
|
|
42f85d118d | ||
|
|
acb182d094 | ||
|
|
6e0fcb788d | ||
|
|
fed4fafa8a | ||
|
|
f699184047 | ||
|
|
55d6a9f2df | ||
|
|
e5bebc01a8 | ||
|
|
a019f07a39 | ||
|
|
d13866d75d | ||
|
|
dfa2f469a4 | ||
|
|
bf0d43bb77 | ||
|
|
72cebbcb59 |
@@ -1 +1 @@
|
||||
2.3.14.github31
|
||||
2.3.14.github35
|
||||
|
||||
@@ -38,7 +38,7 @@ module ActionController
|
||||
# TODO: Review explicit to see if they will automatically be handled by
|
||||
# the initilizer if they are really needed.
|
||||
def self.load_all!
|
||||
[Base, CGIHandler, CgiRequest, Request, Response, Http::Headers, UrlRewriter, UrlWriter]
|
||||
[Base, Request, Response, Http::Headers, UrlRewriter, UrlWriter]
|
||||
end
|
||||
|
||||
autoload :Base, 'action_controller/base'
|
||||
@@ -99,10 +99,6 @@ module ActionController
|
||||
autoload :CookieStore, 'action_controller/session/cookie_store'
|
||||
autoload :MemCacheStore, 'action_controller/session/mem_cache_store'
|
||||
end
|
||||
|
||||
# DEPRECATE: Remove CGI support
|
||||
autoload :CgiRequest, 'action_controller/cgi_process'
|
||||
autoload :CGIHandler, 'action_controller/cgi_process'
|
||||
end
|
||||
|
||||
autoload :Mime, 'action_controller/mime_type'
|
||||
|
||||
@@ -39,9 +39,9 @@ module ActionController #:nodoc:
|
||||
if cache = read_fragment(name, options)
|
||||
buffer.safe_concat(cache.html_safe)
|
||||
else
|
||||
pos = buffer.length
|
||||
pos = buffer.bytesize
|
||||
block.call
|
||||
write_fragment(name, buffer[pos..-1], options)
|
||||
write_fragment(name, buffer.byteslice(pos..-1), options)
|
||||
end
|
||||
else
|
||||
block.call
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
require 'action_controller/cgi_ext/stdinput'
|
||||
require 'action_controller/cgi_ext/query_extension'
|
||||
require 'action_controller/cgi_ext/cookie'
|
||||
|
||||
class CGI #:nodoc:
|
||||
include ActionController::CgiExt::Stdinput
|
||||
|
||||
class << self
|
||||
alias :escapeHTML_fail_on_nil :escapeHTML
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
require 'delegate'
|
||||
require 'cgi'
|
||||
require 'cgi/cookie'
|
||||
|
||||
CGI.module_eval { remove_const "Cookie" }
|
||||
|
||||
@@ -24,7 +26,7 @@ class CGI #:nodoc:
|
||||
# * <tt>:secure</tt> - Whether this cookie is a secure cookie or not (defaults to
|
||||
# +false+). Secure cookies are only transmitted to HTTPS servers.
|
||||
# * <tt>:http_only</tt> - Whether this cookie can be accessed by client side scripts (e.g. document.cookie) or only over HTTP.
|
||||
# More details in http://msdn2.microsoft.com/en-us/library/system.web.httpcookie.httponly.aspx. Defaults to +false+.
|
||||
# More details in http://msdn2.microsoft.com/en-us/library/system.web.httpcookie.httponly.aspx. Defaults to +false+.
|
||||
#
|
||||
# These keywords correspond to attributes of the cookie object.
|
||||
def initialize(name = '', *value)
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
require 'cgi'
|
||||
|
||||
class CGI #:nodoc:
|
||||
module QueryExtension
|
||||
# Remove the old initialize_query method before redefining it.
|
||||
remove_method :initialize_query
|
||||
|
||||
# Neuter CGI parameter parsing.
|
||||
def initialize_query
|
||||
# Fix some strange request environments.
|
||||
env_table['REQUEST_METHOD'] ||= 'GET'
|
||||
|
||||
# POST assumes missing Content-Type is application/x-www-form-urlencoded.
|
||||
if env_table['CONTENT_TYPE'].blank? && env_table['REQUEST_METHOD'] == 'POST'
|
||||
env_table['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'
|
||||
end
|
||||
|
||||
@cookies = CGI::Cookie::parse(env_table['HTTP_COOKIE'] || env_table['COOKIE'])
|
||||
@params = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,24 +0,0 @@
|
||||
require 'cgi'
|
||||
|
||||
module ActionController
|
||||
module CgiExt
|
||||
# Publicize the CGI's internal input stream so we can lazy-read
|
||||
# request.body. Make it writable so we don't have to play $stdin games.
|
||||
module Stdinput
|
||||
def self.included(base)
|
||||
base.class_eval do
|
||||
remove_method :stdinput
|
||||
attr_accessor :stdinput
|
||||
end
|
||||
|
||||
base.alias_method_chain :initialize, :stdinput
|
||||
end
|
||||
|
||||
def initialize_with_stdinput(type = nil, stdinput = $stdin)
|
||||
@stdinput = stdinput
|
||||
@stdinput.set_encoding(Encoding::BINARY) if @stdinput.respond_to?(:set_encoding)
|
||||
initialize_without_stdinput(type || 'query')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,77 +0,0 @@
|
||||
require 'action_controller/cgi_ext'
|
||||
|
||||
module ActionController #:nodoc:
|
||||
class CGIHandler
|
||||
module ProperStream
|
||||
def each
|
||||
while line = gets
|
||||
yield line
|
||||
end
|
||||
end
|
||||
|
||||
def read(*args)
|
||||
if args.empty?
|
||||
super || ""
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.dispatch_cgi(app, cgi, out = $stdout)
|
||||
env = cgi.__send__(:env_table)
|
||||
env.delete "HTTP_CONTENT_LENGTH"
|
||||
|
||||
cgi.stdinput.extend ProperStream
|
||||
|
||||
env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
|
||||
|
||||
env.update({
|
||||
"rack.version" => [0,1],
|
||||
"rack.input" => cgi.stdinput,
|
||||
"rack.errors" => $stderr,
|
||||
"rack.multithread" => false,
|
||||
"rack.multiprocess" => true,
|
||||
"rack.run_once" => false,
|
||||
"rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http"
|
||||
})
|
||||
|
||||
env["QUERY_STRING"] ||= ""
|
||||
env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
|
||||
env["REQUEST_PATH"] ||= "/"
|
||||
env.delete "PATH_INFO" if env["PATH_INFO"] == ""
|
||||
|
||||
status, headers, body = app.call(env)
|
||||
begin
|
||||
out.binmode if out.respond_to?(:binmode)
|
||||
out.sync = false if out.respond_to?(:sync=)
|
||||
|
||||
headers['Status'] = status.to_s
|
||||
|
||||
if headers.include?('Set-Cookie')
|
||||
headers['cookie'] = headers.delete('Set-Cookie').split("\n")
|
||||
end
|
||||
|
||||
out.write(cgi.header(headers))
|
||||
|
||||
body.each { |part|
|
||||
out.write part
|
||||
out.flush if out.respond_to?(:flush)
|
||||
}
|
||||
ensure
|
||||
body.close if body.respond_to?(:close)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class CgiRequest #:nodoc:
|
||||
DEFAULT_SESSION_OPTIONS = {
|
||||
:database_manager => nil,
|
||||
:prefix => "ruby_sess.",
|
||||
:session_path => "/",
|
||||
:session_key => "_session_id",
|
||||
:cookie_only => true,
|
||||
:session_http_only => true
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -22,11 +22,6 @@ module ActionController
|
||||
end
|
||||
end
|
||||
|
||||
# DEPRECATE: Remove CGI support
|
||||
def dispatch(cgi = nil, session_options = CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout)
|
||||
new(output).dispatch_cgi(cgi, session_options)
|
||||
end
|
||||
|
||||
# Add a preparation callback. Preparation callbacks are run before every
|
||||
# request in development mode, and before the first request in production
|
||||
# mode.
|
||||
@@ -42,13 +37,7 @@ module ActionController
|
||||
end
|
||||
|
||||
def run_prepare_callbacks
|
||||
if defined?(Rails) && Rails.logger
|
||||
logger = Rails.logger
|
||||
else
|
||||
logger = Logger.new($stderr)
|
||||
end
|
||||
|
||||
new(logger).send :run_callbacks, :prepare_dispatch
|
||||
new.send :run_callbacks, :prepare_dispatch
|
||||
end
|
||||
|
||||
def reload_application
|
||||
@@ -75,10 +64,8 @@ module ActionController
|
||||
include ActiveSupport::Callbacks
|
||||
define_callbacks :prepare_dispatch, :before_dispatch, :after_dispatch
|
||||
|
||||
# DEPRECATE: Remove arguments, since they are only used by CGI
|
||||
def initialize(output = $stdout, request = nil, response = nil)
|
||||
@output = output
|
||||
build_middleware_stack if @@cache_classes
|
||||
def initialize
|
||||
build_middleware_stack
|
||||
end
|
||||
|
||||
def dispatch
|
||||
@@ -96,21 +83,11 @@ module ActionController
|
||||
end
|
||||
end
|
||||
|
||||
# DEPRECATE: Remove CGI support
|
||||
def dispatch_cgi(cgi, session_options)
|
||||
CGIHandler.dispatch_cgi(self, cgi, @output)
|
||||
end
|
||||
|
||||
def call(env)
|
||||
if @@cache_classes
|
||||
@app.call(env)
|
||||
else
|
||||
Reloader.run do
|
||||
# When class reloading is turned on, we will want to rebuild the
|
||||
# middleware stack every time we process a request. If we don't
|
||||
# rebuild the middleware stack, then the stack may contain references
|
||||
# to old classes metal classes, which will b0rk class reloading.
|
||||
build_middleware_stack
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -768,7 +768,11 @@ module ActionView
|
||||
options = options.stringify_keys
|
||||
tag_value = options.delete("value")
|
||||
name_and_id = options.dup
|
||||
name_and_id["id"] = name_and_id["for"]
|
||||
if name_and_id.has_key?("for")
|
||||
name_and_id["id"] = name_and_id["for"]
|
||||
else
|
||||
name_and_id.delete("id")
|
||||
end
|
||||
add_default_name_and_id_for_value(tag_value, name_and_id)
|
||||
options.delete("index")
|
||||
options["for"] ||= name_and_id["id"]
|
||||
@@ -928,15 +932,15 @@ module ActionView
|
||||
|
||||
def add_default_name_and_id(options)
|
||||
if options.has_key?("index")
|
||||
options["name"] ||= tag_name_with_index(options["index"])
|
||||
options["id"] ||= tag_id_with_index(options["index"])
|
||||
options["name"] = tag_name_with_index(options["index"]) unless options.has_key?("name")
|
||||
options["id"] = tag_id_with_index(options["index"]) unless options.has_key?("id")
|
||||
options.delete("index")
|
||||
elsif defined?(@auto_index)
|
||||
options["name"] ||= tag_name_with_index(@auto_index)
|
||||
options["id"] ||= tag_id_with_index(@auto_index)
|
||||
options["name"] = tag_name_with_index(@auto_index) unless options.has_key?("name")
|
||||
options["id"] = tag_id_with_index(@auto_index) unless options.has_key?("id")
|
||||
else
|
||||
options["name"] ||= tag_name + (options.has_key?('multiple') ? '[]' : '')
|
||||
options["id"] ||= tag_id
|
||||
options["name"] = tag_name + (options.has_key?('multiple') ? '[]' : '') unless options.has_key?("name")
|
||||
options["id"] = tag_id unless options.has_key?("id")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -85,11 +85,13 @@ module ActionView
|
||||
separator = '' if precision == 0
|
||||
|
||||
begin
|
||||
format.gsub(/%n/, number_with_precision(number,
|
||||
value = number_with_precision(number,
|
||||
:precision => precision,
|
||||
:delimiter => delimiter,
|
||||
:separator => separator)
|
||||
).gsub(/%u/, unit).html_safe
|
||||
value = ERB::Util.html_escape(value) if value
|
||||
unit = ERB::Util.html_escape(unit)
|
||||
format.gsub(/%n/, value).gsub(/%u/, unit).html_safe
|
||||
rescue
|
||||
number
|
||||
end
|
||||
|
||||
@@ -17,7 +17,7 @@ module ActionView
|
||||
src << "@output_buffer.safe_append='"
|
||||
src << "\n" * @newline_pending if @newline_pending > 0
|
||||
src << escape_text(text)
|
||||
src << "';"
|
||||
src << "'.freeze;"
|
||||
|
||||
@newline_pending = 0
|
||||
end
|
||||
@@ -63,7 +63,7 @@ module ActionView
|
||||
|
||||
def flush_newline_if_pending(src)
|
||||
if @newline_pending > 0
|
||||
src << "@output_buffer.safe_append='#{"\n" * @newline_pending}';"
|
||||
src << "@output_buffer.safe_append='#{"\n" * @newline_pending}'.freeze;"
|
||||
@newline_pending = 0
|
||||
end
|
||||
end
|
||||
|
||||
@@ -622,6 +622,19 @@ class FragmentCachingTest < ActionController::TestCase
|
||||
assert_equal 'generated till now -> fragment content', buffer
|
||||
end
|
||||
|
||||
def test_fragment_for_bytesize
|
||||
buffer = "\xC4\x8D"
|
||||
buffer.force_encoding('ASCII-8BIT')
|
||||
|
||||
@controller.fragment_for(buffer, 'bytesize') do
|
||||
buffer.force_encoding('UTF-8')
|
||||
buffer << "abc"
|
||||
end
|
||||
|
||||
assert_equal Encoding::UTF_8, buffer.encoding
|
||||
assert_equal "abc", @store.read('views/bytesize')
|
||||
end
|
||||
|
||||
def test_html_safety
|
||||
assert_nil @store.read('views/name')
|
||||
content = 'value'.html_safe
|
||||
|
||||
@@ -45,7 +45,7 @@ class DispatcherTest < Test::Unit::TestCase
|
||||
def test_rebuilds_middleware_stack_on_every_request_if_in_loading_mode
|
||||
dispatcher = create_dispatcher(false)
|
||||
dispatcher.instance_variable_set(:"@app", lambda { |env| })
|
||||
dispatcher.expects(:build_middleware_stack).twice
|
||||
dispatcher.expects(:build_middleware_stack).never
|
||||
dispatcher.call(nil)
|
||||
Reloader.default_lock.unlock
|
||||
dispatcher.call(nil)
|
||||
|
||||
@@ -5,7 +5,6 @@ class BaseRackTest < ActiveSupport::TestCase
|
||||
@env = {
|
||||
"HTTP_MAX_FORWARDS" => "10",
|
||||
"SERVER_NAME" => "glu.ttono.us",
|
||||
"FCGI_ROLE" => "RESPONDER",
|
||||
"AUTH_TYPE" => "Basic",
|
||||
"HTTP_X_FORWARDED_HOST" => "glu.ttono.us",
|
||||
"HTTP_ACCEPT_CHARSET" => "UTF-8",
|
||||
|
||||
@@ -11,17 +11,6 @@ class QueryStringParsingTest < ActionController::IntegrationTest
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
class EarlyParse
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
# Trigger a Rack parse so that env caches the query params
|
||||
Rack::Request.new(env).params
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
def teardown
|
||||
TestController.last_query_parameters = nil
|
||||
@@ -122,8 +111,6 @@ class QueryStringParsingTest < ActionController::IntegrationTest
|
||||
set.draw do |map|
|
||||
map.connect ':action', :controller => "query_string_parsing_test/test"
|
||||
end
|
||||
@stack = ActionController::MiddlewareStack.new
|
||||
@stack.use(EarlyParse)
|
||||
|
||||
get "/parse", actual
|
||||
assert_response :ok
|
||||
|
||||
@@ -175,6 +175,10 @@ class FormHelperTest < ActionView::TestCase
|
||||
I18n.locale = old_locale
|
||||
end
|
||||
|
||||
def test_label_with_for_attribute_as_nil
|
||||
assert_dom_equal('<label>Title</label>', label(:post, :title, nil, :for => nil))
|
||||
end
|
||||
|
||||
def test_label_with_for_attribute_as_symbol
|
||||
assert_dom_equal('<label for="my_for">Title</label>', label(:post, :title, nil, :for => "my_for"))
|
||||
end
|
||||
@@ -274,6 +278,11 @@ class FormHelperTest < ActionView::TestCase
|
||||
hidden_field("post", "title", :value => "Something Else")
|
||||
end
|
||||
|
||||
def test_text_field_with_id_as_nil
|
||||
assert_dom_equal '<input name="post[title]" type="hidden" value="Hello World" />',
|
||||
hidden_field("post", "title", :id => nil)
|
||||
end
|
||||
|
||||
def test_check_box
|
||||
assert_dom_equal(
|
||||
'<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="1" />',
|
||||
|
||||
@@ -24,9 +24,10 @@ class NumberHelperTest < ActionView::TestCase
|
||||
assert_equal("$1,234,567,890.51", number_to_currency(1234567890.506))
|
||||
assert_equal("$1,234,567,892", number_to_currency(1234567891.50, {:precision => 0}))
|
||||
assert_equal("$1,234,567,890.5", number_to_currency(1234567890.50, {:precision => 1}))
|
||||
assert_equal("£1234567890,50", number_to_currency(1234567890.50, {:unit => "£", :separator => ",", :delimiter => ""}))
|
||||
assert_equal("£1234567890,50", number_to_currency(1234567890.50, {:unit => raw("£"), :separator => ",", :delimiter => ""}))
|
||||
assert_equal("&pound;1234567890,50", number_to_currency(1234567890.50, {:unit => "£", :separator => ",", :delimiter => ""}))
|
||||
assert_equal("$1,234,567,890.50", number_to_currency("1234567890.50"))
|
||||
assert_equal("1,234,567,890.50 Kč", number_to_currency("1234567890.50", {:unit => "Kč", :format => "%n %u"}))
|
||||
assert_equal("1,234,567,890.50 Kč", number_to_currency("1234567890.50", {:unit => raw("Kč"), :format => "%n %u"}))
|
||||
#assert_equal("$x.", number_to_currency("x")) # fails due to API consolidation
|
||||
assert_equal("$x", number_to_currency("x"))
|
||||
assert_nil number_to_currency(nil)
|
||||
|
||||
@@ -25,7 +25,7 @@ task :default => :test
|
||||
## This is required until the regular test task
|
||||
## below passes. It's not ideal, but at least
|
||||
## we can see the failures
|
||||
task :test do
|
||||
task :test do
|
||||
Dir['test/**/*_test.rb'].all? do |file|
|
||||
ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
|
||||
system(ruby, '-Itest', file)
|
||||
@@ -38,7 +38,7 @@ Rake::TestTask.new("regular_test") do |t|
|
||||
end
|
||||
|
||||
|
||||
BASE_DIRS = %w(
|
||||
BASE_DIRS = %w(
|
||||
app
|
||||
config/environments
|
||||
config/initializers
|
||||
@@ -158,21 +158,10 @@ end
|
||||
# Copy Ties Content -----------------------------------------------------------------------
|
||||
|
||||
desc "Make copies of all the default content of ties"
|
||||
task :copy_ties_content => [
|
||||
:copy_rootfiles, :copy_dispatches, :copy_html_files, :copy_application,
|
||||
task :copy_ties_content => [
|
||||
:copy_rootfiles, :copy_html_files, :copy_application,
|
||||
:copy_configs, :copy_binfiles, :copy_test_helpers, :copy_app_doc_readme ]
|
||||
|
||||
task :copy_dispatches do
|
||||
copy_with_rewritten_ruby_path("dispatches/dispatch.rb", "#{PKG_DESTINATION}/public/dispatch.rb")
|
||||
chmod 0755, "#{PKG_DESTINATION}/public/dispatch.rb"
|
||||
|
||||
copy_with_rewritten_ruby_path("dispatches/dispatch.rb", "#{PKG_DESTINATION}/public/dispatch.cgi")
|
||||
chmod 0755, "#{PKG_DESTINATION}/public/dispatch.cgi"
|
||||
|
||||
copy_with_rewritten_ruby_path("dispatches/dispatch.fcgi", "#{PKG_DESTINATION}/public/dispatch.fcgi")
|
||||
chmod 0755, "#{PKG_DESTINATION}/public/dispatch.fcgi"
|
||||
end
|
||||
|
||||
task :copy_html_files do
|
||||
HTML_FILES.each { |file| cp File.join('html', file), File.join(PKG_DESTINATION, 'public', file) }
|
||||
end
|
||||
@@ -187,7 +176,7 @@ task :copy_configs do
|
||||
socket = nil
|
||||
require 'erb'
|
||||
File.open("#{PKG_DESTINATION}/config/database.yml", 'w') {|f| f.write ERB.new(IO.read("configs/databases/sqlite3.yml"), nil, '-').result(binding)}
|
||||
|
||||
|
||||
cp "configs/routes.rb", "#{PKG_DESTINATION}/config/routes.rb"
|
||||
|
||||
cp "configs/initializers/backtrace_silencers.rb", "#{PKG_DESTINATION}/config/initializers/backtrace_silencers.rb"
|
||||
@@ -288,15 +277,15 @@ end
|
||||
|
||||
PKG_FILES = FileList[
|
||||
'[a-zA-Z]*',
|
||||
'bin/**/*',
|
||||
'bin/**/*',
|
||||
'builtin/**/*',
|
||||
'configs/**/*',
|
||||
'doc/**/*',
|
||||
'dispatches/**/*',
|
||||
'environments/**/*',
|
||||
'helpers/**/*',
|
||||
'generators/**/*',
|
||||
'html/**/*',
|
||||
'configs/**/*',
|
||||
'doc/**/*',
|
||||
'dispatches/**/*',
|
||||
'environments/**/*',
|
||||
'helpers/**/*',
|
||||
'generators/**/*',
|
||||
'html/**/*',
|
||||
'lib/**/*'
|
||||
] - [ 'test' ]
|
||||
|
||||
@@ -336,7 +325,7 @@ end
|
||||
|
||||
# Publishing -------------------------------------------------------
|
||||
desc "Publish the rails gem"
|
||||
task :pgem => [:gem] do
|
||||
task :pgem => [:gem] do
|
||||
Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
|
||||
`ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'`
|
||||
end
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
#
|
||||
# You may specify the path to the FastCGI crash log (a log of unhandled
|
||||
# exceptions which forced the FastCGI instance to exit, great for debugging)
|
||||
# and the number of requests to process before running garbage collection.
|
||||
#
|
||||
# By default, the FastCGI crash log is RAILS_ROOT/log/fastcgi.crash.log
|
||||
# and the GC period is nil (turned off). A reasonable number of requests
|
||||
# could range from 10-100 depending on the memory footprint of your app.
|
||||
#
|
||||
# Example:
|
||||
# # Default log path, normal GC behavior.
|
||||
# RailsFCGIHandler.process!
|
||||
#
|
||||
# # Default log path, 50 requests between GC.
|
||||
# RailsFCGIHandler.process! nil, 50
|
||||
#
|
||||
# # Custom log path, normal GC behavior.
|
||||
# RailsFCGIHandler.process! '/var/log/myapp_fcgi_crash.log'
|
||||
#
|
||||
require File.dirname(__FILE__) + "/../config/environment"
|
||||
require 'fcgi_handler'
|
||||
|
||||
RailsFCGIHandler.process!
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
|
||||
|
||||
# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
|
||||
# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
|
||||
require "dispatcher"
|
||||
|
||||
ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
|
||||
Dispatcher.dispatch
|
||||
@@ -1,97 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'drb'
|
||||
|
||||
# This file includes an experimental gateway CGI implementation. It will work
|
||||
# only on platforms which support both fork and sockets.
|
||||
#
|
||||
# To enable it edit public/.htaccess and replace dispatch.cgi with gateway.cgi.
|
||||
#
|
||||
# Next, create the directory log/drb_gateway and grant the apache user rw access
|
||||
# to said directory.
|
||||
#
|
||||
# On the next request to your server, the gateway tracker should start up, along
|
||||
# with a few listener processes. This setup should provide you with much better
|
||||
# speeds than dispatch.cgi.
|
||||
#
|
||||
# Keep in mind that the first request made to the server will be slow, as the
|
||||
# tracker and listeners will have to load. Also, the tracker and listeners will
|
||||
# shutdown after a period if inactivity. You can set this value below -- the
|
||||
# default is 90 seconds.
|
||||
|
||||
TrackerSocket = File.expand_path(File.join(File.dirname(__FILE__), '../log/drb_gateway/tracker.sock'))
|
||||
DieAfter = 90 # Seconds
|
||||
Listeners = 3
|
||||
|
||||
def message(s)
|
||||
$stderr.puts "gateway.cgi: #{s}" if ENV && ENV["DEBUG_GATEWAY"]
|
||||
end
|
||||
|
||||
def listener_socket(number)
|
||||
File.expand_path(File.join(File.dirname(__FILE__), "../log/drb_gateway/listener_#{number}.sock"))
|
||||
end
|
||||
|
||||
unless File.exist? TrackerSocket
|
||||
message "Starting tracker and #{Listeners} listeners"
|
||||
fork do
|
||||
Process.setsid
|
||||
STDIN.reopen "/dev/null"
|
||||
STDOUT.reopen "/dev/null", "a"
|
||||
|
||||
root = File.expand_path(File.dirname(__FILE__) + '/..')
|
||||
|
||||
message "starting tracker"
|
||||
fork do
|
||||
ARGV.clear
|
||||
ARGV << TrackerSocket << Listeners.to_s << DieAfter.to_s
|
||||
load File.join(root, 'script', 'tracker')
|
||||
end
|
||||
|
||||
message "starting listeners"
|
||||
require File.join(root, 'config/environment.rb')
|
||||
Listeners.times do |number|
|
||||
fork do
|
||||
ARGV.clear
|
||||
ARGV << listener_socket(number) << DieAfter.to_s
|
||||
load File.join(root, 'script', 'listener')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
message "waiting for tracker and listener to arise..."
|
||||
ready = false
|
||||
10.times do
|
||||
sleep 0.5
|
||||
break if (ready = File.exist?(TrackerSocket) && File.exist?(listener_socket(0)))
|
||||
end
|
||||
|
||||
if ready
|
||||
message "tracker and listener are ready"
|
||||
else
|
||||
message "Waited 5 seconds, listener and tracker not ready... dropping request"
|
||||
Kernel.exit 1
|
||||
end
|
||||
end
|
||||
|
||||
DRb.start_service
|
||||
|
||||
message "connecting to tracker"
|
||||
tracker = DRbObject.new_with_uri("drbunix:#{TrackerSocket}")
|
||||
|
||||
input = $stdin.read
|
||||
$stdin.close
|
||||
|
||||
env = ENV.inspect
|
||||
|
||||
output = nil
|
||||
tracker.with_listener do |number|
|
||||
message "connecting to listener #{number}"
|
||||
socket = listener_socket(number)
|
||||
listener = DRbObject.new_with_uri("drbunix:#{socket}")
|
||||
output = listener.process(env, input)
|
||||
message "listener #{number} has finished, writing output"
|
||||
end
|
||||
|
||||
$stdout.write output
|
||||
$stdout.flush
|
||||
$stdout.close
|
||||
@@ -1,86 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'stringio'
|
||||
require 'fileutils'
|
||||
require 'fcgi_handler'
|
||||
|
||||
def message(s)
|
||||
$stderr.puts "listener: #{s}" if ENV && ENV["DEBUG_GATEWAY"]
|
||||
end
|
||||
|
||||
class RemoteCGI < CGI
|
||||
attr_accessor :stdinput, :stdoutput, :env_table
|
||||
def initialize(env_table, input = nil, output = nil)
|
||||
self.env_table = env_table
|
||||
self.stdinput = input || StringIO.new
|
||||
self.stdoutput = output || StringIO.new
|
||||
super()
|
||||
end
|
||||
|
||||
def out(stream) # Ignore the requested output stream
|
||||
super(stdoutput)
|
||||
end
|
||||
end
|
||||
|
||||
class Listener
|
||||
include DRbUndumped
|
||||
|
||||
def initialize(timeout, socket_path)
|
||||
@socket = File.expand_path(socket_path)
|
||||
@mutex = Mutex.new
|
||||
@active = false
|
||||
@timeout = timeout
|
||||
|
||||
@handler = RailsFCGIHandler.new
|
||||
@handler.extend DRbUndumped
|
||||
|
||||
message 'opening socket'
|
||||
DRb.start_service("drbunix:#{@socket}", self)
|
||||
|
||||
message 'entering process loop'
|
||||
@handler.process! self
|
||||
end
|
||||
|
||||
def each_cgi(&cgi_block)
|
||||
@cgi_block = cgi_block
|
||||
message 'entering idle loop'
|
||||
loop do
|
||||
sleep @timeout rescue nil
|
||||
die! unless @active
|
||||
@active = false
|
||||
end
|
||||
end
|
||||
|
||||
def process(env, input)
|
||||
message 'received request'
|
||||
@mutex.synchronize do
|
||||
@active = true
|
||||
|
||||
message 'creating input stream'
|
||||
input_stream = StringIO.new(input)
|
||||
message 'building CGI instance'
|
||||
cgi = RemoteCGI.new(eval(env), input_stream)
|
||||
|
||||
message 'yielding to fcgi handler'
|
||||
@cgi_block.call cgi
|
||||
message 'yield finished -- sending output'
|
||||
|
||||
cgi.stdoutput.seek(0)
|
||||
output = cgi.stdoutput.read
|
||||
|
||||
return output
|
||||
end
|
||||
end
|
||||
|
||||
def die!
|
||||
message 'shutting down'
|
||||
DRb.stop_service
|
||||
FileUtils.rm_f @socket
|
||||
Kernel.exit 0
|
||||
end
|
||||
end
|
||||
|
||||
socket_path = ARGV.shift
|
||||
timeout = (ARGV.shift || 90).to_i
|
||||
|
||||
Listener.new(timeout, socket_path)
|
||||
@@ -1,69 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'drb'
|
||||
require 'thread'
|
||||
|
||||
def message(s)
|
||||
$stderr.puts "tracker: #{s}" if ENV && ENV["DEBUG_GATEWAY"]
|
||||
end
|
||||
|
||||
class Tracker
|
||||
include DRbUndumped
|
||||
|
||||
def initialize(instances, socket_path)
|
||||
@instances = instances
|
||||
@socket = File.expand_path(socket_path)
|
||||
@active = false
|
||||
|
||||
@listeners = []
|
||||
@instances.times { @listeners << Mutex.new }
|
||||
|
||||
message "using #{@listeners.length} listeners"
|
||||
message "opening socket at #{@socket}"
|
||||
|
||||
@service = DRb.start_service("drbunix://#{@socket}", self)
|
||||
end
|
||||
|
||||
def with_listener
|
||||
message "listener requested"
|
||||
|
||||
mutex = has_lock = index = nil
|
||||
3.times do
|
||||
@listeners.each_with_index do |mutex, index|
|
||||
has_lock = mutex.try_lock
|
||||
break if has_lock
|
||||
end
|
||||
break if has_lock
|
||||
sleep 0.05
|
||||
end
|
||||
|
||||
if has_lock
|
||||
message "obtained listener #{index}"
|
||||
@active = true
|
||||
begin yield index
|
||||
ensure
|
||||
mutex.unlock
|
||||
message "released listener #{index}"
|
||||
end
|
||||
else
|
||||
message "dropping request because no listeners are available!"
|
||||
end
|
||||
end
|
||||
|
||||
def background(check_interval = nil)
|
||||
if check_interval
|
||||
loop do
|
||||
sleep check_interval
|
||||
message "Idle for #{check_interval}, shutting down" unless @active
|
||||
@active = false
|
||||
Kernel.exit 0
|
||||
end
|
||||
else DRb.thread.join
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
socket_path = ARGV.shift
|
||||
instances = ARGV.shift.to_i
|
||||
t = Tracker.new(instances, socket_path)
|
||||
t.background(ARGV.first ? ARGV.shift.to_i : 90)
|
||||
@@ -1,239 +0,0 @@
|
||||
require 'fcgi'
|
||||
require 'logger'
|
||||
require 'dispatcher'
|
||||
require 'rbconfig'
|
||||
|
||||
class RailsFCGIHandler
|
||||
SIGNALS = {
|
||||
'HUP' => :reload,
|
||||
'INT' => :exit_now,
|
||||
'TERM' => :exit_now,
|
||||
'USR1' => :exit,
|
||||
'USR2' => :restart
|
||||
}
|
||||
GLOBAL_SIGNALS = SIGNALS.keys - %w(USR1)
|
||||
|
||||
attr_reader :when_ready
|
||||
|
||||
attr_accessor :log_file_path
|
||||
attr_accessor :gc_request_period
|
||||
|
||||
# Initialize and run the FastCGI instance, passing arguments through to new.
|
||||
def self.process!(*args, &block)
|
||||
new(*args, &block).process!
|
||||
end
|
||||
|
||||
# Initialize the FastCGI instance with the path to a crash log
|
||||
# detailing unhandled exceptions (default RAILS_ROOT/log/fastcgi.crash.log)
|
||||
# and the number of requests to process between garbage collection runs
|
||||
# (default nil for normal GC behavior.) Optionally, pass a block which
|
||||
# takes this instance as an argument for further configuration.
|
||||
def initialize(log_file_path = nil, gc_request_period = nil)
|
||||
self.log_file_path = log_file_path || "#{RAILS_ROOT}/log/fastcgi.crash.log"
|
||||
self.gc_request_period = gc_request_period
|
||||
|
||||
# Yield for additional configuration.
|
||||
yield self if block_given?
|
||||
|
||||
# Safely install signal handlers.
|
||||
install_signal_handlers
|
||||
|
||||
@app = Dispatcher.new
|
||||
|
||||
# Start error timestamp at 11 seconds ago.
|
||||
@last_error_on = Time.now - 11
|
||||
end
|
||||
|
||||
def process!(provider = FCGI)
|
||||
mark_features!
|
||||
|
||||
dispatcher_log :info, 'starting'
|
||||
process_each_request provider
|
||||
dispatcher_log :info, 'stopping gracefully'
|
||||
|
||||
rescue Exception => error
|
||||
case error
|
||||
when SystemExit
|
||||
dispatcher_log :info, 'stopping after explicit exit'
|
||||
when SignalException
|
||||
dispatcher_error error, 'stopping after unhandled signal'
|
||||
else
|
||||
# Retry if exceptions occur more than 10 seconds apart.
|
||||
if Time.now - @last_error_on > 10
|
||||
@last_error_on = Time.now
|
||||
dispatcher_error error, 'retrying after unhandled exception'
|
||||
retry
|
||||
else
|
||||
dispatcher_error error, 'stopping after unhandled exception within 10 seconds of the last'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
def process_each_request(provider)
|
||||
request = nil
|
||||
|
||||
catch :exit do
|
||||
provider.each do |request|
|
||||
process_request(request)
|
||||
|
||||
case when_ready
|
||||
when :reload
|
||||
reload!
|
||||
when :restart
|
||||
close_connection(request)
|
||||
restart!
|
||||
when :exit
|
||||
close_connection(request)
|
||||
throw :exit
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue SignalException => signal
|
||||
raise unless signal.message == 'SIGUSR1'
|
||||
close_connection(request)
|
||||
end
|
||||
|
||||
def process_request(request)
|
||||
@processing, @when_ready = true, nil
|
||||
gc_countdown
|
||||
|
||||
with_signal_handler 'USR1' do
|
||||
begin
|
||||
::Rack::Handler::FastCGI.serve(request, @app)
|
||||
rescue SignalException, SystemExit
|
||||
raise
|
||||
rescue Exception => error
|
||||
dispatcher_error error, 'unhandled dispatch error'
|
||||
end
|
||||
end
|
||||
ensure
|
||||
@processing = false
|
||||
end
|
||||
|
||||
def logger
|
||||
@logger ||= Logger.new(@log_file_path)
|
||||
end
|
||||
|
||||
def dispatcher_log(level, msg)
|
||||
time_str = Time.now.strftime("%d/%b/%Y:%H:%M:%S")
|
||||
logger.send(level, "[#{time_str} :: #{$$}] #{msg}")
|
||||
rescue Exception => log_error # Logger errors
|
||||
STDERR << "Couldn't write to #{@log_file_path.inspect}: #{msg}\n"
|
||||
STDERR << " #{log_error.class}: #{log_error.message}\n"
|
||||
end
|
||||
|
||||
def dispatcher_error(e, msg = "")
|
||||
error_message =
|
||||
"Dispatcher failed to catch: #{e} (#{e.class})\n" +
|
||||
" #{e.backtrace.join("\n ")}\n#{msg}"
|
||||
dispatcher_log(:error, error_message)
|
||||
end
|
||||
|
||||
def install_signal_handlers
|
||||
GLOBAL_SIGNALS.each { |signal| install_signal_handler(signal) }
|
||||
end
|
||||
|
||||
def install_signal_handler(signal, handler = nil)
|
||||
if SIGNALS.include?(signal) && self.class.method_defined?(name = "#{SIGNALS[signal]}_handler")
|
||||
handler ||= method(name).to_proc
|
||||
|
||||
begin
|
||||
trap(signal, handler)
|
||||
rescue ArgumentError
|
||||
dispatcher_log :warn, "Ignoring unsupported signal #{signal}."
|
||||
end
|
||||
else
|
||||
dispatcher_log :warn, "Ignoring unsupported signal #{signal}."
|
||||
end
|
||||
end
|
||||
|
||||
def with_signal_handler(signal)
|
||||
install_signal_handler(signal)
|
||||
yield
|
||||
ensure
|
||||
install_signal_handler(signal, 'DEFAULT')
|
||||
end
|
||||
|
||||
def exit_now_handler(signal)
|
||||
dispatcher_log :info, "asked to stop immediately"
|
||||
exit
|
||||
end
|
||||
|
||||
def exit_handler(signal)
|
||||
dispatcher_log :info, "asked to stop ASAP"
|
||||
if @processing
|
||||
@when_ready = :exit
|
||||
else
|
||||
throw :exit
|
||||
end
|
||||
end
|
||||
|
||||
def reload_handler(signal)
|
||||
dispatcher_log :info, "asked to reload ASAP"
|
||||
if @processing
|
||||
@when_ready = :reload
|
||||
else
|
||||
reload!
|
||||
end
|
||||
end
|
||||
|
||||
def restart_handler(signal)
|
||||
dispatcher_log :info, "asked to restart ASAP"
|
||||
if @processing
|
||||
@when_ready = :restart
|
||||
else
|
||||
restart!
|
||||
end
|
||||
end
|
||||
|
||||
def restart!
|
||||
config = ::Config::CONFIG
|
||||
ruby = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT']
|
||||
command_line = [ruby, $0, ARGV].flatten.join(' ')
|
||||
|
||||
dispatcher_log :info, "restarted"
|
||||
|
||||
# close resources as they won't be closed by
|
||||
# the OS when using exec
|
||||
logger.close rescue nil
|
||||
Rails.logger.close rescue nil
|
||||
|
||||
exec(command_line)
|
||||
end
|
||||
|
||||
def reload!
|
||||
run_gc! if gc_request_period
|
||||
restore!
|
||||
@when_ready = nil
|
||||
dispatcher_log :info, "reloaded"
|
||||
end
|
||||
|
||||
# Make a note of $" so we can safely reload this instance.
|
||||
def mark_features!
|
||||
@features = $".clone
|
||||
end
|
||||
|
||||
def restore!
|
||||
$".replace @features
|
||||
Dispatcher.reset_application!
|
||||
ActionController::Routing::Routes.reload
|
||||
end
|
||||
|
||||
def run_gc!
|
||||
@gc_request_countdown = gc_request_period
|
||||
GC.enable; GC.start; GC.disable
|
||||
end
|
||||
|
||||
def gc_countdown
|
||||
if gc_request_period
|
||||
@gc_request_countdown ||= gc_request_period
|
||||
@gc_request_countdown -= 1
|
||||
run_gc! if @gc_request_countdown <= 0
|
||||
end
|
||||
end
|
||||
|
||||
def close_connection(request)
|
||||
request.finish if request
|
||||
end
|
||||
end
|
||||
@@ -299,7 +299,11 @@ HELP
|
||||
# Evaluate any assignments in a temporary, throwaway binding.
|
||||
vars = template_options[:assigns] || {}
|
||||
b = template_options[:binding] || binding
|
||||
vars.each { |k,v| eval "#{k} = vars[:#{k}] || vars['#{k}']", b }
|
||||
if b.respond_to?(:local_variable_set)
|
||||
vars.each { |k,v| b.local_variable_set(k, v) }
|
||||
else
|
||||
vars.each { |k,v| eval "#{k} = vars[:#{k}] || vars['#{k}']", b }
|
||||
end
|
||||
|
||||
# Render the source file with the temporary binding.
|
||||
ERB.new(file.read, nil, '-').result(b)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'rbconfig'
|
||||
require File.dirname(__FILE__) + '/template_runner'
|
||||
require 'digest/md5'
|
||||
require 'digest/md5'
|
||||
require 'active_support/secure_random'
|
||||
|
||||
class AppGenerator < Rails::Generator::Base
|
||||
@@ -110,12 +110,12 @@ class AppGenerator < Rails::Generator::Base
|
||||
tmp/pids
|
||||
).each { |path| m.directory(path) }
|
||||
end
|
||||
|
||||
|
||||
def create_root_files(m)
|
||||
m.file "fresh_rakefile", "Rakefile"
|
||||
m.file "README", "README"
|
||||
end
|
||||
|
||||
|
||||
def create_app_files(m)
|
||||
m.file "helpers/application_controller.rb", "app/controllers/application_controller.rb"
|
||||
m.file "helpers/application_helper.rb", "app/helpers/application_helper.rb"
|
||||
@@ -138,7 +138,7 @@ class AppGenerator < Rails::Generator::Base
|
||||
%w( server production development test ).each do |file|
|
||||
m.file "configs/empty.log", "log/#{file}.log", :chmod => 0666
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_public_files(m)
|
||||
create_dispatch_files(m)
|
||||
@@ -148,14 +148,14 @@ class AppGenerator < Rails::Generator::Base
|
||||
create_rails_image(m)
|
||||
create_javascript_files(m)
|
||||
end
|
||||
|
||||
|
||||
def create_script_files(m)
|
||||
%w(
|
||||
%w(
|
||||
about console dbconsole destroy generate runner server plugin
|
||||
performance/benchmarker performance/profiler
|
||||
).each do |file|
|
||||
m.file "bin/#{file}", "script/#{file}", {
|
||||
:chmod => 0755,
|
||||
m.file "bin/#{file}", "script/#{file}", {
|
||||
:chmod => 0755,
|
||||
:shebang => options[:shebang] == DEFAULT_SHEBANG ? nil : options[:shebang]
|
||||
}
|
||||
end
|
||||
@@ -172,7 +172,7 @@ class AppGenerator < Rails::Generator::Base
|
||||
:app_name => @app_name,
|
||||
:socket => options[:db] == "mysql" ? mysql_socket_location : nil }
|
||||
end
|
||||
|
||||
|
||||
def create_routes_file(m)
|
||||
m.file "configs/routes.rb", "config/routes.rb"
|
||||
end
|
||||
@@ -182,19 +182,19 @@ class AppGenerator < Rails::Generator::Base
|
||||
end
|
||||
|
||||
def create_initializer_files(m)
|
||||
%w(
|
||||
backtrace_silencers
|
||||
inflections
|
||||
mime_types
|
||||
%w(
|
||||
backtrace_silencers
|
||||
inflections
|
||||
mime_types
|
||||
new_rails_defaults
|
||||
).each do |initializer|
|
||||
m.file "configs/initializers/#{initializer}.rb", "config/initializers/#{initializer}.rb"
|
||||
end
|
||||
|
||||
m.template "configs/initializers/session_store.rb", "config/initializers/session_store.rb",
|
||||
m.template "configs/initializers/session_store.rb", "config/initializers/session_store.rb",
|
||||
:assigns => { :app_name => @app_name, :app_secret => ActiveSupport::SecureRandom.hex(64) }
|
||||
|
||||
m.template "configs/initializers/cookie_verification_secret.rb", "config/initializers/cookie_verification_secret.rb",
|
||||
m.template "configs/initializers/cookie_verification_secret.rb", "config/initializers/cookie_verification_secret.rb",
|
||||
:assigns => { :app_secret => ActiveSupport::SecureRandom.hex(64) }
|
||||
end
|
||||
|
||||
@@ -203,7 +203,7 @@ class AppGenerator < Rails::Generator::Base
|
||||
end
|
||||
|
||||
def create_environment_files(m)
|
||||
m.template "environments/environment.rb", "config/environment.rb",
|
||||
m.template "environments/environment.rb", "config/environment.rb",
|
||||
:assigns => { :freeze => options[:freeze] }
|
||||
|
||||
m.file "environments/boot.rb", "config/boot.rb"
|
||||
@@ -218,9 +218,6 @@ class AppGenerator < Rails::Generator::Base
|
||||
dispatcher_options = { :chmod => 0755, :shebang => options[:shebang] }
|
||||
|
||||
m.file "dispatches/config.ru", "config.ru"
|
||||
m.file "dispatches/dispatch.rb", "public/dispatch.rb", dispatcher_options
|
||||
m.file "dispatches/dispatch.rb", "public/dispatch.cgi", dispatcher_options
|
||||
m.file "dispatches/dispatch.fcgi", "public/dispatch.fcgi", dispatcher_options
|
||||
end
|
||||
end
|
||||
|
||||
@@ -263,4 +260,4 @@ class AppGenerator < Rails::Generator::Base
|
||||
"/opt/lampp/var/mysql/mysql.sock" # xampp for linux
|
||||
].find { |f| File.exist?(f) } unless RUBY_PLATFORM =~ /(:?mswin|mingw)/
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace :rails do
|
||||
|
||||
local = Dir["#{local_base}/**/*"].reject { |path| File.directory?(path) }
|
||||
edge = Dir["#{edge_base}/**/*"].reject { |path| File.directory?(path) }
|
||||
|
||||
|
||||
edge.each do |script|
|
||||
base_name = script[(edge_base.length+1)..-1]
|
||||
next if base_name == "rails"
|
||||
@@ -111,7 +111,7 @@ namespace :rails do
|
||||
|
||||
desc "Update your javascripts from your current rails install"
|
||||
task :javascripts do
|
||||
require 'railties_path'
|
||||
require 'railties_path'
|
||||
project_dir = RAILS_ROOT + '/public/javascripts/'
|
||||
scripts = Dir[RAILTIES_PATH + '/html/javascripts/*.js']
|
||||
scripts.reject!{|s| File.basename(s) == 'application.js'} if File.exist?(project_dir + 'application.js')
|
||||
@@ -120,10 +120,10 @@ namespace :rails do
|
||||
|
||||
desc "Update config/boot.rb from your current rails install"
|
||||
task :configs do
|
||||
require 'railties_path'
|
||||
require 'railties_path'
|
||||
FileUtils.cp(RAILTIES_PATH + '/environments/boot.rb', RAILS_ROOT + '/config/boot.rb')
|
||||
end
|
||||
|
||||
|
||||
desc "Rename application.rb to application_controller.rb"
|
||||
task :application_controller do
|
||||
old_style = RAILS_ROOT + '/app/controllers/application.rb'
|
||||
@@ -133,14 +133,11 @@ namespace :rails do
|
||||
puts "#{old_style} has been renamed to #{new_style}, update your SCM as necessary"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
desc "Generate dispatcher files in RAILS_ROOT/public"
|
||||
task :generate_dispatchers do
|
||||
require 'railties_path'
|
||||
FileUtils.cp(RAILTIES_PATH + '/dispatches/config.ru', RAILS_ROOT + '/config.ru')
|
||||
FileUtils.cp(RAILTIES_PATH + '/dispatches/dispatch.fcgi', RAILS_ROOT + '/public/dispatch.fcgi')
|
||||
FileUtils.cp(RAILTIES_PATH + '/dispatches/dispatch.rb', RAILS_ROOT + '/public/dispatch.rb')
|
||||
FileUtils.cp(RAILTIES_PATH + '/dispatches/dispatch.rb', RAILS_ROOT + '/public/dispatch.cgi')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
# Donated by Florian Gross
|
||||
|
||||
require 'webrick'
|
||||
require 'cgi'
|
||||
require 'stringio'
|
||||
require 'dispatcher'
|
||||
|
||||
include WEBrick
|
||||
|
||||
class CGI #:nodoc:
|
||||
def stdinput
|
||||
@stdin || $stdin
|
||||
end
|
||||
|
||||
def env_table
|
||||
@env_table || ENV
|
||||
end
|
||||
|
||||
def initialize(type = "query", table = nil, stdin = nil)
|
||||
@env_table, @stdin = table, stdin
|
||||
|
||||
if defined?(MOD_RUBY) && !ENV.key?("GATEWAY_INTERFACE")
|
||||
Apache.request.setup_cgi_env
|
||||
end
|
||||
|
||||
extend QueryExtension
|
||||
@multipart = false
|
||||
if defined?(CGI_PARAMS)
|
||||
warn "do not use CGI_PARAMS and CGI_COOKIES"
|
||||
@params = CGI_PARAMS.dup
|
||||
@cookies = CGI_COOKIES.dup
|
||||
else
|
||||
initialize_query() # set @params, @cookies
|
||||
end
|
||||
@output_cookies = nil
|
||||
@output_hidden = nil
|
||||
end
|
||||
end
|
||||
|
||||
# A custom dispatch servlet for use with WEBrick. It dispatches requests
|
||||
# (using the Rails Dispatcher) to the appropriate controller/action. By default,
|
||||
# it restricts WEBrick to a managing a single Rails request at a time, but you
|
||||
# can change this behavior by setting ActionController::Base.allow_concurrency
|
||||
# to true.
|
||||
class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
|
||||
# Start the WEBrick server with the given options, mounting the
|
||||
# DispatchServlet at <tt>/</tt>.
|
||||
def self.dispatch(options = {})
|
||||
Socket.do_not_reverse_lookup = true # patch for OS X
|
||||
|
||||
params = { :Port => options[:port].to_i,
|
||||
:ServerType => options[:server_type],
|
||||
:BindAddress => options[:ip] }
|
||||
params[:MimeTypes] = options[:mime_types] if options[:mime_types]
|
||||
|
||||
server = WEBrick::HTTPServer.new(params)
|
||||
server.mount('/', DispatchServlet, options)
|
||||
|
||||
trap("INT") { server.shutdown }
|
||||
server.start
|
||||
end
|
||||
|
||||
def initialize(server, options) #:nodoc:
|
||||
@server_options = options
|
||||
@file_handler = WEBrick::HTTPServlet::FileHandler.new(server, options[:server_root])
|
||||
# Change to the RAILS_ROOT, since Webrick::Daemon.start does a Dir::cwd("/")
|
||||
# OPTIONS['working_directory'] is an absolute path of the RAILS_ROOT, set in railties/lib/commands/servers/webrick.rb
|
||||
Dir.chdir(OPTIONS['working_directory']) if defined?(OPTIONS) && File.directory?(OPTIONS['working_directory'])
|
||||
super
|
||||
end
|
||||
|
||||
def service(req, res) #:nodoc:
|
||||
unless handle_file(req, res)
|
||||
unless handle_dispatch(req, res)
|
||||
raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def handle_file(req, res) #:nodoc:
|
||||
begin
|
||||
req = req.dup
|
||||
path = req.path.dup
|
||||
|
||||
# Add .html if the last path piece has no . in it
|
||||
path << '.html' if path != '/' && (%r{(^|/)[^./]+$} =~ path)
|
||||
path.gsub!('+', ' ') # Unescape + since FileHandler doesn't do so.
|
||||
|
||||
req.instance_variable_set(:@path_info, path) # Set the modified path...
|
||||
|
||||
@file_handler.send(:service, req, res)
|
||||
return true
|
||||
rescue HTTPStatus::PartialContent, HTTPStatus::NotModified => err
|
||||
res.set_error(err)
|
||||
return true
|
||||
rescue => err
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def handle_dispatch(req, res, origin = nil) #:nodoc:
|
||||
data = StringIO.new
|
||||
Dispatcher.dispatch(
|
||||
CGI.new("query", create_env_table(req, origin), StringIO.new(req.body || "")),
|
||||
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS,
|
||||
data
|
||||
)
|
||||
|
||||
header, body = extract_header_and_body(data)
|
||||
|
||||
set_charset(header)
|
||||
assign_status(res, header)
|
||||
res.cookies.concat(header.delete('set-cookie') || [])
|
||||
header.each { |key, val| res[key] = val.join(", ") }
|
||||
|
||||
res.body = body
|
||||
return true
|
||||
rescue => err
|
||||
p err, err.backtrace
|
||||
return false
|
||||
end
|
||||
|
||||
private
|
||||
def create_env_table(req, origin)
|
||||
env = req.meta_vars.clone
|
||||
env.delete "SCRIPT_NAME"
|
||||
env["QUERY_STRING"] = req.request_uri.query
|
||||
env["REQUEST_URI"] = origin if origin
|
||||
return env
|
||||
end
|
||||
|
||||
def extract_header_and_body(data)
|
||||
data.rewind
|
||||
data = data.read
|
||||
|
||||
raw_header, body = *data.split(/^[\xd\xa]{2}/on, 2)
|
||||
header = WEBrick::HTTPUtils::parse_header(raw_header)
|
||||
|
||||
return header, body
|
||||
end
|
||||
|
||||
def set_charset(header)
|
||||
ct = header["content-type"]
|
||||
if ct.any? { |x| x =~ /^text\// } && ! ct.any? { |x| x =~ /charset=/ }
|
||||
ch = @server_options[:charset] || "UTF-8"
|
||||
ct.find { |x| x =~ /^text\// } << ("; charset=" + ch)
|
||||
end
|
||||
end
|
||||
|
||||
def assign_status(res, header)
|
||||
if /^(\d+)/ =~ header['status'][0]
|
||||
res.status = $1.to_i
|
||||
header.delete('status')
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,266 +0,0 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
if RUBY_VERSION < '1.9.0'
|
||||
uses_gem "fcgi", "0.8.7" do
|
||||
|
||||
require 'action_controller'
|
||||
require 'fcgi_handler'
|
||||
|
||||
Dispatcher.middleware.clear
|
||||
|
||||
class RailsFCGIHandlerTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@log = StringIO.new
|
||||
@handler = RailsFCGIHandler.new(@log)
|
||||
end
|
||||
|
||||
def test_process_restart
|
||||
request = mock
|
||||
FCGI.stubs(:each).yields(request)
|
||||
|
||||
@handler.expects(:process_request).once
|
||||
@handler.expects(:dispatcher_error).never
|
||||
|
||||
@handler.expects(:when_ready).returns(:restart)
|
||||
@handler.expects(:close_connection).with(request)
|
||||
@handler.expects(:reload!).never
|
||||
@handler.expects(:restart!)
|
||||
|
||||
@handler.process!
|
||||
end
|
||||
|
||||
def test_process_exit
|
||||
request = mock
|
||||
FCGI.stubs(:each).yields(request)
|
||||
|
||||
@handler.expects(:process_request).once
|
||||
@handler.expects(:dispatcher_error).never
|
||||
|
||||
@handler.expects(:when_ready).returns(:exit)
|
||||
@handler.expects(:close_connection).with(request)
|
||||
@handler.expects(:reload!).never
|
||||
@handler.expects(:restart!).never
|
||||
|
||||
@handler.process!
|
||||
end
|
||||
|
||||
def test_process_with_system_exit_exception
|
||||
request = mock
|
||||
FCGI.stubs(:each).yields(request)
|
||||
|
||||
@handler.expects(:process_request).once.raises(SystemExit)
|
||||
@handler.stubs(:dispatcher_log)
|
||||
@handler.expects(:dispatcher_log).with(:info, regexp_matches(/^stopping/))
|
||||
@handler.expects(:dispatcher_error).never
|
||||
|
||||
@handler.expects(:when_ready).never
|
||||
@handler.expects(:close_connection).never
|
||||
@handler.expects(:reload!).never
|
||||
@handler.expects(:restart!).never
|
||||
|
||||
@handler.process!
|
||||
end
|
||||
|
||||
def test_restart_handler_outside_request
|
||||
@handler.expects(:dispatcher_log).with(:info, "asked to restart ASAP")
|
||||
@handler.expects(:restart!).once
|
||||
|
||||
@handler.send(:restart_handler, nil)
|
||||
assert_equal nil, @handler.when_ready
|
||||
end
|
||||
|
||||
def test_install_signal_handler_should_log_on_bad_signal
|
||||
@handler.stubs(:trap).raises(ArgumentError)
|
||||
|
||||
@handler.expects(:dispatcher_log).with(:warn, "Ignoring unsupported signal CHEESECAKE.")
|
||||
@handler.send(:install_signal_handler, "CHEESECAKE", nil)
|
||||
end
|
||||
|
||||
def test_reload
|
||||
@handler.expects(:restore!)
|
||||
@handler.expects(:dispatcher_log).with(:info, "reloaded")
|
||||
|
||||
@handler.send(:reload!)
|
||||
assert_nil @handler.when_ready
|
||||
end
|
||||
|
||||
|
||||
def test_reload_runs_gc_when_gc_request_period_set
|
||||
@handler.expects(:run_gc!)
|
||||
@handler.expects(:restore!)
|
||||
@handler.expects(:dispatcher_log).with(:info, "reloaded")
|
||||
@handler.gc_request_period = 10
|
||||
@handler.send(:reload!)
|
||||
end
|
||||
|
||||
def test_reload_doesnt_run_gc_if_gc_request_period_isnt_set
|
||||
@handler.expects(:run_gc!).never
|
||||
@handler.expects(:restore!)
|
||||
@handler.expects(:dispatcher_log).with(:info, "reloaded")
|
||||
@handler.send(:reload!)
|
||||
end
|
||||
|
||||
def test_restart!
|
||||
@handler.expects(:dispatcher_log).with(:info, "restarted")
|
||||
@handler.expects(:exec).returns('restarted')
|
||||
assert_equal 'restarted', @handler.send(:restart!)
|
||||
end
|
||||
|
||||
def test_restore!
|
||||
$".expects(:replace)
|
||||
Dispatcher.expects(:reset_application!)
|
||||
ActionController::Routing::Routes.expects(:reload)
|
||||
@handler.send(:restore!)
|
||||
end
|
||||
|
||||
def test_uninterrupted_processing
|
||||
request = mock
|
||||
FCGI.expects(:each).yields(request)
|
||||
@handler.expects(:process_request).with(request)
|
||||
|
||||
@handler.process!
|
||||
|
||||
assert_nil @handler.when_ready
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class RailsFCGIHandlerSignalsTest < Test::Unit::TestCase
|
||||
class ::RailsFCGIHandler
|
||||
attr_accessor :signal
|
||||
alias_method :old_gc_countdown, :gc_countdown
|
||||
def gc_countdown
|
||||
signal ? Process.kill(signal, $$) : old_gc_countdown
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
@log = StringIO.new
|
||||
@handler = RailsFCGIHandler.new(@log)
|
||||
@dispatcher = mock
|
||||
Dispatcher.stubs(:new).returns(@dispatcher)
|
||||
end
|
||||
|
||||
def test_interrupted_via_HUP_when_not_in_request
|
||||
request = mock
|
||||
FCGI.expects(:each).once.yields(request)
|
||||
@handler.expects(:signal).times(2).returns('HUP')
|
||||
|
||||
@handler.expects(:reload!).once
|
||||
@handler.expects(:close_connection).never
|
||||
@handler.expects(:exit).never
|
||||
|
||||
@handler.process!
|
||||
assert_equal :reload, @handler.when_ready
|
||||
end
|
||||
|
||||
def test_interrupted_via_USR1_when_not_in_request
|
||||
request = mock
|
||||
FCGI.expects(:each).once.yields(request)
|
||||
@handler.expects(:signal).times(2).returns('USR1')
|
||||
@handler.expects(:exit_handler).never
|
||||
|
||||
@handler.expects(:reload!).never
|
||||
@handler.expects(:close_connection).with(request).once
|
||||
@handler.expects(:exit).never
|
||||
|
||||
@handler.process!
|
||||
assert_nil @handler.when_ready
|
||||
end
|
||||
|
||||
def test_restart_via_USR2_when_in_request
|
||||
request = mock
|
||||
FCGI.expects(:each).once.yields(request)
|
||||
@handler.expects(:signal).times(2).returns('USR2')
|
||||
@handler.expects(:exit_handler).never
|
||||
|
||||
@handler.expects(:reload!).never
|
||||
@handler.expects(:close_connection).with(request).once
|
||||
@handler.expects(:exit).never
|
||||
@handler.expects(:restart!).once
|
||||
|
||||
@handler.process!
|
||||
assert_equal :restart, @handler.when_ready
|
||||
end
|
||||
|
||||
def test_interrupted_via_TERM
|
||||
request = mock
|
||||
FCGI.expects(:each).once.yields(request)
|
||||
::Rack::Handler::FastCGI.expects(:serve).once.returns('TERM')
|
||||
|
||||
@handler.expects(:reload!).never
|
||||
@handler.expects(:close_connection).never
|
||||
|
||||
@handler.process!
|
||||
assert_nil @handler.when_ready
|
||||
end
|
||||
|
||||
def test_runtime_exception_in_fcgi
|
||||
error = RuntimeError.new('foo')
|
||||
FCGI.expects(:each).times(2).raises(error)
|
||||
@handler.expects(:dispatcher_error).with(error, regexp_matches(/^retrying/))
|
||||
@handler.expects(:dispatcher_error).with(error, regexp_matches(/^stopping/))
|
||||
@handler.process!
|
||||
end
|
||||
|
||||
def test_runtime_error_in_dispatcher
|
||||
request = mock
|
||||
error = RuntimeError.new('foo')
|
||||
FCGI.expects(:each).once.yields(request)
|
||||
::Rack::Handler::FastCGI.expects(:serve).once.raises(error)
|
||||
@handler.expects(:dispatcher_error).with(error, regexp_matches(/^unhandled/))
|
||||
@handler.process!
|
||||
end
|
||||
|
||||
def test_signal_exception_in_fcgi
|
||||
error = SignalException.new('USR2')
|
||||
FCGI.expects(:each).once.raises(error)
|
||||
@handler.expects(:dispatcher_error).with(error, regexp_matches(/^stopping/))
|
||||
@handler.process!
|
||||
end
|
||||
|
||||
def test_signal_exception_in_dispatcher
|
||||
request = mock
|
||||
error = SignalException.new('USR2')
|
||||
FCGI.expects(:each).once.yields(request)
|
||||
::Rack::Handler::FastCGI.expects(:serve).once.raises(error)
|
||||
@handler.expects(:dispatcher_error).with(error, regexp_matches(/^stopping/))
|
||||
@handler.process!
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class RailsFCGIHandlerPeriodicGCTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@log = StringIO.new
|
||||
end
|
||||
|
||||
def teardown
|
||||
GC.enable
|
||||
end
|
||||
|
||||
def test_normal_gc
|
||||
@handler = RailsFCGIHandler.new(@log)
|
||||
assert_nil @handler.gc_request_period
|
||||
|
||||
# When GC is enabled, GC.disable disables and returns false.
|
||||
assert_equal false, GC.disable
|
||||
end
|
||||
|
||||
def test_periodic_gc
|
||||
@handler = RailsFCGIHandler.new(@log, 10)
|
||||
assert_equal 10, @handler.gc_request_period
|
||||
|
||||
request = mock
|
||||
FCGI.expects(:each).times(10).yields(request)
|
||||
|
||||
@handler.expects(:run_gc!).never
|
||||
9.times { @handler.process! }
|
||||
@handler.expects(:run_gc!).once
|
||||
@handler.process!
|
||||
|
||||
assert_nil @handler.when_ready
|
||||
end
|
||||
end
|
||||
end # uses_gem "fcgi"
|
||||
end # exclude 1.9
|
||||
@@ -4,4 +4,4 @@ set -x
|
||||
set -e
|
||||
|
||||
script/cibuild-on 1.9.3-p231-tcs-github
|
||||
script/cibuild-on 2.0.0-github
|
||||
script/cibuild-on 2.1.0-github
|
||||
|
||||
Reference in New Issue
Block a user