summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2023-03-24 17:01:03 -0700
committerGitHub <noreply@github.com>2023-03-24 17:01:03 -0700
commitb172805895fc0490bf81e942487233e6771f4643 (patch)
tree893721c432e2dac98f2a0345bdfe9497a3b76aa7
parentd4c159f66a0bbf92be2512df2099698097d42120 (diff)
downloadrack-b172805895fc0490bf81e942487233e6771f4643.tar.gz
Handle string reuse by body.each when buffering bodies in Rack::Response (#2044)
An alternative approach would be using a single string inside an array and appending to that. This approach is more backwards compatible, but results in more memory usage. Fixes #1957
-rw-r--r--lib/rack/response.rb1
-rw-r--r--test/spec_response.rb20
2 files changed, 21 insertions, 0 deletions
diff --git a/lib/rack/response.rb b/lib/rack/response.rb
index 4a6af373..20a87159 100644
--- a/lib/rack/response.rb
+++ b/lib/rack/response.rb
@@ -342,6 +342,7 @@ module Rack
end
def append(chunk)
+ chunk = chunk.dup unless chunk.frozen?
@body << chunk
unless chunked?
diff --git a/test/spec_response.rb b/test/spec_response.rb
index 68227fa6..6a6957e5 100644
--- a/test/spec_response.rb
+++ b/test/spec_response.rb
@@ -604,6 +604,26 @@ describe Rack::Response do
res.finish.last.must_equal ["Foo", "Bar"]
end
+ it "handles string reuse in existing body when calling #write" do
+ body_class = Class.new do
+ def initialize(file)
+ @file = file
+ end
+
+ def each
+ buffer = String.new
+
+ while @file.read(5, buffer)
+ yield(buffer)
+ end
+ end
+ end
+ body = body_class.new(StringIO.new('Large large file content'))
+ res = Rack::Response.new(body)
+ res.write(" written")
+ res.finish.last.must_equal ["Large", " larg", "e fil", "e con", "tent", " written"]
+ end
+
it "calls close on #body" do
res = Rack::Response.new
res.body = StringIO.new