Skip to content

Commit 74fe9eb

Browse files
authored
Add priority header according to RFC9218. (#74)
1 parent 65cbe71 commit 74fe9eb

File tree

3 files changed

+140
-0
lines changed

3 files changed

+140
-0
lines changed

lib/protocol/http/header/priority.rb

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# frozen_string_literal: true
2+
3+
# Released under the MIT License.
4+
# Copyright, 2024, by Samuel Williams.
5+
6+
require_relative "split"
7+
8+
module Protocol
9+
module HTTP
10+
module Header
11+
# Represents the `priority` header, used to indicate the relative importance of an HTTP request.
12+
#
13+
# 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.
14+
class Priority < Split
15+
# Initialize the priority header with the given value.
16+
#
17+
# @parameter value [String | Nil] the value of the priority header, if any. The value should be a comma-separated string of directives.
18+
def initialize(value = nil)
19+
super(value&.downcase)
20+
end
21+
22+
# Add a value to the priority header.
23+
#
24+
# @parameter value [String] the directive to add to the header.
25+
def << value
26+
super(value.downcase)
27+
end
28+
29+
# The default urgency level if not specified.
30+
DEFAULT_URGENCY = 3
31+
32+
# Returns the urgency level if specified. 0 is the highest priority, and 7 is the lowest.
33+
#
34+
# @returns [Integer | Nil] the urgency level if specified, or `nil` if not present.
35+
def urgency(default = DEFAULT_URGENCY)
36+
if value = self.find { |value| value.start_with?("u=") }
37+
_, level = value.split("=", 2)
38+
return level.to_i
39+
end
40+
41+
return default
42+
end
43+
44+
# Checks if the response should be delivered incrementally.
45+
#
46+
# The `i` directive, when present, indicates that the response can be delivered incrementally as data becomes available.
47+
#
48+
# @returns [Boolean] whether the request should be delivered incrementally.
49+
def incremental?
50+
self.include?("i")
51+
end
52+
end
53+
end
54+
end
55+
end

lib/protocol/http/headers.rb

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
require_relative "header/vary"
1414
require_relative "header/authorization"
1515
require_relative "header/date"
16+
require_relative "header/priority"
1617

1718
module Protocol
1819
module HTTP
@@ -246,6 +247,7 @@ def []= key, value
246247
"connection" => Header::Connection,
247248
"cache-control" => Header::CacheControl,
248249
"vary" => Header::Vary,
250+
"priority" => Header::Priority,
249251

250252
# Headers specifically for proxies:
251253
"via" => Split,

test/protocol/http/header/priority.rb

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# frozen_string_literal: true
2+
3+
# Released under the MIT License.
4+
# Copyright, 2024, by Samuel Williams.
5+
6+
require "protocol/http/header/priority"
7+
8+
describe Protocol::HTTP::Header::Priority do
9+
let(:header) { subject.new(description) }
10+
11+
with "u=1, i" do
12+
it "correctly parses priority header" do
13+
expect(header).to have_attributes(
14+
urgency: be == 1,
15+
incremental?: be == true,
16+
)
17+
end
18+
end
19+
20+
with "u=0" do
21+
it "correctly parses priority header" do
22+
expect(header).to have_attributes(
23+
urgency: be == 0,
24+
incremental?: be == false,
25+
)
26+
end
27+
end
28+
29+
with "i" do
30+
it "correctly parses incremental flag" do
31+
expect(header).to have_attributes(
32+
# Default urgency level is used:
33+
urgency: be == 3,
34+
incremental?: be == true,
35+
)
36+
end
37+
end
38+
39+
with "u=6" do
40+
it "correctly parses urgency level" do
41+
expect(header).to have_attributes(
42+
urgency: be == 6,
43+
)
44+
end
45+
end
46+
47+
with "u=9, i" do
48+
it "gracefully handles non-standard urgency levels" do
49+
expect(header).to have_attributes(
50+
# Non-standard value is preserved
51+
urgency: be == 9,
52+
incremental?: be == true,
53+
)
54+
end
55+
end
56+
57+
with "u=2, u=5" do
58+
it "prioritizes the first urgency directive" do
59+
expect(header).to have_attributes(
60+
# First occurrence takes precedence
61+
urgency: be == 2,
62+
)
63+
end
64+
end
65+
66+
with "#<<" do
67+
let(:header) { subject.new }
68+
69+
it "can append values" do
70+
header << "u=4"
71+
expect(header).to have_attributes(
72+
urgency: be == 4,
73+
)
74+
end
75+
76+
it "can append incremental flag" do
77+
header << "i"
78+
expect(header).to have_attributes(
79+
incremental?: be == true,
80+
)
81+
end
82+
end
83+
end

0 commit comments

Comments
 (0)