You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
TASK-064: cosmetic cleanup — remove dead code, drop explicit append counts, update specs
1. Delete dead cookie_token_split struct and split_cookie_token helper
(code-simplifier-iter1-1): these 27 lines were never called; the
inline logic in parse_cookie_header was written independently.
2. Replace explicit byte-count literals in append calls with single-
argument form (code-simplifier-iter1-3): out.append("; Secure", 8)
→ out.append("; Secure") etc. across append_time_attributes,
append_target_attributes, and append_flag_attributes. The compiler
derives the length at compile time; no runtime cost change.
3. Mark all five TASK-064 action items complete in TASK-064.md
(housekeeper-iter1-1).
4. Add §3.5.1 Structured Cookie Type (API-CKY) to product_specs.md
with 10 EARS requirements covering the cookie value type, injection
guards, RFC 6265 rendering, parse semantics, deprecated shim policy,
and acceptance criteria (housekeeper-iter1-2).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: specs/product_specs.md
+41Lines changed: 41 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -184,6 +184,47 @@ The response hierarchy has eight subclasses (`string_response`, `file_response`,
184
184
185
185
---
186
186
187
+
### 3.5.1 Structured Cookie Type (API-CKY)
188
+
189
+
**Problem / outcome**
190
+
The v1 `with_cookie(string, string)` / `get_cookie(string)` API stored cookies as opaque string blobs, making RFC 6265 attribute fields (Secure, HttpOnly, SameSite, Path, Domain, Expires, Max-Age) inaccessible to callers and allowing header-injection via unguarded semicolons in values. After TASK-064 the library exposes `httpserver::cookie`, a structured value type, alongside `http_response::with_cookie(cookie)` for responses and `http_request::get_cookies_parsed()` for requests. The string-blob path is retained as a `[[deprecated]]` shim for one transitional v2.0 release.
191
+
192
+
**In scope**
193
+
-`httpserver::cookie` value type with fluent `with_name`, `with_value`, `with_domain`, `with_path`, `with_expires`, `with_max_age`, `with_secure`, `with_http_only`, `with_same_site` setters.
194
+
-`enum class same_site_mode { unset, strict, lax, none }`.
195
+
-`cookie::to_set_cookie_header()` renders a fully RFC 6265 §4.1 conformant `Set-Cookie` value.
196
+
-`cookie::parse_cookie_header(string_view)` parses a `Cookie:` request header into a `std::vector<cookie>`, byte-transparent and lenient.
-`http_request::get_cookies_parsed()` returns `const std::vector<cookie>&`, parsed once and cached.
199
+
- Injection guard: CR, LF, NUL, and `;` are rejected in name, value, domain, and path at setter time (CWE-113).
200
+
- SameSite=None auto-coerces `Secure` at render time (browser requirement per draft-west-cookie-incrementalism).
201
+
- Transitional policy: legacy `get_cookie(string)`, `get_cookies()`, and `with_cookie(string, string)` are `[[deprecated]]` and compile with a diagnostic in v2.0.
202
+
203
+
**Out of scope**
204
+
- Removing the deprecated string-blob path before v2.1.
-`PRD-CKY-REQ-001` When a user constructs a `httpserver::cookie` then the system shall provide fluent `with_*` setters that return `cookie&` on lvalue and `cookie&&` on rvalue, mirroring the `http_response` fluent style.
209
+
-`PRD-CKY-REQ-002` When a user calls `with_name`, `with_value`, `with_domain`, or `with_path` with a value containing CR, LF, NUL, or `;` then the system shall throw `std::invalid_argument`.
210
+
-`PRD-CKY-REQ-003` When a user calls `with_name` with a value containing `=` or ASCII whitespace then the system shall throw `std::invalid_argument`.
211
+
-`PRD-CKY-REQ-004` When a user calls `cookie::to_set_cookie_header()` then the system shall produce a string conforming to RFC 6265 §4.1 with attributes in the canonical order: Expires, Max-Age, Domain, Path, Secure, HttpOnly, SameSite.
212
+
-`PRD-CKY-REQ-005` When a user calls `cookie::to_set_cookie_header()` with `same_site_mode::none` set and `with_secure(false)` then the system shall include `Secure` in the output (browser requirement).
213
+
-`PRD-CKY-REQ-006` When a user calls `cookie::parse_cookie_header(s)` then the system shall return a `std::vector<cookie>` parsed from the `Cookie:` wire format, stripping outer DQUOTE pairs from values and tolerating arbitrary ASCII whitespace around tokens.
214
+
-`PRD-CKY-REQ-007` When a user calls `http_response::with_cookie(cookie)` then the system shall append the structured cookie to the response's cookie list; `get_cookies_parsed()` shall reflect it without copying the cookie object.
215
+
-`PRD-CKY-REQ-008` When a user calls `http_request::get_cookies_parsed()` then the system shall return a `const std::vector<cookie>&` backed by a parse-once cached representation; subsequent calls shall not allocate.
216
+
-`PRD-CKY-REQ-009` When v2.0 ships then `http_response::with_cookie(string, string)`, `http_response::get_cookie(string_view)`, and `http_response::get_cookies()` shall be `[[deprecated]]` and shall not be removed until v2.1.
217
+
-`PRD-CKY-REQ-010` When a user calls the legacy `with_cookie(string, string)` shim with a name or value that violates RFC 6265 cookie-name or cookie-value rules then the system shall throw `std::invalid_argument` before mutating any internal state.
218
+
219
+
**Acceptance criteria**
220
+
-`http_response::string("body").with_cookie(cookie{}.with_name("sid").with_secure(true).with_same_site(same_site_mode::strict))` compiles and produces a single well-formed `Set-Cookie` value.
221
+
-`http_request::get_cookies_parsed()` returns `const std::vector<cookie>&`; pointer identity is stable across unrelated mutations.
Copy file name to clipboardExpand all lines: specs/tasks/M7-v2-cleanup/TASK-064.md
+5-5Lines changed: 5 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,11 +8,11 @@
8
8
Replace the string-blob cookie surface on `http_response` with a structured `httpserver::cookie` value type carrying `name`, `value`, `domain`, `path`, `expires`, `max_age`, `secure`, `http_only`, `same_site`. The follow-up was explicitly deferred at `src/httpserver/http_response.hpp:304-313`.
9
9
10
10
**Action Items:**
11
-
-[] Design the `httpserver::cookie` value type in a new public header `src/httpserver/cookie.hpp`. Default-construct empty; provide fluent `with_*` setters mirroring `http_response`'s style. Include enum `same_site_mode { unset, strict, lax, none }`.
12
-
-[] Add `http_response::with_cookie(cookie)` and `http_response::with_cookie(std::string name, std::string value)` overloads. Internally render to the `Set-Cookie` header per RFC 6265 §4.1.
13
-
-[] Provide `http_request::get_cookies()` returning a structured view (parsed once, cached on the request impl per TASK-016 arena pattern).
14
-
-[] Document migration: legacy string-blob path remains as a `[[deprecated]]` thin shim for one transitional release.
15
-
-[] Add a unit test pinning round-trip parsing/rendering against RFC 6265 examples.
11
+
-[x] Design the `httpserver::cookie` value type in a new public header `src/httpserver/cookie.hpp`. Default-construct empty; provide fluent `with_*` setters mirroring `http_response`'s style. Include enum `same_site_mode { unset, strict, lax, none }`.
12
+
-[x] Add `http_response::with_cookie(cookie)` and `http_response::with_cookie(std::string name, std::string value)` overloads. Internally render to the `Set-Cookie` header per RFC 6265 §4.1.
13
+
-[x] Provide `http_request::get_cookies()` returning a structured view (parsed once, cached on the request impl per TASK-016 arena pattern).
14
+
-[x] Document migration: legacy string-blob path remains as a `[[deprecated]]` thin shim for one transitional release.
15
+
-[x] Add a unit test pinning round-trip parsing/rendering against RFC 6265 examples.
16
16
17
17
**Dependencies:**
18
18
- Blocked by: TASK-016 (arena), TASK-009 (http_response value type)
0 commit comments