diff --git a/CHANGELOG.md b/CHANGELOG.md
index b514ec3b0..daca02c52 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,6 +24,7 @@ All notable changes to this project will be documented in this file. For info on
- `rack.hijack_io` has been removed completely.
- `rack.response_finished` is an optional environment key which contains an array of callable objects that must accept `#call(env, status, headers, error)` and are invoked after the response is finished (either successfully or unsucessfully).
- It is okay to call `#close` on `rack.input` to indicate that you no longer need or care about the input.
+- The stream argument supplied to the streaming body and hijack must support `#<<` for writing output.
### Removed
@@ -44,6 +45,7 @@ All notable changes to this project will be documented in this file. For info on
- Support callable body for explicit streaming support and clarify streaming response body behaviour. ([#1745](https://github.com/rack/rack/pull/1745), [@ioquatix], [#1748](https://github.com/rack/rack/pull/1748), [@wjordan])
- Allow `Rack::Builder#run` to take a block instead of an argument. ([#1942](https://github.com/rack/rack/pull/1942), [@ioquatix])
- Add `rack.response_finished` to `Rack::Lint`. ([#1802](https://github.com/rack/rack/pull/1802), [@BlakeWilliams], [#1952](https://github.com/rack/rack/pull/1952), [@ioquatix])
+- The stream argument must implement `#<<`. ([#1959](https://github.com/rack/rack/pull/1959), [@ioquatix])
### Changed
diff --git a/SPEC.rdoc b/SPEC.rdoc
index 48cd99d66..ddf474ae1 100644
--- a/SPEC.rdoc
+++ b/SPEC.rdoc
@@ -327,7 +327,7 @@ It must not be called after being closed.
It takes a +stream+ argument.
The +stream+ argument must implement:
-read, write, flush, close, close_read, close_write, closed?
+read, write, <<, flush, close, close_read, close_write, closed?
The semantics of these IO methods must be a best effort match to
those of a normal Ruby IO or Socket object, using standard arguments
diff --git a/lib/rack/lint.rb b/lib/rack/lint.rb
index 547e6a1c2..42878879a 100755
--- a/lib/rack/lint.rb
+++ b/lib/rack/lint.rb
@@ -861,7 +861,7 @@ def call(stream)
## It takes a +stream+ argument.
##
## The +stream+ argument must implement:
- ## read, write, flush, close, close_read, close_write, closed?
+ ## read, write, <<, flush, close, close_read, close_write, closed?
##
@body.call(StreamWrapper.new(stream))
end
@@ -875,7 +875,7 @@ class StreamWrapper
## pass on real IO objects, although it is recognized that this approach
## is not directly compatible with HTTP/2.
REQUIRED_METHODS = [
- :read, :write, :flush, :close,
+ :read, :write, :<<, :flush, :close,
:close_read, :close_write, :closed?
]