HTTP Cookies – Data Storage and Transfer Part III

A look into HTTP cookie (“cookie”) storage and transfer mechanisms can give us insights for how to use cookies.

Date published:

Date last modified:

Part III

Practise, Case Studying, and Caveats#

Above we have stated that cookie name in itself is not distinctive, but rather a member of 3 element group that determines a distinctive cookie entry. We have also shown that with domain scoping there are 2 parts to a domain name – fixed-domain and scoped-domain, which obscures the domain declaration and results in multiple cookie entries that can later be fetched by a single domain declaration. What is more, we have proven that intuitively similar paths (eg. /dir or /dir/) do not cancel each other out, and can also result in multiple cookie entries which can later on be fetched for a single path query.

Let’s assume that our working URL is https://www.domain.com/dir/.

  • Set-Cookie: foo=one
  • Set-Cookie: foo=two; Domain=.domain.com
  • Set-Cookie: foo=three; Domain=www.domain.com
  • Set-Cookie: foo=four; Path=/
  • Set-Cookie: foo=five; Path=/dir/
  • Set-Cookie: foo=six; Domain=.domain.com; Path=/
  • Set-Cookie: foo=seven; Domain=.domain.com; Path=/dir/

The response would be the following.

  • Cookie: foo=five; foo=seven; foo=one; foo=two; foo=three; foo=four; foo=six

The resulting data store.

Name Value Domain Path
foo five www.domain.com /dir/
foo seven .domain.com /dir/
foo one www.domain.com /dir
foo two .domain.com /dir
foo three .www.domain.com /dir
foo four www.domain.com /
foo six .domain.com /
Table O: Data store with multiple cookies using “foo” name.

The data store is sorted by path column in string length descending order, and time entered ascending order.

Let’s see how browsers cope with this issue.

< Set-Cookie: foo=bar
< Set-Cookie: foo=baz
HTTP Client / Feature “Cookie” Value PHP Output
Chrome for MacOS 128.0 foo=baz array(1) { ["foo"]=> string(3) "baz" }
Safari for MacOS 17.6 foo=baz array(1) { ["foo"]=> string(3) "baz" }
Edge for MacOS 128.0 foo=baz array(1) { ["foo"]=> string(3) "baz" }
Firefox for MacOS 129.0 foo=baz array(1) { ["foo"]=> string(3) "baz" }
Table P: Repeating cookie name test in common web browsers.

Case Study for Setting and Matching Domain Name#

Working site address: https://www.domain.com/ (mind the “www” prefix).

“Set-Cookie” Domain Resulting Domain At www.domain.com At domain.com At sub.domain.com
(not defined) www.domain.com + - -
www.domain.com .www.domain.com + - -
domain.com .domain.com + + +
sub.domain.com (rejected)
.domain.com .domain.com + + +
.www.domain.com .www.domain.com + - -
domain.com. (rejected)
..domain.com (rejected)
Table Q: Setting cookie on a domain with a “www” prefix.

Working site address: https://domain.com/ (mind no “www” prefix).

“Set-Cookie” Domain Resulting Domain At www.domain.com At domain.com At sub.domain.com
(not defined) domain.com - + -
www.domain.com (rejected)
domain.com .domain.com + + +
sub.domain.com (rejected)
.domain.com (rejected)
.www.domain.com (rejected)
Table R: Setting cookie on a domain with no “www” prefix.

Working site address: https://domain.com./ (mind no “www” prefix, and a trailing dot in the host component).

“Set-Cookie” Domain Resulting Domain At domain.com At domain.com.
(not defined) domain.com. - +
domain.com. .domain.com. - +
domain.com (rejected)
Table S: Setting cookie on a domain with a trailing dot symbol (“.”).

Other Case Studies and Caveats#

< Set-Cookie: foo=ba=r
HTTP Client / Feature “Cookie” Value PHP Output
Chrome for MacOS 128.0 foo=ba=r array(1) { ["foo"]=> string(4) "ba=r" }
Safari for MacOS 17.6 foo=ba=r array(1) { ["foo"]=> string(4) "ba=r" }
Edge for MacOS 128.0 foo=ba=r array(1) { ["foo"]=> string(4) "ba=r" }
Firefox for MacOS 129.0 foo=ba=r array(1) { ["foo"]=> string(4) "ba=r" }
Table T: Testing equal sign (“=”) in cookie value.
< Set-Cookie: foo=ba r
HTTP Client / Feature “Cookie” Value PHP Output
Chrome for MacOS 128.0 foo=ba r array(1) { ["foo"]=> string(4) "ba r" }
Safari for MacOS 17.6 foo=ba r array(1) { ["foo"]=> string(4) "ba r" }
Edge for MacOS 128.0 foo=ba r array(1) { ["foo"]=> string(4) "ba r" }
Firefox for MacOS 129.0 foo=ba r array(1) { ["foo"]=> string(4) "ba r" }
Table U: Whitespace character inside unquoted cookie value.
< Set-Cookie: foo="ba r"
HTTP Client / Feature “Cookie” Value PHP Output
Chrome for MacOS 128.0 foo="ba r" array(1) { ["foo"]=> string(6) ""ba r"" }
Safari for MacOS 17.6 foo="ba r" array(1) { ["foo"]=> string(6) ""ba r"" }
Edge for MacOS 128.0 foo="ba r" array(1) { ["foo"]=> string(6) ""ba r"" }
Firefox for MacOS 129.0 foo="ba r" array(1) { ["foo"]=> string(6) ""ba r"" }
Table V: Whitespace character inside quoted cookie value.
< Set-Cookie: f oo=bar
HTTP Client / Feature “Cookie” Value PHP Output
Chrome for MacOS 128.0 f oo=bar array(1) { ["f_oo"]=> string(3) "bar" }
Safari for MacOS 17.6 f oo=bar array(1) { ["f_oo"]=> string(3) "bar" }
Edge for MacOS 128.0 f oo=bar array(1) { ["f_oo"]=> string(3) "bar" }
Firefox for MacOS 129.0 f oo=bar array(1) { ["f_oo"]=> string(3) "bar" }
Table W: Whitespace character inside cookie name.
< Set-Cookie: foo="bar"
HTTP Client / Feature “Cookie” Value PHP Output
Chrome for MacOS 128.0 foo="bar" array(1) { ["foo"]=> string(5) ""bar"" }
Safari for MacOS 17.6 foo="bar" array(1) { ["foo"]=> string(5) ""bar"" }
Edge for MacOS 128.0 foo="bar" array(1) { ["foo"]=> string(5) ""bar"" }
Firefox for MacOS 129.0 foo="bar" array(1) { ["foo"]=> string(5) ""bar"" }
Table X: Standard quoted cookie value.
< Set-Cookie: foo=ba;r
HTTP Client / Feature “Cookie” Value PHP Output
Chrome for MacOS 128.0 foo=ba array(1) { ["foo"]=> string(2) "ba" }
Safari for MacOS 17.6 foo=ba array(1) { ["foo"]=> string(2) "ba" }
Edge for MacOS 128.0 foo=ba array(1) { ["foo"]=> string(2) "ba" }
Firefox for MacOS 129.0 foo=ba array(1) { ["foo"]=> string(2) "ba" }
Table Y: Semicolon character inside cookie value.
< Set-Cookie: foo="ba;r"
HTTP Client / Feature “Cookie” Value PHP Output
Chrome for MacOS 128.0 foo="ba array(1) { ["foo"]=> string(3) ""ba" }
Safari for MacOS 17.6 foo="ba;r" array(2) { ["foo"]=> string(3) ""ba" ["r""]=> string(0) "" }
Edge for MacOS 128.0 foo="ba array(1) { ["foo"]=> string(3) ""ba" }
Firefox for MacOS 129.0 foo="ba array(1) { ["foo"]=> string(3) ""ba" }
Table Z: Semicolon character inside quoted cookie value.
< Set-Cookie: foo=ba;r; Path=/my/path
HTTP Client / Feature “Cookie” Value PHP Output
Chrome for MacOS 128.0 foo=ba array(1) { ["foo"]=> string(2) "ba" }
Safari for MacOS 17.6 foo=ba array(1) { ["foo"]=> string(2) "ba" }
Edge for MacOS 128.0 foo=ba array(1) { ["foo"]=> string(2) "ba" }
Firefox for MacOS 129.0 foo=ba array(1) { ["foo"]=> string(2) "ba" }
Table AA: Semicolon value inside unquoted cookie value with other directives present.
< Set-Cookie: foo=bar; Path=/my/path; Dummy
HTTP Client / Feature “Cookie” Value PHP Output
Chrome for MacOS 128.0 foo=bar array(1) { ["foo"]=> string(3) "bar" }
Safari for MacOS 17.6 foo=bar array(1) { ["foo"]=> string(3) "bar" }
Edge for MacOS 128.0 foo=bar array(1) { ["foo"]=> string(3) "bar" }
Firefox for MacOS 129.0 foo=bar array(1) { ["foo"]=> string(3) "bar" }
Table AB: Testing invalid attribute at the end of the header field.
< Set-Cookie: foo=bar; Dummy; Path=/my/path
HTTP Client / Feature “Cookie” Value PHP Output
Chrome for MacOS 128.0 foo=bar array(1) { ["foo"]=> string(3) "bar" }
Safari for MacOS 17.6 foo=bar array(1) { ["foo"]=> string(3) "bar" }
Edge for MacOS 128.0 foo=bar array(1) { ["foo"]=> string(3) "bar" }
Firefox for MacOS 129.0 foo=bar array(1) { ["foo"]=> string(3) "bar" }
Table AC: Testing invalid attribute preceeding a valid attribute.