diff --git a/lib/protocol/http2/error.rb b/lib/protocol/http2/error.rb index ed0ee82..492758d 100644 --- a/lib/protocol/http2/error.rb +++ b/lib/protocol/http2/error.rb @@ -50,6 +50,33 @@ class Error < HTTP::Error # The endpoint requires that HTTP/1.1 be used instead of HTTP/2. HTTP_1_1_REQUIRED = 0xD + + MESSAGES = { + NO_ERROR => "No error.", + PROTOCOL_ERROR => "Protocol error!", + INTERNAL_ERROR => "Internal error!", + FLOW_CONTROL_ERROR => "Flow control error!", + SETTINGS_TIMEOUT => "Settings timeout!", + STREAM_CLOSED => "Stream closed!", + FRAME_SIZE_ERROR => "Frame size error!", + REFUSED_STREAM => "Stream refused.", + CANCEL => "Stream cancelled.", + COMPRESSION_ERROR => "Compression error!", + CONNECT_ERROR => "Connect error!", + ENHANCE_YOUR_CALM => "Enhance your calm!", + INADEQUATE_SECURITY => "Inadequate security!", + HTTP_1_1_REQUIRED => "HTTP/1.1 required.", + } + + # Get the message for a given HTTP/2 error code. + # @parameter code [Integer] The HTTP/2 error code. + # @returns [String] The error message. + def self.message_for(code) + return MESSAGES.fetch(code) do + # Unknown error codes are allowed by the protocol, but don't have a static message. + "Unknown code: #{code}!" + end + end end # Raised if connection header is missing or invalid indicating that @@ -62,6 +89,13 @@ class HandshakeError < Error # which signals termination of the current connection. You *cannot* # recover from this exception, or any exceptions subclassed from it. class ProtocolError < Error + # Build a protocol error for a given HTTP/2 error code. + # @parameter code [Integer] The HTTP/2 error code. + # @returns [ProtocolError] The protocol error. + def self.for(code) + return self.new(Error.message_for(code), code) + end + # Initialize a protocol error with message and error code. # @parameter message [String] The error message. # @parameter code [Integer] The HTTP/2 error code. diff --git a/lib/protocol/http2/stream.rb b/lib/protocol/http2/stream.rb index 5748964..dc13f8e 100644 --- a/lib/protocol/http2/stream.rb +++ b/lib/protocol/http2/stream.rb @@ -253,7 +253,7 @@ def close!(error_code = nil) if error_code == REFUSED_STREAM error = ::Protocol::HTTP::RefusedError.new("Stream refused.") else - error = StreamError.new("Stream closed!", error_code) + error = StreamError.for(error_code) end end diff --git a/releases.md b/releases.md index 5b79d33..5bbd93a 100644 --- a/releases.md +++ b/releases.md @@ -1,5 +1,9 @@ # Releases +## Unreleased + + - Improve `StreamError` messages for HTTP/2 stream reset error codes. + ## v0.26.0 - On RST\_STREAM with REFUSED\_STREAM, close the stream with `Protocol::HTTP::RefusedError` instead of `StreamError`. diff --git a/test/protocol/http2/error.rb b/test/protocol/http2/error.rb index 950460e..1392eb2 100644 --- a/test/protocol/http2/error.rb +++ b/test/protocol/http2/error.rb @@ -5,6 +5,50 @@ require "protocol/http2/error" +describe Protocol::HTTP2::Error do + with ".message_for" do + it "returns a static message for a known error code" do + expect(subject.message_for(subject::CANCEL)).to be == "Stream cancelled." + end + + it "returns a fallback message for an unknown error code" do + expect(subject.message_for(99)).to be == "Unknown code: 99!" + end + end +end + +describe Protocol::HTTP2::ProtocolError do + with ".for" do + it "builds a protocol error for a known error code" do + error = subject.for(subject::PROTOCOL_ERROR) + + expect(error).to be_a(subject) + expect(error.message).to be == "Protocol error!" + expect(error.code).to be == subject::PROTOCOL_ERROR + end + end +end + +describe Protocol::HTTP2::StreamError do + with ".for" do + it "builds a stream error for a known error code" do + error = subject.for(Protocol::HTTP2::Error::CANCEL) + + expect(error).to be_a(subject) + expect(error.message).to be == "Stream cancelled." + expect(error.code).to be == Protocol::HTTP2::Error::CANCEL + end + + it "builds a stream error for an unknown error code" do + error = subject.for(99) + + expect(error).to be_a(subject) + expect(error.message).to be == "Unknown code: 99!" + expect(error.code).to be == 99 + end + end +end + describe Protocol::HTTP2::HeaderError do let(:error) {subject.new("Invalid header key")}