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 bytes with one leading dot removed.
8    pub domain: Vec<u8>,
9    /// Whether the original tail-match field was `TRUE`, case-insensitively.
10    pub tail_match: bool,
11    /// Raw cookie path field bytes.
12    pub path: Vec<u8>,
13    /// Whether the original secure field was `TRUE`, case-insensitively.
14    pub secure: bool,
15    /// Expiration timestamp parsed as an unsigned integer.
16    pub expires: u64,
17    /// Raw cookie name bytes.
18    pub name: Vec<u8>,
19    /// Raw cookie value bytes.
20    pub value: Vec<u8>,
21    /// Whether this line used curl's `#HttpOnly_` cookie marker.
22    pub http_only: bool,
23    /// Recognized security prefix in the cookie name.
24    pub prefix: CookiePrefix,
25}
26
27/// Case-sensitive cookie name prefixes recognized by the parser.
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub enum CookiePrefix {
30    /// No recognized cookie prefix.
31    None,
32    /// Cookie name starts with `__Secure-`.
33    Secure,
34    /// Cookie name starts with `__Host-`.
35    Host,
36}
37
38// The prefix checks are intentionally case-sensitive: cookie prefixes are part
39// of the cookie name contract, not ordinary case-insensitive cookie metadata.
40pub(crate) fn cookie_prefix(name: &[u8]) -> CookiePrefix {
41    if name.starts_with(b"__Secure-") {
42        CookiePrefix::Secure
43    } else if name.starts_with(b"__Host-") {
44        CookiePrefix::Host
45    } else {
46        CookiePrefix::None
47    }
48}