Skip to content

Commit

Permalink
Add priority header according to RFC9218. (#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix authored Nov 28, 2024
1 parent 65cbe71 commit 74fe9eb
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 0 deletions.
55 changes: 55 additions & 0 deletions lib/protocol/http/header/priority.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2024, by Samuel Williams.

require_relative "split"

module Protocol
module HTTP
module Header
# Represents the `priority` header, used to indicate the relative importance of an HTTP request.
#
# The `priority` header allows clients to express their preference for how resources should be prioritized by the server. It supports directives like `u=` to specify the urgency level of a request, and `i` to indicate whether a response can be delivered incrementally. The urgency levels range from 0 (highest priority) to 7 (lowest priority), while the `i` directive is a boolean flag.
class Priority < Split
# Initialize the priority header with the given value.
#
# @parameter value [String | Nil] the value of the priority header, if any. The value should be a comma-separated string of directives.
def initialize(value = nil)
super(value&.downcase)
end

# Add a value to the priority header.
#
# @parameter value [String] the directive to add to the header.
def << value
super(value.downcase)
end

# The default urgency level if not specified.
DEFAULT_URGENCY = 3

# Returns the urgency level if specified. 0 is the highest priority, and 7 is the lowest.
#
# @returns [Integer | Nil] the urgency level if specified, or `nil` if not present.
def urgency(default = DEFAULT_URGENCY)
if value = self.find { |value| value.start_with?("u=") }
_, level = value.split("=", 2)
return level.to_i
end

return default
end

# Checks if the response should be delivered incrementally.
#
# The `i` directive, when present, indicates that the response can be delivered incrementally as data becomes available.
#
# @returns [Boolean] whether the request should be delivered incrementally.
def incremental?
self.include?("i")
end
end
end
end
end
2 changes: 2 additions & 0 deletions lib/protocol/http/headers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
require_relative "header/vary"
require_relative "header/authorization"
require_relative "header/date"
require_relative "header/priority"

module Protocol
module HTTP
Expand Down Expand Up @@ -246,6 +247,7 @@ def []= key, value
"connection" => Header::Connection,
"cache-control" => Header::CacheControl,
"vary" => Header::Vary,
"priority" => Header::Priority,

# Headers specifically for proxies:
"via" => Split,
Expand Down
83 changes: 83 additions & 0 deletions test/protocol/http/header/priority.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2024, by Samuel Williams.

require "protocol/http/header/priority"

describe Protocol::HTTP::Header::Priority do
let(:header) { subject.new(description) }

with "u=1, i" do
it "correctly parses priority header" do
expect(header).to have_attributes(
urgency: be == 1,
incremental?: be == true,
)
end
end

with "u=0" do
it "correctly parses priority header" do
expect(header).to have_attributes(
urgency: be == 0,
incremental?: be == false,
)
end
end

with "i" do
it "correctly parses incremental flag" do
expect(header).to have_attributes(
# Default urgency level is used:
urgency: be == 3,
incremental?: be == true,
)
end
end

with "u=6" do
it "correctly parses urgency level" do
expect(header).to have_attributes(
urgency: be == 6,
)
end
end

with "u=9, i" do
it "gracefully handles non-standard urgency levels" do
expect(header).to have_attributes(
# Non-standard value is preserved
urgency: be == 9,
incremental?: be == true,
)
end
end

with "u=2, u=5" do
it "prioritizes the first urgency directive" do
expect(header).to have_attributes(
# First occurrence takes precedence
urgency: be == 2,
)
end
end

with "#<<" do
let(:header) { subject.new }

it "can append values" do
header << "u=4"
expect(header).to have_attributes(
urgency: be == 4,
)
end

it "can append incremental flag" do
header << "i"
expect(header).to have_attributes(
incremental?: be == true,
)
end
end
end

0 comments on commit 74fe9eb

Please sign in to comment.