Summary
OpenAI::Internal::Util::ReadIOAdapter#read(max_len) can return more than max_len bytes when wrapping an Enumerator. The buffered enumerator path currently slices with an inclusive range, so read(3) can return 4 bytes and read(0) can consume data.
Reproduction
adapter = OpenAI::Internal::Util::ReadIOAdapter.new(["abc", "def"].to_enum) {}
p adapter.read(0)
p adapter.read(1)
p adapter.read(3)
p adapter.read(99)
p adapter.read(1)
Expected
Actual
Impact
This adapter is used for streamed request bodies, including multipart uploads. IO#read(max_len) is byte-oriented, so returning more than max_len bytes can violate callers' expectations when an upload body is backed by an Enumerator. The same code path should use byte lengths rather than character lengths for buffered reads.
Summary
OpenAI::Internal::Util::ReadIOAdapter#read(max_len)can return more thanmax_lenbytes when wrapping anEnumerator. The buffered enumerator path currently slices with an inclusive range, soread(3)can return 4 bytes andread(0)can consume data.Reproduction
Expected
Actual
Impact
This adapter is used for streamed request bodies, including multipart uploads.
IO#read(max_len)is byte-oriented, so returning more thanmax_lenbytes can violate callers' expectations when an upload body is backed by anEnumerator. The same code path should use byte lengths rather than character lengths for buffered reads.