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

Reducing object allocations by reusing the Array object from the parent middleware #1887

Merged
merged 2 commits into from Jul 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions lib/rack/chunked.rb
Expand Up @@ -99,7 +99,7 @@ def chunkable_version?(ver)
# but does not have content-length or transfer-encoding headers,
# modify the response to use chunked transfer-encoding.
def call(env)
status, headers, body = @app.call(env)
status, headers, body = response = @app.call(env)

if chunkable_version?(env[SERVER_PROTOCOL]) &&
!STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) &&
Expand All @@ -108,13 +108,13 @@ def call(env)

headers[TRANSFER_ENCODING] = 'chunked'
if headers['trailer']
body = TrailerBody.new(body)
response[2] = TrailerBody.new(body)
else
body = Body.new(body)
response[2] = Body.new(body)
end
end

[status, headers, body]
response
end
end
end
7 changes: 4 additions & 3 deletions lib/rack/common_logger.rb
Expand Up @@ -40,9 +40,10 @@ def initialize(app, logger = nil)
# cause the request not to be logged.
def call(env)
began_at = Utils.clock_time
status, headers, body = @app.call(env)
body = BodyProxy.new(body) { log(env, status, headers, began_at) }
[status, headers, body]
status, headers, body = response = @app.call(env)

response[2] = BodyProxy.new(body) { log(env, status, headers, began_at) }
response
end

private
Expand Down
12 changes: 6 additions & 6 deletions lib/rack/conditional_get.rb
Expand Up @@ -28,17 +28,17 @@ def initialize(app)
def call(env)
case env[REQUEST_METHOD]
when "GET", "HEAD"
status, headers, body = @app.call(env)
status, headers, body = response = @app.call(env)

if status == 200 && fresh?(env, headers)
status = 304
response[0] = 304
headers.delete(CONTENT_TYPE)
headers.delete(CONTENT_LENGTH)
original_body = body
body = Rack::BodyProxy.new([]) do
original_body.close if original_body.respond_to?(:close)
response[2] = Rack::BodyProxy.new([]) do
body.close if body.respond_to?(:close)
end
end
[status, headers, body]
response
else
@app.call(env)
end
Expand Down
6 changes: 3 additions & 3 deletions lib/rack/content_length.rb
Expand Up @@ -17,18 +17,18 @@ def initialize(app)
end

def call(env)
status, headers, body = @app.call(env)
status, headers, body = response = @app.call(env)

if !STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) &&
!headers[CONTENT_LENGTH] &&
!headers[TRANSFER_ENCODING] &&
body.respond_to?(:to_ary)

body = body.to_ary
response[2] = body = body.to_ary
headers[CONTENT_LENGTH] = body.sum(&:bytesize).to_s
end

[status, headers, body]
response
end
end
end
4 changes: 2 additions & 2 deletions lib/rack/content_type.rb
Expand Up @@ -21,13 +21,13 @@ def initialize(app, content_type = "text/html")
end

def call(env)
status, headers, body = @app.call(env)
status, headers, _ = response = @app.call(env)

unless STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i)
headers[CONTENT_TYPE] ||= @content_type
end

[status, headers, body]
response
end
end
end
9 changes: 5 additions & 4 deletions lib/rack/deflater.rb
Expand Up @@ -44,10 +44,10 @@ def initialize(app, options = {})
end

def call(env)
status, headers, body = @app.call(env)
status, headers, body = response = @app.call(env)

unless should_deflate?(env, status, headers, body)
return [status, headers, body]
return response
end

request = Request.new(env)
Expand All @@ -67,9 +67,10 @@ def call(env)
headers.delete(CONTENT_LENGTH)
mtime = headers["last-modified"]
mtime = Time.httpdate(mtime).to_i if mtime
[status, headers, GzipStream.new(body, mtime, @sync)]
response[2] = GzipStream.new(body, mtime, @sync)
response
when "identity"
[status, headers, body]
response
else # when nil
# Only possible encoding values here are 'gzip', 'identity', and nil
message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found."
Expand Down
4 changes: 2 additions & 2 deletions lib/rack/etag.rb
Expand Up @@ -26,7 +26,7 @@ def initialize(app, no_cache_control = nil, cache_control = DEFAULT_CACHE_CONTRO
end

def call(env)
status, headers, body = @app.call(env)
status, headers, body = response = @app.call(env)

if etag_status?(status) && body.respond_to?(:to_ary) && !skip_caching?(headers)
body = body.to_ary
Expand All @@ -42,7 +42,7 @@ def call(env)
end
end

[status, headers, body]
response
end

private
Expand Down
14 changes: 6 additions & 8 deletions lib/rack/head.rb
Expand Up @@ -12,17 +12,15 @@ def initialize(app)
end

def call(env)
status, headers, body = @app.call(env)
_, _, body = response = @app.call(env)

if env[REQUEST_METHOD] == HEAD
[
status, headers, Rack::BodyProxy.new([]) do
body.close if body.respond_to? :close
end
]
else
[status, headers, body]
response[2] = Rack::BodyProxy.new([]) do
body.close if body.respond_to? :close
end
end

response
end
end
end
4 changes: 2 additions & 2 deletions lib/rack/runtime.rb
Expand Up @@ -21,15 +21,15 @@ def initialize(app, name = nil)

def call(env)
start_time = Utils.clock_time
status, headers, body = @app.call(env)
_, headers, _ = response = @app.call(env)

request_time = Utils.clock_time - start_time

unless headers.key?(@header_name)
headers[@header_name] = FORMAT_STRING % request_time
end

[status, headers, body]
response
end
end
end
8 changes: 4 additions & 4 deletions lib/rack/sendfile.rb
Expand Up @@ -111,7 +111,7 @@ def initialize(app, variation = nil, mappings = [])
end

def call(env)
status, headers, body = @app.call(env)
status, headers, body = response = @app.call(env)

if body.respond_to?(:to_path)
case type = variation(env)
Expand All @@ -122,7 +122,7 @@ def call(env)
# '?' must be percent-encoded because it is not query string but a part of path
headers[type.downcase] = ::Rack::Utils.escape_path(url).gsub('?', '%3F')
obody = body
body = Rack::BodyProxy.new([]) do
response[2] = Rack::BodyProxy.new([]) do
obody.close if obody.respond_to?(:close)
end
else
Expand All @@ -133,15 +133,15 @@ def call(env)
headers[CONTENT_LENGTH] = '0'
headers[type.downcase] = path
obody = body
body = Rack::BodyProxy.new([]) do
response[2] = Rack::BodyProxy.new([]) do
obody.close if obody.respond_to?(:close)
end
when '', nil
else
env[RACK_ERRORS].puts "Unknown x-sendfile variation: '#{type}'.\n"
end
end
[status, headers, body]
response
end

private
Expand Down
14 changes: 7 additions & 7 deletions lib/rack/show_status.rb
Expand Up @@ -22,7 +22,7 @@ def initialize(app)
end

def call(env)
status, headers, body = @app.call(env)
status, headers, body = response = @app.call(env)
empty = headers[CONTENT_LENGTH].to_i <= 0

# client or server error, or explicit message
Expand All @@ -40,15 +40,15 @@ def call(env)
html = @template.result(binding)
size = html.bytesize

original_body = body
body = Rack::BodyProxy.new([html]) do
original_body.close if original_body.respond_to?(:close)
response[2] = Rack::BodyProxy.new([html]) do
body.close if body.respond_to?(:close)
end

[status, headers.merge(CONTENT_TYPE => "text/html", CONTENT_LENGTH => size.to_s), body]
else
[status, headers, body]
headers[CONTENT_TYPE] = "text/html"
headers[CONTENT_LENGTH] = size.to_s
end

response
end

def h(obj) # :nodoc:
Expand Down
6 changes: 3 additions & 3 deletions lib/rack/tempfile_reaper.rb
Expand Up @@ -17,17 +17,17 @@ def call(env)
env[RACK_TEMPFILES] ||= []

begin
status, headers, body = @app.call(env)
_, _, body = response = @app.call(env)
rescue Exception
env[RACK_TEMPFILES]&.each(&:close!)
raise
end

body_proxy = BodyProxy.new(body) do
response[2] = BodyProxy.new(body) do
env[RACK_TEMPFILES]&.each(&:close!)
end

[status, headers, body_proxy]
response
end
end
end