diff --git a/lib/http/response/body.rb b/lib/http/response/body.rb index 557db352..6eab7e48 100644 --- a/lib/http/response/body.rb +++ b/lib/http/response/body.rb @@ -20,14 +20,15 @@ def initialize(stream, length: nil, encoding: Encoding::BINARY) @connection = stream.is_a?(Inflater) ? stream.connection : stream @streaming = nil @contents = nil - @encoding = encoding + @encoding = find_encoding(encoding) @length = length || Float::INFINITY end # (see HTTP::Client#readpartial) def readpartial(*args) stream! - @stream.readpartial(*args) + chunk = @stream.readpartial(*args) + chunk.force_encoding(@encoding) if chunk end # Iterate over the body, allowing it to be enumerable @@ -43,22 +44,15 @@ def to_s raise StateError, "body is being streamed" unless @streaming.nil? - # see issue 312 - begin - encoding = Encoding.find @encoding - rescue ArgumentError - encoding = Encoding::BINARY - end - begin @streaming = false - @contents = String.new("").force_encoding(encoding) + @contents = String.new("").force_encoding(@encoding) length = @length while length > 0 && (chunk = @stream.readpartial) length -= chunk.bytesize - @contents << chunk.force_encoding(encoding) + @contents << chunk.force_encoding(@encoding) end rescue @contents = nil @@ -79,6 +73,15 @@ def stream! def inspect "#<#{self.class}:#{object_id.to_s(16)} @streaming=#{!!@streaming}>" end + + private + + # Retrieve encoding by name. If encoding cannot be found, default to binary. + def find_encoding(encoding) + Encoding.find encoding + rescue ArgumentError + Encoding::BINARY + end end end end diff --git a/spec/lib/http/response/body_spec.rb b/spec/lib/http/response/body_spec.rb index fec54231..bf013705 100644 --- a/spec/lib/http/response/body_spec.rb +++ b/spec/lib/http/response/body_spec.rb @@ -37,6 +37,18 @@ body.readpartial end end + + it "returns content in specified encoding" do + body = described_class.new(connection) + expect(connection).to receive(:readpartial). + and_return(String.new("content").force_encoding(Encoding::UTF_8)) + expect(body.readpartial.encoding).to eq Encoding::BINARY + + body = described_class.new(connection, :encoding => Encoding::UTF_8) + expect(connection).to receive(:readpartial). + and_return(String.new("content").force_encoding(Encoding::BINARY)) + expect(body.readpartial.encoding).to eq Encoding::UTF_8 + end end context "when body is gzipped" do @@ -58,7 +70,7 @@ it "streams decoded body" do [ "Hi, HTTP ", - String.new("here ☺").force_encoding("ASCII-8BIT"), + "here ☺", nil ].each do |part| expect(subject.readpartial).to eq(part)