1use crate::{BpiError, BpiResult};
2
3pub type CookiePair = (String, String);
4
5pub fn parse_cookie_header(cookie_header: &str) -> BpiResult<Vec<CookiePair>> {
6 let mut pairs = Vec::new();
7
8 for segment in cookie_header
9 .split(';')
10 .map(str::trim)
11 .filter(|segment| !segment.is_empty())
12 {
13 let Some((key, value)) = segment.split_once('=') else {
14 return Err(BpiError::invalid_parameter(
15 "cookie",
16 "cookie segment must contain '='",
17 ));
18 };
19
20 let key = key.trim();
21 if key.is_empty() {
22 return Err(BpiError::invalid_parameter(
23 "cookie",
24 "cookie key cannot be empty",
25 ));
26 }
27
28 pairs.push((key.to_string(), value.trim().to_string()));
29 }
30
31 if pairs.is_empty() {
32 return Err(BpiError::invalid_parameter(
33 "cookie",
34 "cookie string cannot be empty",
35 ));
36 }
37
38 Ok(pairs)
39}
40
41pub fn format_cookie_pairs(pairs: &[CookiePair]) -> String {
42 pairs
43 .iter()
44 .map(|(key, value)| format!("{key}={value}"))
45 .collect::<Vec<_>>()
46 .join("; ")
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52 use crate::BpiError;
53
54 #[test]
55 fn parse_cookie_header_returns_named_pairs() -> Result<(), BpiError> {
56 let pairs = parse_cookie_header("SESSDATA=session; bili_jct=csrf")?;
57
58 assert_eq!(
59 pairs,
60 vec![
61 ("SESSDATA".to_string(), "session".to_string()),
62 ("bili_jct".to_string(), "csrf".to_string())
63 ]
64 );
65 Ok(())
66 }
67
68 #[test]
69 fn parse_cookie_header_rejects_invalid_segments() {
70 let err = parse_cookie_header("SESSDATA").unwrap_err();
71
72 assert!(matches!(
73 err,
74 BpiError::InvalidParameter {
75 field: "cookie",
76 ..
77 }
78 ));
79 }
80
81 #[test]
82 fn parse_cookie_header_rejects_empty_input() {
83 let err = parse_cookie_header(" ; ").unwrap_err();
84
85 assert!(matches!(
86 err,
87 BpiError::InvalidParameter {
88 field: "cookie",
89 ..
90 }
91 ));
92 }
93
94 #[test]
95 fn format_cookie_pairs_returns_deterministic_header() {
96 let pairs = vec![
97 ("SESSDATA".to_string(), "session".to_string()),
98 ("bili_jct".to_string(), "csrf".to_string()),
99 ];
100
101 assert_eq!(
102 format_cookie_pairs(&pairs),
103 "SESSDATA=session; bili_jct=csrf"
104 );
105 }
106}