@@ -15,30 +15,36 @@ pub const PARAM_SIGNATURE: &str = "X-Os-Signature";
1515/// - Method is always `GET` (HEAD maps to GET).
1616/// - Path uses the encoded URI path as received by the service.
1717/// - Percent-encoded octets are normalized to uppercase hex digits.
18- /// - Query params use the encoded key/value pairs from the URI, excluding
19- /// `X-Os-Signature`, sorted by encoded key.
18+ /// - Query params use the encoded keys and optional values from the URI,
19+ /// excluding `X-Os-Signature`, sorted by encoded key.
2020pub fn canonical_presigned_request ( path : & str , query : Option < & str > ) -> String {
2121 let canonical_path = normalize_percent_encoding ( path) ;
2222
23- let mut params: Vec < ( String , String ) > = query
23+ let mut params: Vec < ( String , Option < String > ) > = query
2424 . unwrap_or ( "" )
2525 . split ( '&' )
2626 . filter ( |s| !s. is_empty ( ) )
2727 . filter_map ( |pair| {
28- let ( k, v) = pair. split_once ( '=' ) ?;
28+ let ( k, v) = match pair. split_once ( '=' ) {
29+ Some ( ( k, v) ) => ( k, Some ( normalize_percent_encoding ( v) ) ) ,
30+ None => ( pair, None ) ,
31+ } ;
2932 let canonical_key = normalize_percent_encoding ( k) ;
3033 if canonical_key == PARAM_SIGNATURE {
3134 return None ;
3235 }
33- Some ( ( canonical_key, normalize_percent_encoding ( v ) ) )
36+ Some ( ( canonical_key, v ) )
3437 } )
3538 . collect ( ) ;
3639
3740 params. sort_by ( |a, b| a. 0 . cmp ( & b. 0 ) . then_with ( || a. 1 . cmp ( & b. 1 ) ) ) ;
3841
3942 let query_str = params
4043 . iter ( )
41- . map ( |( k, v) | format ! ( "{k}={v}" ) )
44+ . map ( |( k, v) | match v {
45+ Some ( v) => format ! ( "{k}={v}" ) ,
46+ None => k. clone ( ) ,
47+ } )
4248 . collect :: < Vec < _ > > ( )
4349 . join ( "&" ) ;
4450
@@ -114,4 +120,14 @@ mod tests {
114120 let c2 = canonical_presigned_request ( "/path" , Some ( "X-Os-Expires=1000&X-Os-KeyId=test" ) ) ;
115121 assert_eq ! ( c1, c2) ;
116122 }
123+
124+ #[ test]
125+ fn test_canonical_form_bare_query_params ( ) {
126+ let canonical =
127+ canonical_presigned_request ( "/path" , Some ( "y&X-Os-KeyId=test&x=1&X-Os-Expires=1000&z" ) ) ;
128+ assert_eq ! (
129+ canonical,
130+ "GET\n /path\n X-Os-Expires=1000&X-Os-KeyId=test&x=1&y&z"
131+ ) ;
132+ }
117133}
0 commit comments