Skip to content

Commit efb69db

Browse files
committed
Add priority header.
1 parent f0a9782 commit efb69db

File tree

4 files changed

+147
-2
lines changed

4 files changed

+147
-2
lines changed

lib/protocol/http/header/priority.rb

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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+
class Priority < Split
12+
# Urgency levels as defined in RFC 9218:
13+
#
14+
# These levels indicate the relative importance of a request, helping servers and intermediaries allocate resources efficiently. Properly setting urgency can significantly improve user-perceived performance by prioritizing critical content and deferring less important tasks.
15+
module Urgency
16+
# `background` priority indicates a request that is not time-sensitive and can be processed with minimal impact to other tasks. It is ideal for requests like analytics or logging, which do not directly impact the user's current experience.
17+
BACKGROUND = "background"
18+
19+
# `low` priority indicates a request that is important but not critical. It is suitable for content like non-blocking images, videos, or scripts that enhance the experience but do not affect core functionality.
20+
LOW = "low"
21+
22+
# `normal` priority (default) indicates the standard priority for most requests. It is appropriate for content like text, CSS, or essential images that are necessary for the primary user experience but do not require urgent delivery.
23+
NORMAL = "normal"
24+
25+
# `high` priority indicates the highest priority, used for requests that are essential and time-critical to the user experience. Examples include content above-the-fold on a webpage, critical API calls, or resources required for rendering.
26+
HIGH = "high"
27+
end
28+
29+
# The `progressive` flag indicates that the response can be delivered incrementally (progressively) as data becomes available. This is particularly useful for large resources like images or video streams, where partial delivery improves the user experience by allowing content to render or play before the full response is received.
30+
PROGRESSIVE = "progressive"
31+
32+
# Initialize the priority header with the given value.
33+
#
34+
# @parameter value [String | Nil] the value of the priority header, if any.
35+
def initialize(value = nil)
36+
super(value&.downcase)
37+
end
38+
39+
# Add a value to the priority header.
40+
def << value
41+
super(value.downcase)
42+
end
43+
44+
# Returns the urgency level if specified.
45+
#
46+
# @returns [String | Nil] the urgency level if specified, or `nil`.
47+
def urgency
48+
if value = self.find{|value| value.start_with?("urgency=")}
49+
_, level = value.split("=", 2)
50+
51+
return level
52+
end
53+
end
54+
55+
# @returns [Boolean] whether the request should be delivered progressively.
56+
def progressive?
57+
self.include?(PROGRESSIVE)
58+
end
59+
end
60+
end
61+
end
62+
end

lib/protocol/http/header/split.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ module Header
1010
class Split < Array
1111
COMMA = /\s*,\s*/
1212

13-
def initialize(value)
13+
def initialize(value = nil)
1414
if value
1515
super(value.split(COMMA))
1616
else
17-
super([])
17+
super()
1818
end
1919
end
2020

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
@@ -218,6 +219,7 @@ def []= key, value
218219
"connection" => Header::Connection,
219220
"cache-control" => Header::CacheControl,
220221
"vary" => Header::Vary,
222+
"priority" => Header::Priority,
221223

222224
# Headers specifically for proxies:
223225
"via" => Split,

test/protocol/http/header/priority.rb

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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 "urgency=low, progressive" do
12+
it "correctly parses priority header" do
13+
expect(header).to have_attributes(
14+
urgency: be == "low",
15+
progressive?: be == true,
16+
)
17+
end
18+
end
19+
20+
with "urgency=high" do
21+
it "correctly parses priority header" do
22+
expect(header).to have_attributes(
23+
urgency: be == "high",
24+
progressive?: be == false,
25+
)
26+
end
27+
end
28+
29+
with "progressive" do
30+
it "correctly parses progressive flag" do
31+
expect(header).to have_attributes(
32+
urgency: be_nil,
33+
progressive?: be == true,
34+
)
35+
end
36+
end
37+
38+
with "urgency=background" do
39+
it "correctly parses urgency" do
40+
expect(header).to have_attributes(
41+
urgency: be == "background",
42+
)
43+
end
44+
end
45+
46+
with "urgency=extreeeeem, progressive" do
47+
it "gracefully handles non-standard urgency" do
48+
expect(header).to have_attributes(
49+
# Non-standard value is preserved
50+
urgency: be == "extreeeeem",
51+
progressive?: be == true,
52+
)
53+
end
54+
end
55+
56+
with "urgency=low, urgency=high" do
57+
it "prioritizes the first urgency directive" do
58+
expect(header).to have_attributes(
59+
urgency: be == "low", # First occurrence takes precedence
60+
)
61+
end
62+
end
63+
64+
with "#<<" do
65+
let(:header) {subject.new}
66+
67+
it "can append values" do
68+
header << "urgency=low"
69+
expect(header).to have_attributes(
70+
urgency: be == "low",
71+
)
72+
end
73+
74+
it "can append progressive flag" do
75+
header << "progressive"
76+
expect(header).to have_attributes(
77+
progressive?: be == true,
78+
)
79+
end
80+
end
81+
end

0 commit comments

Comments
 (0)