diff --git a/lib/protocol/http/body/head.rb b/lib/protocol/http/body/head.rb index 0e89ee3..2a7b0bd 100644 --- a/lib/protocol/http/body/head.rb +++ b/lib/protocol/http/body/head.rb @@ -12,12 +12,24 @@ module Body # Represents a body suitable for HEAD requests, in other words, a body that is empty and has a known length. class Head < Readable # Create a head body for the given body, capturing its length and then closing it. - def self.for(body) - head = self.new(body.length) - - body.close + # + # If a body is provided, the length is determined from the body, and the body is closed. + # If no body is provided, and the content length is provided, a head body is created with that length. + # This is useful for creating a head body when you only know the content length but not the actual body, which may happen in adapters for HTTP applications where the application may not provide a body for HEAD requests, but the content length is known. + # + # @parameter body [Readable | Nil] the body to create a head for. + # @parameter length [Integer | Nil] the content length of the body, if known. + # @returns [Head | Nil] the head body, or nil if the body is nil. + def self.for(body, length = nil) + if body + head = self.new(body.length) + body.close + return head + elsif length + return self.new(length) + end - return head + return nil end # Initialize the head body with the given length. diff --git a/releases.md b/releases.md index e8cef03..10a16fe 100644 --- a/releases.md +++ b/releases.md @@ -4,6 +4,7 @@ - `Protocol::HTTP::Headers` now raise a `DuplicateHeaderError` when a duplicate singleton header (e.g. `content-length`) is added. - `Protocol::HTTP::Headers#add` now coerces the value to a string when adding a header, ensuring consistent behaviour. + - `Protocol::HTTP::Body::Head.for` now accepts an optional `length` parameter, allowing it to create a head body even when the body is not provided, based on the known content length. ## v0.50.0 diff --git a/test/protocol/http/body/head.rb b/test/protocol/http/body/head.rb index 7aee400..17bd1d8 100644 --- a/test/protocol/http/body/head.rb +++ b/test/protocol/http/body/head.rb @@ -46,14 +46,33 @@ end with ".for" do - let(:source) {Protocol::HTTP::Body::Buffered.wrap("!")} - let(:body) {subject.for(source)} + with "body" do + let(:source) {Protocol::HTTP::Body::Buffered.wrap("!")} + let(:body) {subject.for(source)} + + it "captures length and closes existing body" do + expect(source).to receive(:close) + + expect(body).to have_attributes(length: be == 1) + body.close + end + end - it "captures length and closes existing body" do - expect(source).to receive(:close) + with "content length" do + let(:body) {subject.for(nil, 42)} - expect(body).to have_attributes(length: be == 1) - body.close + it "uses the content length if no body is provided" do + expect(body).to have_attributes(length: be == 42) + expect(body).to be(:empty?) + expect(body).to be(:ready?) + end + end + end + + with ".for with nil body" do + it "returns nil when body is nil" do + body = subject.for(nil) + expect(body).to be_nil end end end