diff --git a/lib/protocol/http1/connection.rb b/lib/protocol/http1/connection.rb index 056ccb6..c796d08 100644 --- a/lib/protocol/http1/connection.rb +++ b/lib/protocol/http1/connection.rb @@ -266,6 +266,8 @@ def write_request(authority, method, target, version, headers) @stream.write("host: #{authority}\r\n") if authority write_headers(headers) + rescue + raise ::Protocol::HTTP::RequestRefusedError end # Write a response to the connection. It is expected you will write the body after this method. diff --git a/protocol-http1.gemspec b/protocol-http1.gemspec index 0c1107b..ee9e200 100644 --- a/protocol-http1.gemspec +++ b/protocol-http1.gemspec @@ -24,5 +24,5 @@ Gem::Specification.new do |spec| spec.required_ruby_version = ">= 3.3" - spec.add_dependency "protocol-http", "~> 0.58" + spec.add_dependency "protocol-http", "~> 0.61" end diff --git a/releases.md b/releases.md index b12d3e3..baf186f 100644 --- a/releases.md +++ b/releases.md @@ -1,5 +1,9 @@ # Releases +## Unreleased + + - `write_request` now raises `Protocol::HTTP::RequestRefusedError` if the request line or headers cannot be written, indicating the request was not processed and can be safely retried. + ## v0.37.1 - Defer `body.close` in `write_chunked_body`, `write_fixed_length_body`, and `write_body_and_close` until after the response is fully written and flushed. Previously, `body.each` called `close` in its `ensure` block before the terminal chunk (chunked encoding) or final flush was written, causing `rack.response_finished` callbacks to delay the client-visible response completion. diff --git a/test/protocol/http1/connection.rb b/test/protocol/http1/connection.rb index 185f465..7f42057 100644 --- a/test/protocol/http1/connection.rb +++ b/test/protocol/http1/connection.rb @@ -699,12 +699,20 @@ expect(client).to be(:closed?) end + it "raises RequestRefusedError when the stream is broken" do + client.stream.close + + expect do + client.write_request("localhost", "GET", "/", "HTTP/1.1", {}) + end.to raise_exception(Protocol::HTTP::RequestRefusedError) + end + it "can't write a request in the closed state" do client.state = :closed expect do client.write_request("localhost", "GET", "/", "HTTP/1.0", {}) - end.to raise_exception(Protocol::HTTP1::ProtocolError) + end.to raise_exception(Protocol::HTTP::RequestRefusedError) end it "can't read a response in the closed state" do