Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define Rack::Builder::Config, and support middleware.rackup configuring middleware based on server configuration #1720

Merged
merged 11 commits into from Jan 27, 2022
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,10 @@ All notable changes to this project will be documented in this file. For info on

- Do not use semicolon as GET parameter separator. ([#1733](https://github.com/rack/rack/pull/1733), [@jeremyevans](https://github.com/jeremyevans))

### Removed

- Remove `rack.multithread`/`rack.multiprocess`/`rack.run_once`. These variables generally come too late to be useful. ([#1720](https://github.com/rack/rack/pull/1720), [@ioquatix](https://github.com/ioquatix), [@jeremyevans](https://github.com/jeremyevans)))

### Added

- `Rack::RewindableInput` supports size. ([@ahorek](https://github.com/ahorek))
Expand Down
13 changes: 0 additions & 13 deletions SPEC.rdoc
Expand Up @@ -78,19 +78,6 @@ Rack-specific variables:
request URL.
<tt>rack.input</tt>:: See below, the input stream.
<tt>rack.errors</tt>:: See below, the error stream.
<tt>rack.multithread</tt>:: true if the application object may be
simultaneously invoked by another thread
in the same process, false otherwise.
<tt>rack.multiprocess</tt>:: true if an equivalent application object
may be simultaneously invoked by another
process, false otherwise.
<tt>rack.run_once</tt>:: true if the server expects
(but does not guarantee!) that the
application will only be invoked this one
time during the life of its containing
process. Normally, this will only be true
for a server based on CGI
(or something similar).
<tt>rack.hijack?</tt>:: present and true if the server supports
connection hijacking. See below, hijacking.
<tt>rack.hijack</tt>:: an object responding to #call that must be
Expand Down
3 changes: 0 additions & 3 deletions lib/rack.rb
Expand Up @@ -55,9 +55,6 @@ module Rack
RACK_SESSION = 'rack.session'
RACK_SESSION_OPTIONS = 'rack.session.options'
RACK_SHOWSTATUS_DETAIL = 'rack.showstatus.detail'
RACK_MULTITHREAD = 'rack.multithread'
RACK_MULTIPROCESS = 'rack.multiprocess'
RACK_RUNONCE = 'rack.run_once'
RACK_URL_SCHEME = 'rack.url_scheme'
RACK_HIJACK = 'rack.hijack'
RACK_IS_HIJACK = 'rack.hijack?'
Expand Down
3 changes: 0 additions & 3 deletions lib/rack/handler/cgi.rb
Expand Up @@ -18,9 +18,6 @@ def self.serve(app)
RACK_VERSION => Rack::VERSION,
RACK_INPUT => Rack::RewindableInput.new($stdin),
RACK_ERRORS => $stderr,
RACK_MULTITHREAD => false,
RACK_MULTIPROCESS => true,
RACK_RUNONCE => true,
RACK_URL_SCHEME => ["yes", "on", "1"].include?(ENV[HTTPS]) ? "https" : "http"
)

Expand Down
3 changes: 0 additions & 3 deletions lib/rack/handler/webrick.rb
Expand Up @@ -75,9 +75,6 @@ def service(req, res)
RACK_VERSION => Rack::VERSION,
RACK_INPUT => rack_input,
RACK_ERRORS => $stderr,
RACK_MULTITHREAD => true,
RACK_MULTIPROCESS => false,
RACK_RUNONCE => false,
RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[HTTPS]) ? "https" : "http",
RACK_IS_HIJACK => true,
RACK_HIJACK => lambda { raise NotImplementedError, "only partial hijack is supported."},
Expand Down
19 changes: 1 addition & 18 deletions lib/rack/lint.rb
Expand Up @@ -166,22 +166,6 @@ def check_environment(env)

## <tt>rack.errors</tt>:: See below, the error stream.

## <tt>rack.multithread</tt>:: true if the application object may be
## simultaneously invoked by another thread
## in the same process, false otherwise.

## <tt>rack.multiprocess</tt>:: true if an equivalent application object
## may be simultaneously invoked by another
## process, false otherwise.

## <tt>rack.run_once</tt>:: true if the server expects
## (but does not guarantee!) that the
## application will only be invoked this one
## time during the life of its containing
## process. Normally, this will only be true
## for a server based on CGI
## (or something similar).

## <tt>rack.hijack?</tt>:: present and true if the server supports
## connection hijacking. See below, hijacking.

Expand Down Expand Up @@ -283,8 +267,7 @@ def check_environment(env)
##

%w[REQUEST_METHOD SERVER_NAME QUERY_STRING
rack.version rack.input rack.errors
rack.multithread rack.multiprocess rack.run_once].each { |header|
rack.version rack.input rack.errors].each { |header|
raise LintError, "env missing required key #{header}" unless env.include? header
}

Expand Down
7 changes: 1 addition & 6 deletions lib/rack/lock.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true

require 'thread'

module Rack
# Rack::Lock locks every request inside a mutex, so that every request
# will effectively be executed synchronously.
Expand All @@ -12,10 +10,8 @@ def initialize(app, mutex = Mutex.new)

def call(env)
@mutex.lock
@env = env
@old_rack_multithread = env[RACK_MULTITHREAD]
begin
response = @app.call(env.merge!(RACK_MULTITHREAD => false))
response = @app.call(env)
returned = response << BodyProxy.new(response.pop) { unlock }
ensure
unlock unless returned
Expand All @@ -26,7 +22,6 @@ def call(env)

def unlock
@mutex.unlock
@env[RACK_MULTITHREAD] = @old_rack_multithread
end
end
end
3 changes: 0 additions & 3 deletions lib/rack/mock.rb
Expand Up @@ -45,9 +45,6 @@ def string
RACK_VERSION => Rack::VERSION,
RACK_INPUT => StringIO.new,
RACK_ERRORS => StringIO.new,
RACK_MULTITHREAD => true,
RACK_MULTIPROCESS => true,
RACK_RUNONCE => false,
}.freeze

def initialize(app)
Expand Down
1 change: 0 additions & 1 deletion lib/rack/request.rb
Expand Up @@ -172,7 +172,6 @@ def query_string; get_header(QUERY_STRING).to_s end
def content_length; get_header('CONTENT_LENGTH') end
def logger; get_header(RACK_LOGGER) end
def user_agent; get_header('HTTP_USER_AGENT') end
def multithread?; get_header(RACK_MULTITHREAD) end

# the referer of the client
def referer; get_header('HTTP_REFERER') end
Expand Down
13 changes: 3 additions & 10 deletions lib/rack/session/pool.rb
Expand Up @@ -45,7 +45,7 @@ def generate_sid(*args, use_mutex: true)
end

def find_session(req, sid)
with_lock(req) do
@mutex.synchronize do
unless sid and session = get_session_with_fallback(sid)
sid, session = generate_sid(use_mutex: false), {}
@pool.store sid.private_id, session
Expand All @@ -55,27 +55,20 @@ def find_session(req, sid)
end

def write_session(req, session_id, new_session, options)
with_lock(req) do
@mutex.synchronize do
@pool.store session_id.private_id, new_session
session_id
end
end

def delete_session(req, session_id, options)
with_lock(req) do
@mutex.synchronize do
@pool.delete(session_id.public_id)
@pool.delete(session_id.private_id)
generate_sid(use_mutex: false) unless options[:drop]
end
end

def with_lock(req)
@mutex.lock if req.multithread?
yield
ensure
@mutex.unlock if @mutex.locked?
end

private

def get_session_with_fallback(sid)
Expand Down
23 changes: 0 additions & 23 deletions test/spec_lock.rb
Expand Up @@ -139,28 +139,6 @@ def close; @close_called = true; end
lock.synchronized.must_equal false
end

it "set multithread flag to false" do
app = lock_app(lambda { |env|
env['rack.multithread'].must_equal false
[200, { "Content-Type" => "text/plain" }, %w{ a b c }]
}, false)
env = Rack::MockRequest.env_for("/")
env['rack.multithread'].must_equal true
_, _, body = app.call(env)
body.close
env['rack.multithread'].must_equal true
end

it "reset original multithread flag when exiting lock" do
app = Class.new(Rack::Lock) {
def call(env)
env['rack.multithread'].must_equal true
super
end
}.new(lambda { |env| [200, { "Content-Type" => "text/plain" }, %w{ a b c }] })
Rack::Lint.new(app).call(Rack::MockRequest.env_for("/"))
end

it 'not unlock if an error is raised before the mutex is locked' do
lock = Class.new do
def initialize() @unlocked = false end
Expand All @@ -181,7 +159,6 @@ def initialize(env) @env = env end
end
app = Rack::Lock.new lambda { |env| [200, { "Content-Type" => "text/plain" }, proxy.new(env)] }
response = app.call(Rack::MockRequest.env_for("/"))[2]
response.env['rack.multithread'].must_equal false
end

it "unlock if an exception occurs before returning" do
Expand Down
2 changes: 1 addition & 1 deletion test/spec_session_pool.rb
Expand Up @@ -241,7 +241,7 @@
tnum = rand(7).to_i + 5
r = Array.new(tnum) do
Thread.new(treq) do |run|
run.get('/', "HTTP_COOKIE" => cookie, 'rack.multithread' => true)
run.get('/', "HTTP_COOKIE" => cookie)
end
end.reverse.map{|t| t.run.join.value }
r.each do |resp|
Expand Down
3 changes: 0 additions & 3 deletions test/spec_webrick.rb
Expand Up @@ -50,9 +50,6 @@ def is_running?
it "have rack headers" do
GET("/test")
response["rack.version"].must_equal [1, 3]
response["rack.multithread"].must_equal true
assert_equal false, response["rack.multiprocess"]
assert_equal false, response["rack.run_once"]
end

it "have CGI headers on GET" do
Expand Down