Method: Rack::Utils.add_cookie_to_header

Defined in:
lib/rack/utils.rb


218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/rack/utils.rb', line 218

def add_cookie_to_header(header, key, value)
  case value
  when Hash
    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]
    # There is an RFC mess in the area of date formatting for Cookies. Not
    # only are there contradicting RFCs and examples within RFC text, but
    # there are also numerous conflicting names of fields and partially
    # cross-applicable specifications.
    #
    # These are best described in RFC 2616 3.3.1. This RFC text also
    # specifies that RFC 822 as updated by RFC 1123 is preferred. That is a
    # fixed length format with space-date delimited fields.
    #
    # See also RFC 1123 section 5.2.14.
    #
    # RFC 6265 also specifies "sane-cookie-date" as RFC 1123 date, defined
    # in RFC 2616 3.3.1. RFC 6265 also gives examples that clearly denote
    # the space delimited format. These formats are compliant with RFC 2822.
    #
    # For reference, all involved RFCs are:
    # RFC 822
    # RFC 1123
    # RFC 2109
    # RFC 2616
    # RFC 2822
    # RFC 2965
    # RFC 6265
    expires = "; expires=" +
      rfc2822(value[:expires].clone.gmtime) if value[:expires]
    secure = "; secure"  if value[:secure]
    httponly = "; HttpOnly" if (value.key?(:httponly) ? value[:httponly] : value[:http_only])
    same_site =
      case value[:same_site]
      when false, nil
        nil
      when :lax, 'Lax', :Lax
        '; SameSite=Lax'.freeze
      when true, :strict, 'Strict', :Strict
        '; SameSite=Strict'.freeze
      else
        raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}"
      end
    value = value[:value]
  end
  value = [value] unless Array === value

  cookie = "#{escape(key)}=#{value.map { |v| escape v }.join('&')}#{domain}" \
    "#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}"

  case header
  when nil, ''
    cookie
  when String
    [header, cookie].join("\n")
  when Array
    (header + [cookie]).join("\n")
  else
    raise ArgumentError, "Unrecognized cookie header value. Expected String, Array, or nil, got #{header.inspect}"
  end
end