bench_scraper/cookie.rs
1#![warn(missing_docs)]
2
3#[derive(Debug, PartialEq, Eq)]
4/// The [SameSite](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite) policy for a cookie.
5pub enum SameSite {
6 /// Cookies are not sent on normal cross-site subrequests, but are sent when a user is navigating to the origin site.
7 Lax,
8 /// Cookies will only be sent in a first-party context and not be sent along with requests initiated by third party websites.
9 Strict,
10 /// Cookies will be sent in all contexts, i.e. in responses to both first-party and cross-site requests.
11 None,
12}
13
14#[derive(Debug, PartialEq, Eq)]
15/// A single HTTP cookie.
16pub struct Cookie {
17 /// The host (domain) with which the cookie is associated.
18 pub host: String,
19 /// The path under which the cookie should be used when making requests.
20 pub path: String,
21 /// The name of the cookie.
22 pub name: String,
23 /// The contents of the cookie.
24 pub value: String,
25 /// Whether the cookie should only be sent over encrypted channels (https).
26 pub is_secure: bool,
27 /// Whether the cookie should be hidden from client-side scripting (javascript).
28 pub is_http_only: bool,
29 /// When the cookie was first registered with the browser.
30 pub creation_time: time::OffsetDateTime,
31 /// When the cookie will no longer be valid.
32 pub expiration_time: Option<time::OffsetDateTime>,
33 /// The SameSite setting for the cookie (which may not have been specified).
34 pub same_site: Option<SameSite>,
35 /// The last time the cookie was accessed by the browser (if this data is tracked).
36 pub last_accessed: Option<time::OffsetDateTime>,
37}
38
39impl Cookie {
40 /// Crafts a [`Set-Cookie` header value] corresponding to this cookie.
41 ///
42 /// [`Set-Cookie` header value]: https://developer.mozilla.org/docs/Web/HTTP/Headers/Set-Cookie
43 pub fn get_set_cookie_header(&self) -> String {
44 let mut properties: Vec<String> = vec![
45 format!("{}={}", self.name, self.value),
46 format!("Path={}", self.path),
47 ];
48 // we're doing our best to guess whether domain is set or not
49 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
50 if !self.name.starts_with("__Host-") {
51 properties.push(format!("Domain={}", self.host));
52 }
53 if let Some(expiration) = self.expiration_time {
54 if let Ok(format) = expiration.format(&time::format_description::well_known::Rfc2822) {
55 properties.push(format!("Expires={}", format));
56 }
57 }
58 if self.is_secure {
59 properties.push("Secure".to_string())
60 }
61 if self.is_http_only {
62 properties.push("HttpOnly".to_string());
63 }
64 if let Some(ss) = &self.same_site {
65 properties.push(format!(
66 "SameSite={}",
67 match ss {
68 SameSite::Lax => "Lax",
69 SameSite::Strict => "Strict",
70 SameSite::None => "None",
71 }
72 ));
73 }
74 properties.join("; ")
75 }
76
77 /// Creates a [URL] that could have feasibly responded with this cookie as a `Set-Cookie` header.
78 ///
79 /// This URL is a guess based on the cookie's domain and path;
80 /// there is no guarantee that calls to this URL will set this cookie,
81 /// or even that this URL will respond successfully.
82 ///
83 /// [URL]: https://developer.mozilla.org/docs/Glossary/URL
84 pub fn get_url(&self) -> String {
85 format!("https://{}{}", self.host.trim_matches('.'), self.path)
86 }
87}
88
89#[cfg(feature = "reqwest")]
90impl TryFrom<Cookie> for reqwest::header::HeaderValue {
91 type Error = reqwest::header::InvalidHeaderValue;
92
93 fn try_from(cookie: Cookie) -> Result<Self, Self::Error> {
94 let result = cookie.get_set_cookie_header();
95 reqwest::header::HeaderValue::from_str(&result)
96 }
97}
98
99#[cfg(feature = "reqwest")]
100impl FromIterator<Cookie> for reqwest::cookie::Jar {
101 fn from_iter<I: IntoIterator<Item = Cookie>>(iter: I) -> reqwest::cookie::Jar {
102 let jar = reqwest::cookie::Jar::default();
103 for cookie in iter {
104 let set_cookie = cookie.get_set_cookie_header();
105 if let Ok(url) = reqwest::Url::parse(&cookie.get_url()) {
106 jar.add_cookie_str(&set_cookie, &url);
107 }
108 }
109 jar
110 }
111}