@@ -50,6 +50,42 @@ pub(super) struct HeaderValues<'a> {
5050 pub ( super ) signed_headers : SignedHeaders ,
5151}
5252
53+ #[ derive( Debug ) ]
54+ pub ( crate ) enum InvalidHeaderErrorKind {
55+ /// Invalid UTF-8 contained in HeaderValue
56+ InvalidUtf8 ,
57+ }
58+
59+ impl fmt:: Display for InvalidHeaderErrorKind {
60+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
61+ match self {
62+ InvalidHeaderErrorKind :: InvalidUtf8 => {
63+ write ! ( f, "invalid UTF-8 contained in header value" )
64+ }
65+ }
66+ }
67+ }
68+
69+ /// Error occurred while handling a `HeaderValue` in a `CanonicalRequest`.
70+ /// Thus the context of this error is specific to `CanonicalRequest`.
71+ #[ derive( Debug ) ]
72+ pub ( crate ) struct InvalidHeaderError {
73+ source : Error ,
74+ kind : InvalidHeaderErrorKind ,
75+ }
76+
77+ impl fmt:: Display for InvalidHeaderError {
78+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
79+ write ! ( f, "{}: {}" , self . kind, self . source)
80+ }
81+ }
82+
83+ impl std:: error:: Error for InvalidHeaderError {
84+ fn source ( & self ) -> Option < & ( dyn std:: error:: Error + ' static ) > {
85+ Some ( self . source . as_ref ( ) )
86+ }
87+ }
88+
5389#[ derive( Debug , PartialEq ) ]
5490pub ( super ) struct QueryParamValues < ' a > {
5591 pub ( super ) algorithm : & ' static str ,
@@ -377,7 +413,11 @@ fn trim_spaces_from_byte_string(bytes: &[u8]) -> &[u8] {
377413/// Will ensure that the underlying bytes are valid UTF-8.
378414fn normalize_header_value ( header_value : & HeaderValue ) -> Result < HeaderValue , Error > {
379415 let trimmed_value = trim_all ( header_value. as_bytes ( ) ) ;
380- let trimmed_value_as_utf8_str = std:: str:: from_utf8 ( & trimmed_value) . map_err ( Error :: from) ?;
416+ let trimmed_value_as_utf8_str =
417+ std:: str:: from_utf8 ( & trimmed_value) . map_err ( |e| InvalidHeaderError {
418+ source : Error :: from ( e) ,
419+ kind : InvalidHeaderErrorKind :: InvalidUtf8 ,
420+ } ) ?;
381421 HeaderValue :: from_str ( trimmed_value_as_utf8_str) . map_err ( Error :: from)
382422}
383423
@@ -499,7 +539,8 @@ impl<'a> fmt::Display for StringToSign<'a> {
499539mod tests {
500540 use crate :: date_time:: test_parsers:: parse_date_time;
501541 use crate :: http_request:: canonical_request:: {
502- normalize_header_value, trim_all, CanonicalRequest , SigningScope , StringToSign ,
542+ normalize_header_value, trim_all, CanonicalRequest , InvalidHeaderError , SigningScope ,
543+ StringToSign ,
503544 } ;
504545 use crate :: http_request:: query_writer:: QueryWriter ;
505546 use crate :: http_request:: test:: { test_canonical_request, test_request, test_sts} ;
@@ -752,8 +793,12 @@ mod tests {
752793 }
753794
754795 #[ test]
755- fn test_normalize_header_value_returns_err_on_invalid_utf8 ( ) {
796+ fn test_normalize_header_value_returns_expected_error_on_invalid_utf8 ( ) {
756797 let header_value = HeaderValue :: from_bytes ( & [ 0xC0 , 0xC1 ] ) . unwrap ( ) ;
757- assert ! ( normalize_header_value( & header_value) . is_err( ) ) ;
798+ assert ! ( normalize_header_value( & header_value)
799+ . err( )
800+ . unwrap( )
801+ . downcast_ref:: <InvalidHeaderError >( )
802+ . is_some( ) ) ;
758803 }
759804}
0 commit comments