Skip to content

Commit fc7235d

Browse files
committed
Move URL and Reference to Protocol::URL gem.
1 parent e796678 commit fc7235d

File tree

22 files changed

+209
-1092
lines changed

22 files changed

+209
-1092
lines changed

guides/hypertext-references/readme.md

Lines changed: 0 additions & 140 deletions
This file was deleted.

guides/links.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ headers:
66
order: 3
77
middleware:
88
order: 4
9-
hypertext-references:
10-
order: 5
11-
url-parsing:
12-
order: 6
139
streaming:
1410
order: 7
1511
design-overview:

guides/url-parsing/readme.md

Lines changed: 0 additions & 130 deletions
This file was deleted.

lib/protocol/http/cookie.rb

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,37 @@
44
# Copyright, 2019-2025, by Samuel Williams.
55
# Copyright, 2022, by Herrick Fang.
66

7-
require_relative "url"
7+
require_relative "quoted_string"
88

99
module Protocol
1010
module HTTP
1111
# Represents an individual cookie key-value pair.
1212
class Cookie
13+
# Valid cookie name characters according to RFC 6265.
14+
# cookie-name = token (RFC 2616 defines token)
15+
VALID_COOKIE_KEY = /\A#{TOKEN}\z/.freeze
16+
17+
# Valid cookie value characters according to RFC 6265.
18+
# cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
19+
# cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
20+
# Excludes control chars, whitespace, DQUOTE, comma, semicolon, and backslash
21+
VALID_COOKIE_VALUE = /\A[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*\z/.freeze
22+
1323
# Initialize the cookie with the given name, value, and directives.
1424
#
15-
# @parameter name [String] The name of the cookiel, e.g. "session_id".
25+
# @parameter name [String] The name of the cookie, e.g. "session_id".
1626
# @parameter value [String] The value of the cookie, e.g. "1234".
1727
# @parameter directives [Hash] The directives of the cookie, e.g. `{"path" => "/"}`.
18-
def initialize(name, value, directives)
28+
# @raises [ArgumentError] If the name or value contains invalid characters.
29+
def initialize(name, value, directives = nil)
30+
unless VALID_COOKIE_KEY.match?(name)
31+
raise ArgumentError, "Invalid cookie name: #{name.inspect}"
32+
end
33+
34+
if value && !VALID_COOKIE_VALUE.match?(value)
35+
raise ArgumentError, "Invalid cookie value: #{value.inspect}"
36+
end
37+
1938
@name = name
2039
@value = value
2140
@directives = directives
@@ -30,41 +49,37 @@ def initialize(name, value, directives)
3049
# @attribute [Hash] The directives of the cookie.
3150
attr :directives
3251

33-
# Encode the name of the cookie.
34-
def encoded_name
35-
URL.escape(@name)
36-
end
37-
38-
# Encode the value of the cookie.
39-
def encoded_value
40-
URL.escape(@value)
52+
# Encode a string for use in a cookie, escaping characters that are not allowed.
53+
#
54+
# @parameter string [String] The string to encode.
55+
# @returns [String] The encoded string.
56+
def self.encode(string)
57+
string.b.gsub(/([^!#$%&'*+\-\.\/0-9A-Z\^_`a-z|~]+)/) do |match|
58+
"%" + match.unpack("H2" * match.bytesize).join("%").upcase
59+
end
4160
end
4261

4362
# Convert the cookie to a string.
4463
#
4564
# @returns [String] The string representation of the cookie.
4665
def to_s
47-
buffer = String.new.b
66+
buffer = String.new
4867

49-
buffer << encoded_name << "=" << encoded_value
68+
buffer << @name << "=" << @value
5069

5170
if @directives
52-
@directives.collect do |key, value|
71+
@directives.each do |key, value|
5372
buffer << ";"
73+
buffer << key
5474

55-
case value
56-
when String
57-
buffer << key << "=" << value
58-
when TrueClass
59-
buffer << key
75+
if value != true
76+
buffer << "=" << value.to_s
6077
end
6178
end
6279
end
6380

6481
return buffer
65-
end
66-
67-
# Parse a string into a cookie.
82+
end # Parse a string into a cookie.
6883
#
6984
# @parameter string [String] The string to parse.
7085
# @returns [Cookie] The parsed cookie.
@@ -74,11 +89,7 @@ def self.parse(string)
7489
key, value = head.split("=", 2)
7590
directives = self.parse_directives(directives)
7691

77-
self.new(
78-
URL.unescape(key),
79-
URL.unescape(value),
80-
directives,
81-
)
92+
self.new(key, value, directives)
8293
end
8394

8495
# Parse a list of strings into a hash of directives.

0 commit comments

Comments
 (0)