HTTP Cookies – Data Storage and Transfer Part II

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 II

One cannot send a direct query to fetch data from the data store. The way it works is that a data store query is built on the HTTP client side, based on the site being visited and other parameters of the environment being used.

  1. Environment Parameters
  2. Data store query
  3. Result assembly (“Cookie Data”)
  4. “Cookie” in request headers (or another destination, eg. JS API)
Diagram E: simplified steps a HTTP agent takes to serve cookies.

A HTTP client will consider questions like the following.

  • Is secure connection (HTTPS) being used?
  • What host name is being used? Is it an Internet authority domain name with a distinguishable registrable part?
  • What is the directory path in the URL?
  • Is cookie data going to be sent over to the server or someplace else?
  • Is cross-origin active? If yes, what type?
  • What is the exact time of the request?

Matching Data Elements#

In section 2 where we addressed writing operations to the data store we raised the question of matching values of data elements. It turned out that when writing data to the data store a user agent does not obscure the data and will conduct a strict match, eg. /dir/ will not cancel /dir. Let’s consider the same questions again, but in terms of reading information from the data store.

  • Does .domain.com match domain.com?
  • Does /dir match /dir/?

In section 2 the answer was “no”, but here the answer is “yes”. As we will see below, the query that reads info from the data store will choose not just the exact matches, but also nonequivalent ones.

How To Build a List Of Domains That Would Match?#

Say we are on an Internet authority host foo.bar.domain.com. The base domain should be identified as domain.com. A collection of all host names above the registrable part (including the registrable domain itself) should be assembled. A dot symbol (“.”) should be prepended to each of them making them scoped domains. Finally, the exact current domain name (non-scoped) should be added to finalise the collection.

  • .foo.bar.domain.com scoped 2 levels above registrable
  •  foo.bar.domain.com exact current
  •     .bar.domain.com scoped one level above registrable
  •         .domain.com scoped registrable

Pseudo-code example below.

`domain` in(".foo.bar.domain.com", "foo.bar.domain.com", ".bar.domain.com", ".domain.com")

When other than Internet authority host name is used (eg. an IP address or an alias host name resolving on local network), the query mechanism will look for exact match only.

  • `domain` = `ip address`
  • `domain` = `localhost`

Additionally, if request domain ends with a dot symbol (“.”), it will be part of the domain, eg. foo.bar.domain.com. (mind the trailing dot) will query the below.

`domain` in(".foo.bar.domain.com.", "foo.bar.domain.com.", ".bar.domain.com.", ".domain.com.")

Fetching Relevant Path Entries#

A few things to remember about URI path component. If file name is in the path, it should be trimmed off. Also, the URI path must point to a directory and therefore must end with a forward slash (HTTP server would normally redirect to a location where path component ends with a forward slash in order to represent an actual directory).

First off, while looping through all path data elements in the data store, a trailing forward slash should be appended, if there is not any, and then a virtual version of the path created.

`virtual_path` = if(string_ends_with(`data_store_path`, '/')) then `data_store_path ` else string_concat(`data_store_path`, '/')

Secondly, if the URI path starts with the virtual path above, this entry should be declared matching.

string_starts_with(`uri_path`, `virtual_path`)

The following entries will match.

URI Path Data Store Path
/dir/ /dir
/dir/ /dir/
/dir/foo/ /dir
/dir// /dir
/dir// /dir/
/dir// /dir//
/dir/ /
Table M: Matching entries in fetch operations.

The below entries will NOT match.

URI Path Data Store Path
/dir/ /dir//
/dir/ /d
/ /dir/
/dir/foo/ /dir//
Table N: mismatching entries in fetch operations.

If cookie path in the data store path is set to /dir/, it will not be sent on URI paths below it, eg. it will not be sent on /. But it will be sent for subdirectories, eg. /dir/foo/. Data store path entry /dir will be considered as a valid prefix of /dir/, though /d is not a valid prefix of /dir/.

Targeting Expiry Date-time#

The formula here is very simple.

`expiry` > `current time`

Targeting Secure#

If secure connection is used, only entries containing Secure = true will be filtered out. If connection is insecure, then only Secure = false will match.

Targeting HttpOnly#

If cookie is sent over to the server via the HTTP transfer mechanism (HTTP client to Server), then HttpOnly = *(true|false). If cookie is sent anywhere else but the server, then HttpOnly = false.

Targeting SameSite#

When request URI’s base domain name (for Internet authority it is the registrable domain name, otherwise host name) matches site URI’s base domain name, then SameSite = *(None|Strict|Lax). When request URI’s base domain name does not match site URI’s base domain name, but the request was instantiated from the site with the intention to navigate to the new request page (not to be confused with “Referrer”), then SameSite = (None|Lax). Finally, when request URI’s domain name does not match site URI’s domain name, but the request was made to access resources on the site, then SameSite = None.

    • Same origin
    • “None”, “Strict”, or “Lax”
    • Cross origin Navigate
    • “None” or “Lax”
    • Cross origin Resource
    • “None”
Diagram F: determining what samesite value to use based on origin.

Result Assembly#

Once user agent runs the query onto the data store, it will collect a group of matching entries. These entries will be sorted by 2 rules – path string length in descending order, and entry time entered in ascending order (when path lengths match, older go first). Then, cookie name and value data elements will be concatenated into name-value pairs, where name and value will be joined with an equal sign (“=”) control symbol. The value part will not be wrapped into single or double quotes. Finally, all pairs will be pooled into a single string by separating each pair with a semicolon character.

Last but not least this string will be passed onto the “Cookie” response header field, when cookie data is meant to be sent via HTTP transfer.

“Cookie” is a HTTP request header field, which is designed to send data from HTTP client’s cookie data store over to the server, where it can then pass that data onto a web application.

Cookie: name-value pair [; name-value pair]

It is structured as a group of semicolon separated name-value pairs. As it was shown above these pairs originate from the query result – a collection of matching cookie entries. The resolution of the order of pairs is carried out in the result assembly portion.

Thank You for reading and coming that far! We really appreciate your interest. Please continue to Part III.