From 4ce40b4b938eea73c32a6ee3d3cbed15b7b04cab Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Tue, 17 Sep 2024 14:25:40 +1200 Subject: [PATCH] Introduce `Body#discard` for efficiently ignoring body. (#69) --- lib/protocol/http/body/buffered.rb | 6 ++++++ lib/protocol/http/body/readable.rb | 10 ++++++++++ lib/protocol/http/body/reader.rb | 8 ++++++++ lib/protocol/http/body/wrapper.rb | 4 ++++ test/protocol/http/body/buffered.rb | 8 ++++++++ test/protocol/http/body/readable.rb | 7 +++++++ test/protocol/http/body/reader.rb | 7 +++++++ test/protocol/http/body/wrapper.rb | 7 +++++++ 8 files changed, 57 insertions(+) diff --git a/lib/protocol/http/body/buffered.rb b/lib/protocol/http/body/buffered.rb index 088252b..3f3a07b 100644 --- a/lib/protocol/http/body/buffered.rb +++ b/lib/protocol/http/body/buffered.rb @@ -59,6 +59,8 @@ def finish # Ensure that future reads return nil, but allow for rewinding. def close(error = nil) @index = @chunks.length + + return nil end def clear @@ -90,6 +92,10 @@ def read end end + def discard + self.close + end + def write(chunk) @chunks << chunk end diff --git a/lib/protocol/http/body/readable.rb b/lib/protocol/http/body/readable.rb index 68e075c..ec021ce 100644 --- a/lib/protocol/http/body/readable.rb +++ b/lib/protocol/http/body/readable.rb @@ -133,6 +133,16 @@ def finish Buffered.read(self) end + # Discard the body as efficiently as possible. + # + # The default implementation simply reads all chunks until the body is empty. + # + # Useful for discarding the body when it is not needed, but preserving the underlying connection. + def discard + while chunk = self.read + end + end + def as_json(...) { class: self.class.name, diff --git a/lib/protocol/http/body/reader.rb b/lib/protocol/http/body/reader.rb index 274d6a0..8859db9 100644 --- a/lib/protocol/http/body/reader.rb +++ b/lib/protocol/http/body/reader.rb @@ -40,6 +40,14 @@ def finish end end + # Discard the body as efficiently as possible. + def discard + if body = @body + @body = nil + body.discard + end + end + # Buffer the entire request/response body. # @returns [Reader] itself. def buffered! diff --git a/lib/protocol/http/body/wrapper.rb b/lib/protocol/http/body/wrapper.rb index 7c4189b..f1dd2b7 100644 --- a/lib/protocol/http/body/wrapper.rb +++ b/lib/protocol/http/body/wrapper.rb @@ -59,6 +59,10 @@ def read @body.read end + def discard + @body.discard + end + def as_json(...) { class: self.class.name, diff --git a/test/protocol/http/body/buffered.rb b/test/protocol/http/body/buffered.rb index be72de7..b2d8a11 100644 --- a/test/protocol/http/body/buffered.rb +++ b/test/protocol/http/body/buffered.rb @@ -175,4 +175,12 @@ expect(body.inspect).to be =~ /\d+ chunks, \d+ bytes/ end end + + with "#discard" do + it "closes the body" do + expect(body).to receive(:close) + + expect(body.discard).to be == nil + end + end end diff --git a/test/protocol/http/body/readable.rb b/test/protocol/http/body/readable.rb index fadba64..dbca1a6 100644 --- a/test/protocol/http/body/readable.rb +++ b/test/protocol/http/body/readable.rb @@ -58,6 +58,13 @@ end end + with "#discard" do + it "should read all chunks" do + expect(body).to receive(:read).and_return(nil) + expect(body.discard).to be_nil + end + end + with "#as_json" do it "generates a JSON representation" do expect(body.as_json).to have_keys( diff --git a/test/protocol/http/body/reader.rb b/test/protocol/http/body/reader.rb index 49e6038..11eefc9 100644 --- a/test/protocol/http/body/reader.rb +++ b/test/protocol/http/body/reader.rb @@ -29,6 +29,13 @@ def initialize(body) end end + with "#discard" do + it 'discards the body' do + expect(body).to receive(:discard) + expect(reader.discard).to be_nil + end + end + with '#buffered!' do it 'buffers the body' do expect(reader.buffered!).to be_equal(reader) diff --git a/test/protocol/http/body/wrapper.rb b/test/protocol/http/body/wrapper.rb index 991225a..398352f 100644 --- a/test/protocol/http/body/wrapper.rb +++ b/test/protocol/http/body/wrapper.rb @@ -104,4 +104,11 @@ body.call(stream) end end + + with "#discard" do + it "should proxy discard" do + expect(source).to receive(:discard).and_return(nil) + expect(body.discard).to be_nil + end + end end