Skip to content

Commit 2d1b628

Browse files
committed
Improved documentation for Protocol::HTTP::Header.
1 parent dd3b233 commit 2d1b628

File tree

11 files changed

+172
-23
lines changed

11 files changed

+172
-23
lines changed

lib/protocol/http/header/authorization.rb

+10-2
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,21 @@ module Header
1212
# ~~~ ruby
1313
# headers.add('authorization', Authorization.basic("my_username", "my_password"))
1414
# ~~~
15+
#
16+
# TODO Support other authorization mechanisms, e.g. bearer token.
1517
class Authorization < String
16-
# Splits the header and
17-
# @return [Tuple(String, String)]
18+
# Splits the header into the credentials.
19+
#
20+
# @returns [Tuple(String, String)] The username and password.
1821
def credentials
1922
self.split(/\s+/, 2)
2023
end
2124

25+
# Generate a new basic authorization header, encoding the given username and password.
26+
#
27+
# @parameter username [String] The username.
28+
# @parameter password [String] The password.
29+
# @returns [Authorization] The basic authorization header.
2230
def self.basic(username, password)
2331
strict_base64_encoded = ["#{username}:#{password}"].pack("m0")
2432

lib/protocol/http/header/cache_control.rb

+42-10
Original file line numberDiff line numberDiff line change
@@ -9,86 +9,118 @@
99
module Protocol
1010
module HTTP
1111
module Header
12+
# Represents the `cache-control` header, which is a list of cache directives.
1213
class CacheControl < Split
14+
# The `private` directive indicates that the response is intended for a single user and must not be stored by shared caches.
1315
PRIVATE = "private"
16+
17+
# The `public` directive indicates that the response may be stored by any cache, even if it would normally be considered non-cacheable.
1418
PUBLIC = "public"
19+
20+
# The `no-cache` directive indicates that caches must revalidate the response with the origin server before serving it to clients.
1521
NO_CACHE = "no-cache"
22+
23+
# The `no-store` directive indicates that caches must not store the response under any circumstances.
1624
NO_STORE = "no-store"
25+
26+
# The `max-age` directive indicates the maximum amount of time, in seconds, that a response is considered fresh.
1727
MAX_AGE = "max-age"
28+
29+
# The `s-maxage` directive is similar to `max-age` but applies only to shared caches. If both `s-maxage` and `max-age` are present, `s-maxage` takes precedence in shared caches.
1830
S_MAXAGE = "s-maxage"
1931

32+
# The `static` directive is a custom directive often used to indicate that the resource is immutable or rarely changes, allowing longer caching periods.
2033
STATIC = "static"
34+
35+
# The `dynamic` directive is a custom directive used to indicate that the resource is generated dynamically and may change frequently, requiring shorter caching periods.
2136
DYNAMIC = "dynamic"
37+
38+
# The `streaming` directive is a custom directive used to indicate that the resource is intended for progressive or chunked delivery, such as live video streams.
2239
STREAMING = "streaming"
2340

41+
# The `must-revalidate` directive indicates that once a response becomes stale, caches must not use it to satisfy subsequent requests without revalidating it with the origin server.
2442
MUST_REVALIDATE = "must-revalidate"
43+
44+
# The `proxy-revalidate` directive is similar to `must-revalidate` but applies only to shared caches.
2545
PROXY_REVALIDATE = "proxy-revalidate"
2646

47+
# Initializes the cache control header with the given value. The value is expected to be a comma-separated string of cache directives.
48+
#
49+
# @parameter value [String | Nil] the raw Cache-Control header value.
2750
def initialize(value = nil)
2851
super(value&.downcase)
2952
end
3053

54+
# Adds a directive to the Cache-Control header. The value will be normalized to lowercase before being added.
55+
#
56+
# @parameter value [String] the directive to add.
3157
def << value
3258
super(value.downcase)
3359
end
3460

61+
# @returns [Boolean] whether the `static` directive is present.
3562
def static?
3663
self.include?(STATIC)
3764
end
3865

66+
# @returns [Boolean] whether the `dynamic` directive is present.
3967
def dynamic?
4068
self.include?(DYNAMIC)
4169
end
4270

71+
# @returns [Boolean] whether the `streaming` directive is present.
4372
def streaming?
4473
self.include?(STREAMING)
4574
end
4675

76+
# @returns [Boolean] whether the `private` directive is present.
4777
def private?
4878
self.include?(PRIVATE)
4979
end
5080

81+
# @returns [Boolean] whether the `public` directive is present.
5182
def public?
5283
self.include?(PUBLIC)
5384
end
5485

86+
# @returns [Boolean] whether the `no-cache` directive is present.
5587
def no_cache?
5688
self.include?(NO_CACHE)
5789
end
5890

91+
# @returns [Boolean] whether the `no-store` directive is present.
5992
def no_store?
6093
self.include?(NO_STORE)
6194
end
6295

63-
# Indicates that a response must not be used once it is stale.
64-
# See https://www.rfc-editor.org/rfc/rfc9111.html#name-must-revalidate
96+
# @returns [Boolean] whether the `must-revalidate` directive is present.
6597
def must_revalidate?
6698
self.include?(MUST_REVALIDATE)
6799
end
68100

69-
# Like must-revalidate, but for shared caches only.
70-
# See https://www.rfc-editor.org/rfc/rfc9111.html#name-proxy-revalidate
101+
# @returns [Boolean] whether the `proxy-revalidate` directive is present.
71102
def proxy_revalidate?
72103
self.include?(PROXY_REVALIDATE)
73104
end
74105

75-
# The maximum time, in seconds, a response should be considered fresh.
76-
# See https://www.rfc-editor.org/rfc/rfc9111.html#name-max-age-2
106+
# @returns [Integer | Nil] the value of the `max-age` directive in seconds, or `nil` if the directive is not present or invalid.
77107
def max_age
78108
find_integer_value(MAX_AGE)
79109
end
80110

81-
# Like max-age, but for shared caches only, which should use it before
82-
# max-age when present.
83-
# See https://www.rfc-editor.org/rfc/rfc9111.html#name-s-maxage
111+
# @returns [Integer | Nil] the value of the `s-maxage` directive in seconds, or `nil` if the directive is not present or invalid.
84112
def s_maxage
85113
find_integer_value(S_MAXAGE)
86114
end
87115

88116
private
89117

118+
# Finds and parses an integer value from a directive.
119+
#
120+
# @parameter value_name [String] the directive name to search for (e.g., "max-age").
121+
# @returns [Integer | Nil] the parsed integer value, or `nil` if not found or invalid.
90122
def find_integer_value(value_name)
91-
if value = self.find{|value| value.start_with?(value_name)}
123+
if value = self.find { |value| value.start_with?(value_name) }
92124
_, age = value.split("=", 2)
93125

94126
if age =~ /\A[0-9]+\z/

lib/protocol/http/header/connection.rb

+18-1
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,48 @@
99
module Protocol
1010
module HTTP
1111
module Header
12+
# Represents the `connection` HTTP header, which controls options for the current connection.
13+
#
14+
# The `connection` header is used to specify control options such as whether the connection should be kept alive, closed, or upgraded to a different protocol.
1215
class Connection < Split
16+
# The `keep-alive` directive indicates that the connection should remain open for future requests or responses, avoiding the overhead of opening a new connection.
1317
KEEP_ALIVE = "keep-alive"
18+
19+
# The `close` directive indicates that the connection should be closed after the current request and response are complete.
1420
CLOSE = "close"
21+
22+
# The `upgrade` directive indicates that the connection should be upgraded to a different protocol, as specified in the `Upgrade` header.
1523
UPGRADE = "upgrade"
1624

25+
# Initializes the connection header with the given value. The value is expected to be a comma-separated string of directives.
26+
#
27+
# @parameter value [String | Nil] the raw `connection` header value.
1728
def initialize(value = nil)
1829
super(value&.downcase)
1930
end
2031

32+
# Adds a directive to the `connection` header. The value will be normalized to lowercase before being added.
33+
#
34+
# @parameter value [String] the directive to add.
2135
def << value
2236
super(value.downcase)
2337
end
2438

39+
# @returns [Boolean] whether the `keep-alive` directive is present and the connection is not marked for closure with the `close` directive.
2540
def keep_alive?
2641
self.include?(KEEP_ALIVE) && !close?
2742
end
2843

44+
# @returns [Boolean] whether the `close` directive is present, indicating that the connection should be closed after the current request and response.
2945
def close?
3046
self.include?(CLOSE)
3147
end
3248

49+
# @returns [Boolean] whether the `upgrade` directive is present, indicating that the connection should be upgraded to a different protocol.
3350
def upgrade?
3451
self.include?(UPGRADE)
3552
end
3653
end
3754
end
3855
end
39-
end
56+
end

lib/protocol/http/header/cookie.rb

+10-3
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@
99
module Protocol
1010
module HTTP
1111
module Header
12-
# The Cookie HTTP request header contains stored HTTP cookies previously sent by the server with the Set-Cookie header.
12+
# The `cookie` header contains stored HTTP cookies previously sent by the server with the `set-cookie` header.
13+
#
14+
# It is used by clients to send key-value pairs representing stored cookies back to the server.
1315
class Cookie < Multiple
16+
# Parses the `cookie` header into a hash of cookie names and their corresponding cookie objects.
17+
#
18+
# @returns [Hash(String, HTTP::Cookie)] a hash where keys are cookie names and values are {HTTP::Cookie} objects.
1419
def to_h
1520
cookies = self.collect do |string|
1621
HTTP::Cookie.parse(string)
@@ -20,9 +25,11 @@ def to_h
2025
end
2126
end
2227

23-
# The Set-Cookie HTTP response header sends cookies from the server to the user agent.
28+
# The `set-cookie` header sends cookies from the server to the user agent.
29+
#
30+
# It is used to store cookies on the client side, which are then sent back to the server in subsequent requests using the `cookie` header.
2431
class SetCookie < Cookie
2532
end
2633
end
2734
end
28-
end
35+
end

lib/protocol/http/header/date.rb

+9
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,20 @@
88
module Protocol
99
module HTTP
1010
module Header
11+
# The `date` header represents the date and time at which the message was originated.
12+
#
13+
# This header is typically included in HTTP responses and follows the format defined in RFC 9110.
1114
class Date < String
15+
# Replaces the current value of the `date` header with the specified value.
16+
#
17+
# @parameter value [String] the new value for the `date` header.
1218
def << value
1319
replace(value)
1420
end
1521

22+
# Converts the `date` header value to a `Time` object.
23+
#
24+
# @returns [Time] the parsed time object corresponding to the `date` header value.
1625
def to_time
1726
::Time.parse(self)
1827
end

lib/protocol/http/header/etag.rb

+11
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,22 @@
66
module Protocol
77
module HTTP
88
module Header
9+
# The `etag` header represents the entity tag for a resource.
10+
#
11+
# The `etag` header provides a unique identifier for a specific version of a resource, typically used for cache validation or conditional requests. It can be either a strong or weak validator as defined in RFC 9110.
912
class ETag < String
13+
# Replaces the current value of the `etag` header with the specified value.
14+
#
15+
# @parameter value [String] the new value for the `etag` header.
1016
def << value
1117
replace(value)
1218
end
1319

20+
# Checks whether the `etag` is a weak validator.
21+
#
22+
# Weak validators indicate semantically equivalent content but may not be byte-for-byte identical.
23+
#
24+
# @returns [Boolean] whether the `etag` is weak.
1425
def weak?
1526
self.start_with?("W/")
1627
end

lib/protocol/http/header/etags.rb

+35-4
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,63 @@
99
module Protocol
1010
module HTTP
1111
module Header
12+
# The `etags` header represents a list of entity tags (ETags) for resources.
13+
#
14+
# The `etags` header is used for conditional requests to compare the current version of a resource with previously stored versions. It supports both strong and weak validators, as well as the wildcard character (`*`) to indicate a match for any resource.
1215
class ETags < Split
16+
# Checks if the `etags` header contains the wildcard (`*`) character.
17+
#
18+
# The wildcard character matches any resource version, regardless of its actual value.
19+
#
20+
# @returns [Boolean] whether the wildcard is present.
1321
def wildcard?
1422
self.include?("*")
1523
end
1624

17-
# This implementation is not strictly correct according to the RFC-specified format.
25+
# Checks if the specified ETag matches the `etags` header.
26+
#
27+
# This method returns `true` if the wildcard is present or if the exact ETag is found in the list. Note that this implementation is not strictly compliant with the RFC-specified format.
28+
#
29+
# @parameter etag [String] the ETag to compare against the `etags` header.
30+
# @returns [Boolean] whether the specified ETag matches.
1831
def match?(etag)
1932
wildcard? || self.include?(etag)
2033
end
2134

22-
# Useful with If-Match
35+
# Checks for a strong match with the specified ETag, useful with the `if-match` header.
36+
#
37+
# A strong match requires that the ETag in the header list matches the specified ETag and that neither is a weak validator.
38+
#
39+
# @parameter etag [String] the ETag to compare against the `etags` header.
40+
# @returns [Boolean] whether a strong match is found.
2341
def strong_match?(etag)
2442
wildcard? || (!weak_tag?(etag) && self.include?(etag))
2543
end
2644

27-
# Useful with If-None-Match
45+
# Checks for a weak match with the specified ETag, useful with the `if-none-match` header.
46+
#
47+
# A weak match allows for semantically equivalent content, including weak validators and their strong counterparts.
48+
#
49+
# @parameter etag [String] the ETag to compare against the `etags` header.
50+
# @returns [Boolean] whether a weak match is found.
2851
def weak_match?(etag)
2952
wildcard? || self.include?(etag) || self.include?(opposite_tag(etag))
3053
end
3154

3255
private
33-
56+
57+
# Converts a weak tag to its strong counterpart or vice versa.
58+
#
59+
# @parameter etag [String] the ETag to convert.
60+
# @returns [String] the opposite form of the provided ETag.
3461
def opposite_tag(etag)
3562
weak_tag?(etag) ? etag[2..-1] : "W/#{etag}"
3663
end
3764

65+
# Checks if the given ETag is a weak validator.
66+
#
67+
# @parameter tag [String] the ETag to check.
68+
# @returns [Boolean] whether the tag is weak.
3869
def weak_tag?(tag)
3970
tag&.start_with? "W/"
4071
end

lib/protocol/http/header/multiple.rb

+9-1
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,22 @@
66
module Protocol
77
module HTTP
88
module Header
9-
# Header value which is split by newline charaters (e.g. cookies).
9+
# Represents headers that can contain multiple distinct values separated by newline characters.
10+
#
11+
# This isn't a specific header but is used as a base for headers that store multiple values, such as cookies. The values are split and stored as an array internally, and serialized back to a newline-separated string when needed.
1012
class Multiple < Array
13+
# Initializes the multiple header with the given value. As the header key-value pair can only contain one value, the value given here is added to the internal array, and subsequent values can be added using the `<<` operator.
14+
#
15+
# @parameter value [String] the raw header value.
1116
def initialize(value)
1217
super()
1318

1419
self << value
1520
end
1621

22+
# Serializes the stored values into a newline-separated string.
23+
#
24+
# @returns [String] the serialized representation of the header values.
1725
def to_s
1826
join("\n")
1927
end

lib/protocol/http/header/priority.rb

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
module Protocol
99
module HTTP
1010
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 can include directives like `urgency` to specify the importance of a request, and `progressive` to indicate whether a response can be delivered incrementally.
1114
class Priority < Split
1215
# Urgency levels as defined in RFC 9218:
1316
#

0 commit comments

Comments
 (0)