1+ //! Cookie handling utilities.
2+ //!
3+ //! This module provides functionality for parsing and creating cookies
4+ //! used in the trusted server system.
5+
16use cookie:: { Cookie , CookieJar } ;
7+ use error_stack:: { Report , ResultExt } ;
28use fastly:: http:: header;
39use fastly:: Request ;
410
11+ use crate :: error:: TrustedServerError ;
512use crate :: settings:: Settings ;
613
714const COOKIE_MAX_AGE : i32 = 365 * 24 * 60 * 60 ; // 1 year
815
9- // return empty cookie jar for unparsable cookies
16+ /// Parses a cookie string into a [`CookieJar`].
17+ ///
18+ /// Returns an empty jar if the cookie string is unparseable.
19+ /// Individual invalid cookies are skipped rather than failing the entire parse.
1020pub fn parse_cookies_to_jar ( s : & str ) -> CookieJar {
1121 let cookie_str = s. trim ( ) . to_owned ( ) ;
1222 let mut jar = CookieJar :: new ( ) ;
@@ -19,20 +29,39 @@ pub fn parse_cookies_to_jar(s: &str) -> CookieJar {
1929 jar
2030}
2131
22- pub fn handle_request_cookies ( req : & Request ) -> Option < CookieJar > {
32+ /// Extracts and parses cookies from an HTTP request.
33+ ///
34+ /// Attempts to parse the Cookie header into a [`CookieJar`] for easy access
35+ /// to individual cookies.
36+ ///
37+ /// # Errors
38+ ///
39+ /// - [`TrustedServerError::InvalidHeaderValue`] if the Cookie header contains invalid UTF-8
40+ pub fn handle_request_cookies (
41+ req : & Request ,
42+ ) -> Result < Option < CookieJar > , Report < TrustedServerError > > {
2343 match req. get_header ( header:: COOKIE ) {
2444 Some ( header_value) => {
25- let header_value_str: & str = header_value. to_str ( ) . unwrap_or ( "" ) ;
26- let jar: CookieJar = parse_cookies_to_jar ( header_value_str) ;
27- Some ( jar)
45+ let header_value_str =
46+ header_value
47+ . to_str ( )
48+ . change_context ( TrustedServerError :: InvalidHeaderValue {
49+ message : "Cookie header contains invalid UTF-8" . to_string ( ) ,
50+ } ) ?;
51+ let jar = parse_cookies_to_jar ( header_value_str) ;
52+ Ok ( Some ( jar) )
2853 }
2954 None => {
30- log:: warn !( "No cookie header found in request" ) ;
31- None
55+ log:: debug !( "No cookie header found in request" ) ;
56+ Ok ( None )
3257 }
3358 }
3459}
3560
61+ /// Creates a synthetic ID cookie string.
62+ ///
63+ /// Generates a properly formatted cookie with security attributes
64+ /// for storing the synthetic ID.
3665pub fn create_synthetic_cookie ( settings : & Settings , synthetic_id : & str ) -> String {
3766 format ! (
3867 "synthetic_id={}; Domain={}; Path=/; Secure; SameSite=Lax; Max-Age={}" ,
@@ -84,7 +113,9 @@ mod tests {
84113 #[ test]
85114 fn test_handle_request_cookies ( ) {
86115 let req = Request :: get ( "http://example.com" ) . with_header ( header:: COOKIE , "c1=v1;c2=v2" ) ;
87- let jar = handle_request_cookies ( & req) . unwrap ( ) ;
116+ let jar = handle_request_cookies ( & req)
117+ . expect ( "should parse cookies" )
118+ . expect ( "should have cookie jar" ) ;
88119
89120 assert ! ( jar. iter( ) . count( ) == 2 ) ;
90121 assert_eq ! ( jar. get( "c1" ) . unwrap( ) . value( ) , "v1" ) ;
@@ -94,23 +125,27 @@ mod tests {
94125 #[ test]
95126 fn test_handle_request_cookies_with_empty_cookie ( ) {
96127 let req = Request :: get ( "http://example.com" ) . with_header ( header:: COOKIE , "" ) ;
97- let jar = handle_request_cookies ( & req) . unwrap ( ) ;
128+ let jar = handle_request_cookies ( & req)
129+ . expect ( "should parse cookies" )
130+ . expect ( "should have cookie jar" ) ;
98131
99132 assert ! ( jar. iter( ) . count( ) == 0 ) ;
100133 }
101134
102135 #[ test]
103136 fn test_handle_request_cookies_no_cookie_header ( ) {
104137 let req: Request = Request :: get ( "https://example.com" ) ;
105- let jar = handle_request_cookies ( & req) ;
138+ let jar = handle_request_cookies ( & req) . expect ( "should handle missing cookie header" ) ;
106139
107140 assert ! ( jar. is_none( ) ) ;
108141 }
109142
110143 #[ test]
111144 fn test_handle_request_cookies_invalid_cookie_header ( ) {
112145 let req = Request :: get ( "http://example.com" ) . with_header ( header:: COOKIE , "invalid" ) ;
113- let jar = handle_request_cookies ( & req) . unwrap ( ) ;
146+ let jar = handle_request_cookies ( & req)
147+ . expect ( "should parse cookies" )
148+ . expect ( "should have cookie jar" ) ;
114149
115150 assert ! ( jar. iter( ) . count( ) == 0 ) ;
116151 }
0 commit comments