netscape-cookie-file-parser 0.1.0

Parse Netscape/curl cookie jar files while preserving raw cookie bytes.
Documentation
//! Parser for Netscape/curl cookie jar files.
//!
//! Netscape cookie files are line-oriented. Each cookie line contains seven
//! tab-separated fields: domain, tail-match flag, path, secure flag, expires,
//! name, and value. This crate keeps cookie data as raw bytes so non-UTF-8
//! cookie names, values, paths, and domains can round-trip through the parser.
//!
//! Empty lines and ordinary `#` comments are skipped. curl's `#HttpOnly_`
//! extension is treated as metadata on the cookie rather than as a comment.
//!
//! ```
//! use netscape_cookie_file_parser::{parse_line, CookiePrefix};
//!
//! let cookie = parse_line("#HttpOnly_.example.com\tTRUE\t/\tTRUE\t0\t__Secure-SID\tabc")
//!     .unwrap()
//!     .unwrap();
//!
//! assert_eq!(cookie.domain, b"example.com");
//! assert!(cookie.http_only);
//! assert_eq!(cookie.prefix, CookiePrefix::Secure);
//! ```

use std::io::BufRead;

mod cookie;
mod error;
mod parser;
#[cfg(test)]
mod tests;

pub use cookie::{Cookie, CookiePrefix};
pub use error::{ParseError, ParseErrorKind};
pub use parser::NetscapeCookieParser;

/// Parses all valid cookie lines from a buffered reader.
///
/// The first malformed cookie line or I/O error stops parsing and returns a
/// [`ParseError`] with the 1-based line number.
pub fn parse<R: BufRead>(reader: R) -> Result<Vec<Cookie>, ParseError> {
    NetscapeCookieParser::new(reader).collect()
}

/// Parses all valid cookie lines and skips malformed cookie records.
///
/// I/O errors are still returned because the parser cannot safely continue once
/// the underlying reader fails.
pub fn parse_lossy<R: BufRead>(reader: R) -> Result<Vec<Cookie>, ParseError> {
    let mut cookies = Vec::new();

    for result in NetscapeCookieParser::new(reader) {
        match result {
            Ok(cookie) => cookies.push(cookie),
            Err(error) if matches!(error.kind, ParseErrorKind::Io(_)) => return Err(error),
            Err(_) => {}
        }
    }

    Ok(cookies)
}

/// Parses one Netscape cookie file line.
///
/// Returns `Ok(None)` for blank lines, ordinary comments, and `#HttpOnly_`
/// lines whose payload is still a comment.
pub fn parse_line(line: impl AsRef<[u8]>) -> Result<Option<Cookie>, ParseErrorKind> {
    parser::parse_line_inner(line.as_ref())
}