Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 2 additions & 2 deletions lib/openai/internal/util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -428,11 +428,11 @@ def close
@stream.to_a.join
in Integer
@buf << @stream.next while @buf.length < max_len
@buf.slice!(..max_len)
@buf.slice!(0, max_len)
end
rescue StopIteration
@stream = nil
@buf.slice!(0..)
@buf.empty? ? nil : @buf.slice!(0..)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Handle EOF when read receives an output buffer

When an enumerator-backed body ends exactly on the IO.copy_stream buffer boundary, IO.copy_stream makes one more call as read(16384, outbuf). This new EOF branch now returns nil while still inside the Enumerator path, so read reaches out_string.replace(read) with read == nil and raises TypeError instead of letting Net::HTTP finish the upload. For example, an enumerator yielding exactly 16 KiB reproduces the failure through IO.copy_stream.

Useful? React with 👍 / 👎.

end

# @api private
Expand Down
17 changes: 17 additions & 0 deletions test/openai/internal/util_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,23 @@ def test_copy_read
end
end

def test_read_respects_max_len_for_enumerator
input =
Enumerator.new do |y|
y << "ab"
y << "cd"
y << "ef"
end

# rubocop:disable Lint/EmptyBlock
adapter = OpenAI::Internal::Util::ReadIOAdapter.new(input) {}
# rubocop:enable Lint/EmptyBlock

assert_equal("abc", adapter.read(3))
assert_equal("def", adapter.read(3))
assert_nil(adapter.read(3))
end

def test_copy_write
cases = {
StringIO.new => "",
Expand Down