{
  "flavors": {
    "ok": "The control, fully correct and minimal: badhttp_ok=1; Path=/cookies; Max-Age=3600. Store it, return it to /cookies/* for an hour.",
    "echo": "The readback. Sets nothing; returns the Cookie header you sent (raw, plus base64 of its UTF-8 re-encoding) and the parsed pairs in order, duplicates preserved. Three notes: an upstream hop joins multiple Cookie header lines with \"; \" before the Worker sees them; the runtime replaces bytes that are not valid UTF-8 with U+FFFD — so EF BF BD in the base64 means your client sent raw non-UTF-8 bytes; and a Cookie header over 8,199 bytes is silently dropped upstream of the Worker (observed live: 8,199 arrives intact, 8,200 never arrives, the request otherwise succeeds).",
    "folded": "Two cookies folded into ONE Set-Cookie header, comma-separated: \"badhttp_folded_a=1, badhttp_folded_b=2\". bis §3 forbids folding Set-Cookie (RFC 6265 had it at SHOULD NOT); the parse algorithm yields ONE cookie whose value is \"1, badhttp_folded_b=2\". A client that splits on commas invents a second cookie.",
    "many": "?count= separate Set-Cookie headers (1-20, default 10), badhttp_many_01 onward, zero-padded. Tests per-response cookie handling and ordering.",
    "duplicate": "The same name twice with different paths: badhttp_dup=deep; Path=/cookies/echo and badhttp_dup=shallow; Path=/cookies. Two distinct cookies. A jar keyed on name alone silently loses one.",
    "on-redirect": "A 302 to /cookies/echo that carries Set-Cookie: badhttp_redirect=1 ON the redirect itself. A historic bug class: clients that drop Set-Cookie on 3xx responses. One shot: curl -sL -c jar -b jar.",
    "delete": "The cleanup: one expiring Set-Cookie for every cookie this family can plant, each with the exact Path (and Domain, and prefix-required attributes) it was set with — RFC 6265 §5.3 removes a cookie only on a name+domain+path match, so a deletion that is casual about attributes deletes nothing. Uses both idioms: Expires in 1970 and Max-Age=0.",
    "conflicting-expiry": "badhttp_conflict=alive with BOTH Expires in 1970 AND Max-Age=3600. §5.3 step 3 consults Max-Age before Expires (prose in §4.1.2.2: Max-Age has precedence). A client honoring Expires deletes a cookie that should live an hour.",
    "bad-expires": "Expires in ISO 8601 (2027-08-23T12:00:00Z), which the cookie-date algorithm (§5.1.1) cannot parse — \"-\" is a delimiter and no month token survives. The attribute is ignored and the cookie becomes a session cookie. A homegrown jar that feeds Expires to a general date parser mints a 2027 expiry instead; /cookies/delete clears it either way.",
    "far-future": "Expires in the year 9999 (Fri, 01 Jan 9999 00:00:00 GMT). bis §5.5 says user agents SHOULD cap cookie lifetime (400 days recommended); CLI jars mostly predate the cap. /cookies/delete removes it.",
    "wrong-domain": "Domain=example.com on a cookie set by this host. The Domain does not domain-match the request host, so the whole cookie MUST be ignored (§5.3 step 6). Jar-observable: it must simply never appear. Max-Age is 300 s so a jar that wrongly keeps it is only polluted briefly.",
    "public-suffix": "Domain=dev — a public suffix. A cookie scoped to a whole TLD is a supercookie; a jar configured with a public-suffix list ignores it (§5.3 step 5 — conditional on that configuration; plain RFC 6265 without a PSL would accept it, since badhttp.dev domain-matches dev). On this host the single-label Domain also trips the older no-embedded-dot heuristic, so PSL-free jars reject it too; only a jar with neither guard stores it — and would then send it back here, so /cookies/echo can catch it. Max-Age 300 s bounds the damage.",
    "domain": "The accepted-Domain pair: badhttp_domain_dot with Domain=.<this host> (leading dot) and badhttp_domain with Domain=<this host>. §5.2.3 strips the leading %x2E, so both become identical domain cookies (host-only flag off) — a classic divergence between jar generations and jar file formats. Meaningful on badhttp.dev itself.",
    "path-prefix": "Path=/cookie — one letter short of /cookies. Path-matching (§5.1.4) requires the prefix to end at a \"/\" boundary, so this cookie must NEVER be sent to /cookies/*. A naive prefix-matcher sends it anyway.",
    "name-prefixes": "Four prefixed cookies (bis §4.1.3, §5.4 — the prefixes do not exist in RFC 6265): __Host-badhttp_good (valid: Path=/, Secure, no Domain), __Host-badhttp_bad (invalid: Path is not /), __Secure-badhttp_good (valid: Secure), __Secure-badhttp_bad (invalid: no Secure). A bis client stores exactly the two _good ones; an RFC-6265-only jar conformantly stores all four. Meaningful over HTTPS only.",
    "quoted": "badhttp_quoted=\"hello world\" (a DQUOTE-wrapped value with a space) and badhttp_semi=\"semi;colon\" (a semicolon inside the quotes — but the parser splits on \";\" before it ever sees quotes, so the stored value is \"semi with an unclosed quote). What does your client send back — quotes kept, stripped, re-added?",
    "utf8": "A value of raw UTF-8: badhttp_utf8=☃ (the bytes e2 98 83 on the wire; the runtime UTF-8-encodes header strings, which is itself a platform quirk worth knowing). Outside the cookie-octet grammar; real servers do it anyway. Jars differ: store raw, percent-encode, or drop. The echo base64 field shows exactly what came back.",
    "nameless": "Two nameless shapes at different paths so both can coexist: a Set-Cookie with no \"=\" at all (badhttp-just-a-value, default path /cookies) and one that starts with \"=\" (=badhttp_empty_name; Path=/cookies/echo). RFC 6265 §5.2 ignores both — step 2 (no \"=\") and step 5 (empty name); the bis parse stores each as a value with an empty name. Generations of jars really do differ here.",
    "huge": "One cookie whose name plus value sum to exactly ?bytes= bytes (64-8192, default 4096), padded with x. bis §5.6 step 5 says a client MUST ignore the cookie when name+value exceed 4096 bytes (RFC 6265 §6.1 has only a SHOULD-support floor, measured including attributes). So 4096 survives a conformant jar and 4097 must not. The echo round trip tells you your client's cap."
  },
  "usage": "/cookies/{flavor}; /cookies/echo is the readback",
  "politeness": "Every cookie name starts with badhttp_ (or __Host-badhttp_ / __Secure-badhttp_) — except the two nameless-flavor cookies, which have no name at all and carry the badhttp marker in their value. No Max-Age or Expires runs past 3600 s except far-future, whose date is the test (the two reject-me flavors are down at 300 s); bad-expires and the nameless pair carry no usable expiry and live as session cookies. Cookies are scoped Path=/cookies wherever the test allows; /cookies/delete expires every cookie the family can plant, exact paths and all; no cookie value is ever derived from your request.",
  "observability": "Most flavors are visible in the /cookies/echo round trip or in your jar file. wrong-domain and public-suffix are negative tests: the bug is their cookie existing at all. path-prefix is stored correctly by a conformant jar; the bug is it appearing in a Cookie header here. Every response body repeats the Set-Cookie values it carried (set) and what your request carried (received).",
  "spec": "RFC 6265 and draft-ietf-httpbis-rfc6265bis-22 (\"bis\"); each flavor names the rule it bends.",
  "limits": {
    "max_count": 20,
    "max_bytes": 8192,
    "echoed_cookie_header_cap": 16384
  }
}
