cookie_monster/cookie/
serialize.rs1use crate::{
2 Error, SameSite,
3 cookie::parse::{find_invalid_cookie_value, invalid_token, trim_quotes},
4};
5
6use super::Cookie;
7use std::fmt::Write;
8
9impl Cookie {
10 pub fn serialize(&self) -> crate::Result<String> {
19 self.serialize_inner(|name, value, buf| {
20 let trimmed_value = trim_quotes(value);
23
24 if let Some(invalid_char) = find_invalid_cookie_value(trimmed_value) {
25 return Err(Error::InvalidValue(invalid_char));
26 } else if let Some(token) = invalid_token(name) {
27 return Err(Error::InvalidName(token));
28 }
29
30 let _ = write!(buf, "{name}={value}");
31 Ok(())
32 })
33 }
34
35 #[cfg(feature = "percent-encode")]
43 pub fn serialize_encoded(&self) -> crate::Result<String> {
44 use crate::cookie::encoding::{encode_name, encode_value};
45
46 self.serialize_inner(|name, value, buf| {
47 let _ = write!(buf, "{}={}", encode_name(name), encode_value(value));
49 Ok(())
50 })
51 }
52
53 fn serialize_inner(
54 &self,
55 callback: impl Fn(&str, &str, &mut String) -> crate::Result<()>,
56 ) -> crate::Result<String> {
57 let value = self.value();
58 let name = self.name();
59 let domain = self.domain();
60 let path = self.path();
61
62 if name.is_empty() {
63 return Err(Error::NameEmpty);
64 }
65
66 let prefix = self.prefix.map(|p| p.as_str()).unwrap_or_default();
67
68 let buf_len = prefix.len()
69 + name.len()
70 + value.len()
71 + domain.map(str::len).unwrap_or_default()
72 + path.map(str::len).unwrap_or_default();
73
74 let mut buf = String::with_capacity(buf_len + 110);
77
78 buf.push_str(prefix);
80
81 callback(name, value, &mut buf)?;
84
85 if let Some(max_age) = self.max_age_secs() {
87 buf.push_str("; Max-Age=");
88 write!(&mut buf, "{max_age}").expect("Failed to write Max-Age seconds");
89 }
90
91 self.serialize_domain(&mut buf);
92
93 self.serialize_path(&mut buf)?;
94
95 if self.is_secure() || self.is_partitioned() || self.same_site() == Some(SameSite::None) {
97 buf.push_str("; Secure");
98 }
99
100 if self.is_http_only() {
101 buf.push_str("; HttpOnly");
102 }
103
104 if self.is_partitioned() {
105 buf.push_str("; Partitioned");
106 }
107
108 self.serialize_same_site(&mut buf);
109
110 self.serialize_expire(&mut buf)?;
111 Ok(buf)
112 }
113}