I do not know from where the idea of "packed" came about. Those are just cookies with the =
sign in the value, or at least should be according to the specs. Let us go through the RFCs and see that:
Set-Cookie: acct=t=&s=; domain=.stackapps.com; expires=...
is exactly the same as
Set-Cookie: acct="t=&s="; domain=.stackapps.com; expires=...
Therefore, it is a single cookie and shall be treated as such.
The answer is rather long, sorry for that. I tried to aim it at people who find the grammar rules found in the RFCs difficult to understand. If you believe that some piece of the grammar is still difficult to understand please point it to me in a comment.
Through the RFCs
The current RFC for the Set-Cookie
header is RFC6265, in section 4.1 it has the formal syntax for Set-Cookie
:
set-cookie-header = "Set-Cookie:" SP set-cookie-string
set-cookie-string = cookie-pair *( ";" SP cookie-av )
cookie-pair = cookie-name "=" cookie-value
cookie-name = token
cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
; US-ASCII characters excluding CTLs,
; whitespace DQUOTE, comma, semicolon,
; and backslash
token = <token, defined in [RFC2616], Section 2.2>
cookie-av = expires-av / max-age-av / domain-av /
path-av / secure-av / httponly-av /
extension-av
expires-av = "Expires=" sane-cookie-date
sane-cookie-date = <rfc1123-date, defined in [RFC2616], Section 3.3.1>
max-age-av = "Max-Age=" non-zero-digit *DIGIT
; In practice, both expires-av and max-age-av
; are limited to dates representable by the
; user agent.
non-zero-digit = %x31-39
; digits 1 through 9
domain-av = "Domain=" domain-value
domain-value = <subdomain>
; defined in [RFC1034], Section 3.5, as
; enhanced by [RFC1123], Section 2.1
path-av = "Path=" path-value
path-value = <any CHAR except CTLs or ";">
secure-av = "Secure"
httponly-av = "HttpOnly"
extension-av = <any CHAR except CTLs or ";">
That is a little terse but we do not need to got through it all. For a start we have the Set-Cookie:
header and a space (SP
), then the set-cookie-string
which is defined further.
set-cookie-header = "Set-Cookie:" SP set-cookie-string
set-cookie-string
is composed of a cookie-pair
(defined further), which is the grammar part that interests us, and optionally a set of any number of cookie-av
prefixed with ;
and a space. The *()
construct allows for any number of occurrences (including zero) of the grammar part.
set-cookie-string = cookie-pair *( ";" SP cookie-av )
cookie-av
defines the metadata that can be used in the cookie but it is not needed for our proof, therefore we will abandon its discussion.
The cookie-pair
on the other hand is a very simple construct: one cookie-name
one mandatory =
sign and one cookie-value
.
cookie-pair = cookie-name "=" cookie-value
The cookie-name
is defined as a token
which leads us to another RFC, RFC2616. In the section 2.2 of that RFC we find the basic rules that define the token
.
cookie-name = token
token = <token, defined in [RFC2616], Section 2.2>
token
definition:
CTL = <any US-ASCII control character
(octets 0 - 31) and DEL (127)>
...
token = 1*<any CHAR except CTLs or separators>
separators = "(" | ")" | "<" | ">" | "@"
| "," | ";" | ":" | "\" | <">
| "/" | "[" | "]" | "?" | "="
| "{" | "}" | SP | HT
The 1*<>
syntax means any number of occurrences but at least one occurrence. To find the CTL
s use man ascii
and check the Dec
column, SP
is space (as we already saw) and HT
is the horizontal tab (9 in the ascii table).
The interesting part for us is the fact that a token
cannot contain an =
character.
Back to RFC6265:
cookie-pair = cookie-name "=" cookie-value
cookie-name
stops at the first =
character, that first =
character is always the =
explicit in the grammar. Now, let's finally define the cookie-value
cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
; US-ASCII characters excluding CTLs,
; whitespace DQUOTE, comma, semicolon,
; and backslash
We already saw that the *
there means any occurrences including zero (note that empty cookies are allowed by the RFC!). The interesting part the entire cookie-value
can be enclosed by double quotes (DQUOTE
is the double quote character as you might have guessed).
But the most interesting part is that the =
sign (x3D
in the ascii) table is allowed as a cookie-octet
/ %x3C-5B / <- right there!
Yet the space (x20
) and semicolon (x3B
) are disallowed.
Conclusion
Therefore this Set-Cookie
header shall be interpreted as
Set-Cookie: acct=t=&s=; domain=.stackapps.com; expires=...
cookie-set-header = "Set-Cookie:" SP set-cookie-string
set-cookie-string = cookie-pair *(";" cookie-av)
cookie-pair = cookie-name "=" cookie-value
cookie-name = "acct"
cookie-value = "t=&s="
And the header sending it back to the server shall be
Cookie: acct=t=&s=
Sending it as follows violates the RFC:
Cookie: acct=t&; s=