lib/rack/utils.rb in rack-3.1.1 vs lib/rack/utils.rb in rack-3.1.2

- old
+ new

@@ -242,42 +242,51 @@ # def parse_cookies(env) parse_cookies_header env[HTTP_COOKIE] end - # A valid cookie key according to RFC6265 and RFC2616. + # A valid cookie key according to RFC2616. # A <cookie-name> can be any US-ASCII characters, except control characters, spaces, or tabs. It also must not contain a separator character like the following: ( ) < > @ , ; : \ " / [ ] ? = { }. VALID_COOKIE_KEY = /\A[!#$%&'*+\-\.\^_`|~0-9a-zA-Z]+\z/.freeze private_constant :VALID_COOKIE_KEY + private def escape_cookie_key(key) + if key =~ VALID_COOKIE_KEY + key + else + warn "Cookie key #{key.inspect} is not valid according to RFC2616; it will be escaped. This behaviour is deprecated and will be removed in a future version of Rack.", uplevel: 2 + escape(key) + end + end + # :call-seq: # set_cookie_header(key, value) -> encoded string # # Generate an encoded string using the provided +key+ and +value+ suitable # for the +set-cookie+ header according to RFC6265. The +value+ may be an - # instance of either +String+ or +Hash+. If the cookie key is invalid (as - # defined by RFC6265), an +ArgumentError+ will be raised. + # instance of either +String+ or +Hash+. # # If the cookie +value+ is an instance of +Hash+, it considers the following # cookie attribute keys: +domain+, +max_age+, +expires+ (must be instance # of +Time+), +secure+, +http_only+, +same_site+ and +value+. For more # details about the interpretation of these fields, consult # [RFC6265 Section 5.2](https://datatracker.ietf.org/doc/html/rfc6265#section-5.2). # + # An extra cookie attribute +escape_key+ can be provided to control whether + # or not the cookie key is URL encoded. If explicitly set to +false+, the + # cookie key name will not be url encoded (escaped). The default is +true+. + # # set_cookie_header("myname", "myvalue") # # => "myname=myvalue" # # set_cookie_header("myname", {value: "myvalue", max_age: 10}) # # => "myname=myvalue; max-age=10" # def set_cookie_header(key, value) - unless key =~ VALID_COOKIE_KEY - raise ArgumentError, "invalid cookie key: #{key.inspect}" - end - case value when Hash + key = escape_cookie_key(key) unless value[:escape_key] == false domain = "; domain=#{value[:domain]}" if value[:domain] path = "; path=#{value[:path]}" if value[:path] max_age = "; max-age=#{value[:max_age]}" if value[:max_age] expires = "; expires=#{value[:expires].httpdate}" if value[:expires] secure = "; secure" if value[:secure] @@ -295,9 +304,11 @@ else raise ArgumentError, "Invalid :same_site value: #{value[:same_site].inspect}" end partitioned = "; partitioned" if value[:partitioned] value = value[:value] + else + key = escape_cookie_key(key) end value = [value] unless Array === value return "#{key}=#{value.map { |v| escape v }.join('&')}#{domain}" \