Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- `HTTP::Response::Body#each` now accepts a `buffer_size:` keyword argument
to control the chunk size used when streaming the body, instead of always
using `HTTP::Connection::BUFFER_SIZE` (16KB). ([#782])

### Fixed

- Building a default `Host` header now raises `HTTP::RequestError` when the
Expand Down Expand Up @@ -293,6 +299,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`Request` and `Response`. Use `request.headers["..."]` and
`response.headers["..."]` instead ([#537])

[#782]: https://github.com/httprb/http/issues/782
[#270]: https://github.com/httprb/http/issues/270
[#223]: https://github.com/httprb/http/issues/223
[#358]: https://github.com/httprb/http/issues/358
Expand Down
8 changes: 6 additions & 2 deletions lib/http/response/body.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,17 @@ def readpartial(*)
# @example
# body.each { |chunk| puts chunk }
#
# @example
# body.each(buffer_size: 1.megabyte) { |chunk| puts chunk }
#
# @param buffer_size [Integer] the maximum size of each yielded chunk
# @yield [chunk] Passes each chunk to the block
# @yieldparam chunk [String]
# @return [void]
# @api public
def each
def each(buffer_size: Connection::BUFFER_SIZE)
loop do
yield readpartial
yield readpartial(buffer_size)
end
rescue EOFError # rubocop:disable Lint/SuppressedException
end
Expand Down
4 changes: 2 additions & 2 deletions sig/http.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -1034,8 +1034,8 @@ module HTTP

def initialize: (untyped stream, ?encoding: String | Encoding) -> void
def readpartial: (?Integer size, ?String? outbuf) -> String
def each: () { (String) -> void } -> void
| () -> Enumerator[String, void]
def each: (?buffer_size: Integer) { (String) -> void } -> void
| (?buffer_size: Integer) -> Enumerator[String, void]
def to_s: () -> untyped
alias to_str to_s
def stream!: () -> untyped
Expand Down
28 changes: 28 additions & 0 deletions test/http/response/body_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,34 @@ def test_each_yields_each_chunk
assert_equal "Hello, World!", collected.join
end

def test_each_passes_buffer_size_to_underlying_readpartial
received_sizes = []
conn = Object.new
conn.define_singleton_method(:readpartial) do |size = nil|
received_sizes << size
raise EOFError if received_sizes.size > 1

"data"
end
body = HTTP::Response::Body.new(conn, encoding: Encoding::UTF_8)
body.each(buffer_size: 1_048_576) { |chunk| chunk }

assert_equal [1_048_576, 1_048_576], received_sizes
end

def test_each_defaults_buffer_size_to_connection_buffer_size
received_sizes = []
conn = Object.new
conn.define_singleton_method(:readpartial) do |size = nil|
received_sizes << size
raise EOFError
end
body = HTTP::Response::Body.new(conn, encoding: Encoding::UTF_8)
body.each { |chunk| chunk }

assert_equal [HTTP::Connection::BUFFER_SIZE], received_sizes
end

# ---------------------------------------------------------------------------
# #to_s when streaming
# ---------------------------------------------------------------------------
Expand Down
Loading