Skip to content

Add priority header according to RFC9218. #74

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading