Skip to main content

netscape_cookie_file_parser/
cookie.rs

1/// One parsed cookie record from a Netscape cookie file.
2///
3/// String-like fields are byte buffers rather than `String`s because cookie jar
4/// files seen in the wild may contain non-UTF-8 octets.
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct Cookie {
7    /// Cookie domain with one leading dot removed, matching curl's behavior.
8    pub domain: Vec<u8>,
9    /// Whether the original tail-match field was `TRUE`, case-insensitively.
10    pub tail_match: bool,
11    /// Sanitized cookie path.
12    ///
13    /// Relative and malformed paths are normalized to `/`; non-root paths have
14    /// one trailing slash removed.
15    pub path: Vec<u8>,
16    /// Whether the original secure field was `TRUE`, case-insensitively.
17    pub secure: bool,
18    /// Expiration timestamp parsed as an unsigned integer.
19    pub expires: u64,
20    /// Raw cookie name bytes.
21    pub name: Vec<u8>,
22    /// Raw cookie value bytes.
23    pub value: Vec<u8>,
24    /// Whether this line used curl's `#HttpOnly_` cookie marker.
25    pub http_only: bool,
26    /// Recognized security prefix in the cookie name.
27    pub prefix: CookiePrefix,
28}
29
30/// Case-sensitive cookie name prefixes recognized by the parser.
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum CookiePrefix {
33    /// No recognized cookie prefix.
34    None,
35    /// Cookie name starts with `__Secure-`.
36    Secure,
37    /// Cookie name starts with `__Host-`.
38    Host,
39}
40
41// The prefix checks are intentionally case-sensitive: cookie prefixes are part
42// of the cookie name contract, not ordinary case-insensitive cookie metadata.
43pub(crate) fn cookie_prefix(name: &[u8]) -> CookiePrefix {
44    if name.starts_with(b"__Secure-") {
45        CookiePrefix::Secure
46    } else if name.starts_with(b"__Host-") {
47        CookiePrefix::Host
48    } else {
49        CookiePrefix::None
50    }
51}