aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_controller/cgi_process.rb10
-rw-r--r--railties/CHANGELOG2
-rw-r--r--railties/lib/dispatcher.rb6
-rw-r--r--railties/lib/webrick_server.rb96
4 files changed, 75 insertions, 39 deletions
diff --git a/actionpack/lib/action_controller/cgi_process.rb b/actionpack/lib/action_controller/cgi_process.rb
index 9166a8d433..e4e86615c0 100644
--- a/actionpack/lib/action_controller/cgi_process.rb
+++ b/actionpack/lib/action_controller/cgi_process.rb
@@ -124,20 +124,20 @@ module ActionController #:nodoc:
super()
end
- def out
+ def out(output = $stdout)
convert_content_type!(@headers)
- $stdout.binmode if $stdout.respond_to?(:binmode)
- $stdout.sync = false
+ output.binmode if output.respond_to?(:binmode)
+ output.sync = false if output.respond_to?(:sync=)
begin
- print @cgi.header(@headers)
+ output.write(@cgi.header(@headers))
if @cgi.send(:env_table)['REQUEST_METHOD'] == 'HEAD'
return
elsif @body.respond_to?(:call)
@body.call(self)
else
- print @body
+ output.write(@body)
end
rescue Errno::EPIPE => e
# lost connection to the FCGI process -- ignore the output, then
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index d4423b4a83..444a918a7c 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,5 +1,7 @@
*SVN*
+* Removed the mutex from the WEBrick adapter under the production environment so concurrent requests can be served
+
* Fixed that mailer generator generated fixtures/plural while units expected fixtures/singular #1457 [Scott Barron]
* Added a 'whiny nil' that's aim to ensure that when users pass nil to methods where that isn't appropriate, instead of NoMethodError? and the name of some method used by the framework users will see a message explaining what type of object was expected. Only active in test and development environments by default #1209 [Michael Koziarski]
diff --git a/railties/lib/dispatcher.rb b/railties/lib/dispatcher.rb
index 140d8e84a3..b2f9650e65 100644
--- a/railties/lib/dispatcher.rb
+++ b/railties/lib/dispatcher.rb
@@ -25,13 +25,13 @@ require 'breakpoint'
class Dispatcher
class << self
- def dispatch(cgi = CGI.new, session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS)
+ def dispatch(cgi = CGI.new, session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout)
begin
request, response = ActionController::CgiRequest.new(cgi, session_options), ActionController::CgiResponse.new(cgi)
prepare_application
- ActionController::Routing::Routes.recognize!(request).process(request, response).out
+ ActionController::Routing::Routes.recognize!(request).process(request, response).out(output)
rescue Object => exception
- ActionController::Base.process_with_exception(request, response, exception).out
+ ActionController::Base.process_with_exception(request, response, exception).out(output)
ensure
reset_application
end
diff --git a/railties/lib/webrick_server.rb b/railties/lib/webrick_server.rb
index bd8c287c9b..46451e2e52 100644
--- a/railties/lib/webrick_server.rb
+++ b/railties/lib/webrick_server.rb
@@ -8,6 +8,24 @@ include WEBrick
ABSOLUTE_RAILS_ROOT = File.expand_path(RAILS_ROOT)
+class CGI
+ def stdinput
+ @stdin || $stdin
+ end
+
+ def stdinput=(input)
+ @stdin = input
+ end
+
+ def env_table
+ @env_table || ENV
+ end
+
+ def env_table=(table)
+ @env_table = table
+ end
+end
+
class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
REQUEST_MUTEX = Mutex.new
@@ -18,6 +36,10 @@ class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
server.mount('/', DispatchServlet, options)
trap("INT") { server.shutdown }
+
+ require File.join(@server_options[:server_root], "..", "config", "environment") unless defined?(RAILS_ROOT)
+ require "dispatcher"
+
server.start
end
@@ -31,20 +53,21 @@ class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
def service(req, res)
begin
unless handle_file(req, res)
- REQUEST_MUTEX.lock
+ REQUEST_MUTEX.lock unless RAILS_ENV == 'production'
unless handle_dispatch(req, res)
raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
end
end
ensure
- REQUEST_MUTEX.unlock if REQUEST_MUTEX.locked?
+ unless RAILS_ENV == 'production'
+ REQUEST_MUTEX.unlock if REQUEST_MUTEX.locked?
+ end
end
end
def handle_file(req, res)
begin
req = req.dup
-
path = req.path.dup
# Add .html if the last path piece has no . in it
@@ -63,35 +86,13 @@ class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
end
end
- def handle_dispatch(req, res, origin = nil)
- env = req.meta_vars.clone
- env.delete "SCRIPT_NAME"
- env["QUERY_STRING"] = req.request_uri.query
- env["REQUEST_URI"] = origin if origin
-
- data = nil
- $old_stdin, $old_stdout = $stdin, $stdout
- $stdin, $stdout = StringIO.new(req.body || ""), StringIO.new
-
- begin
- require 'cgi'
- CGI.send(:define_method, :env_table) { env }
-
- load File.join(@server_options[:server_root], "dispatch.rb")
-
- $stdout.rewind
- data = $stdout.read
- ensure
- $stdin, $stdout = $old_stdin, $old_stdout
- end
+ def handle_dispatch(req, res, origin = nil)
+ data = StringIO.new
+ Dispatcher.dispatch(create_cgi(req, origin), ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, data)
- raw_header, body = *data.split(/^[\xd\xa]+/on, 2)
- header = WEBrick::HTTPUtils::parse_header(raw_header)
- if /^(\d+)/ =~ header['status'][0]
- res.status = $1.to_i
- header.delete('status')
- end
- res.cookies.concat header.delete('set-cookie')
+ header, body = extract_header_and_body(data)
+ assign_status(res, header)
+ res.cookies.concat(header.delete('set-cookie'))
header.each { |key, val| res[key] = val.join(", ") }
res.body = body
@@ -100,4 +101,37 @@ class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
p err, err.backtrace
return false
end
+
+ private
+ def create_cgi(req, origin)
+ cgi = CGI.new
+ cgi.env_table = create_env_table(req, origin)
+ cgi.stdinput = req.body || ""
+ return cgi
+ end
+
+ 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]+/on, 2)
+ header = WEBrick::HTTPUtils::parse_header(raw_header)
+
+ return header, body
+ end
+
+ def assign_status(res, header)
+ if /^(\d+)/ =~ header['status'][0]
+ res.status = $1.to_i
+ header.delete('status')
+ end
+ end
end