From c666b1c203c0d49f0b9c9d704502f8536e3b9362 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Mon, 12 Jun 2023 08:51:19 +0900 Subject: [PATCH] Manually chunked response body. --- config.ru | 2 +- lib/rack/conform.rb | 2 ++ lib/rack/conform/chunked.rb | 41 +++++++++++++++++++++++++++++ test/rack/conform/streaming/body.rb | 14 ++++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 lib/rack/conform/chunked.rb diff --git a/config.ru b/config.ru index 8e7d6be..30b0f78 100644 --- a/config.ru +++ b/config.ru @@ -1,2 +1,2 @@ -require_relative 'lib/rack/conform/application' +require_relative 'lib/rack/conform' run Rack::Conform::Application.new diff --git a/lib/rack/conform.rb b/lib/rack/conform.rb index a2034d8..53e90ac 100644 --- a/lib/rack/conform.rb +++ b/lib/rack/conform.rb @@ -5,3 +5,5 @@ require_relative 'conform/version' require_relative 'conform/application' + +require_relative 'conform/chunked' diff --git a/lib/rack/conform/chunked.rb b/lib/rack/conform/chunked.rb new file mode 100644 index 0000000..e09ee98 --- /dev/null +++ b/lib/rack/conform/chunked.rb @@ -0,0 +1,41 @@ + +module Rack + module Conform + module Chunked + class Body # :nodoc: + TERM = "\r\n" + TAIL = "0#{TERM}" + + # Store the response body to be chunked. + def initialize(body) + @body = body + end + + # For each element yielded by the response body, yield + # the element in chunked encoding. + def each(&block) + term = TERM + @body.each do |chunk| + size = chunk.bytesize + next if size == 0 + + yield [size.to_s(16), term, chunk.b, term].join + end + yield TAIL + yield term + end + + # Close the response body if the response body supports it. + def close + @body.close if @body.respond_to?(:close) + end + end + end + + class Application + def test_chunked_body(env) + [200, {'transfer-encoding' => 'chunked'}, Chunked::Body.new(env['rack.input'])] + end + end + end +end diff --git a/test/rack/conform/streaming/body.rb b/test/rack/conform/streaming/body.rb index 6433f9f..149cfea 100644 --- a/test/rack/conform/streaming/body.rb +++ b/test/rack/conform/streaming/body.rb @@ -18,3 +18,17 @@ response&.finish end end + +it 'can stream a chunked response' do + body = Protocol::HTTP::Body::Buffered.new([ + "Hello ", + "World!" + ]) + + response = client.post("/chunked/body", {}, body) + + expect(response.status).to be == 200 + expect(response.read).to be == "Hello World!" +ensure + response&.finish +end