Skip to content

Commit 2aa6aa8

Browse files
committed
Cover compat rewrite branches
1 parent ffd7ba3 commit 2aa6aa8

1 file changed

Lines changed: 132 additions & 0 deletions

File tree

src/compat.rs

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,27 @@ mod tests {
709709
);
710710
}
711711

712+
/// Covers supported RFC 2047 Q words and unsupported metadata encodings.
713+
#[test]
714+
fn decodes_rfc2047_q_metadata_and_rejects_unsupported_words() {
715+
assert_eq!(
716+
decode_rfc2047_header_value("=?UTF-8?Q?Hello_World=C3=A9?=").as_deref(),
717+
Some("Hello World\u{e9}")
718+
);
719+
assert_eq!(
720+
decode_rfc2047_header_value("=?utf-8?q?=c3=a9?=").as_deref(),
721+
Some("\u{e9}")
722+
);
723+
assert_eq!(
724+
decode_rfc2047_header_value("=?us-ascii?Q?AZaz09=21?=").as_deref(),
725+
Some("AZaz09!")
726+
);
727+
assert_eq!(decode_rfc2047_header_value("=?iso-8859-1?Q?caf=E9?="), None);
728+
assert_eq!(decode_rfc2047_header_value("=?UTF-8?X?abc?="), None);
729+
assert_eq!(decode_rfc2047_header_value("=?UTF-8?Q?bad=GG?="), None);
730+
assert_eq!(decode_rfc2047_header_value("plain"), None);
731+
}
732+
712733
#[tokio::test]
713734
async fn rewrites_object_lock_invalid_retention_error_code() -> Result<(), HttpError> {
714735
let mut response = HttpResponse::new(Body::from(
@@ -725,6 +746,97 @@ mod tests {
725746
Ok(())
726747
}
727748

749+
/// Keeps XML error rewrites scoped to matching status, marker, and UTF-8 bodies.
750+
#[tokio::test]
751+
async fn leaves_non_target_xml_error_rewrites_alone() -> Result<(), HttpError> {
752+
let mut wrong_status = HttpResponse::new(Body::from(
753+
"<Error><Code>InvalidRequest</Code><Message>InvalidRetentionPeriod</Message></Error>"
754+
.to_string(),
755+
));
756+
*wrong_status.status_mut() = StatusCode::NOT_FOUND;
757+
let wrong_status = rewrite_invalid_retention_period_code(wrong_status).await?;
758+
assert_eq!(wrong_status.status(), StatusCode::NOT_FOUND);
759+
assert!(
760+
response_body_text(wrong_status)
761+
.await?
762+
.contains("InvalidRequest")
763+
);
764+
765+
let mut missing_marker = HttpResponse::new(Body::from(
766+
"<Error><Code>InvalidRequest</Code><Message>other</Message></Error>".to_string(),
767+
));
768+
*missing_marker.status_mut() = StatusCode::BAD_REQUEST;
769+
let missing_marker = rewrite_invalid_retention_period_code(missing_marker).await?;
770+
assert!(
771+
response_body_text(missing_marker)
772+
.await?
773+
.contains("InvalidRequest")
774+
);
775+
776+
let mut non_utf8 = HttpResponse::new(Body::from(Bytes::from_static(&[0xff, b'<'])));
777+
*non_utf8.status_mut() = StatusCode::BAD_REQUEST;
778+
let non_utf8 = rewrite_invalid_retention_period_code(non_utf8).await?;
779+
let bytes = non_utf8
780+
.into_body()
781+
.collect()
782+
.await
783+
.map_err(HttpError::new)?
784+
.to_bytes();
785+
assert_eq!(bytes.as_ref(), &[0xff, b'<']);
786+
787+
Ok(())
788+
}
789+
790+
/// Covers POST Object status compatibility rewrites for parsed policy errors.
791+
#[tokio::test]
792+
async fn rewrites_post_policy_condition_statuses() -> Result<(), HttpError> {
793+
let mut invalid_policy = HttpResponse::new(Body::from(
794+
"<Error><Code>InvalidPolicyDocument</Code><Message>Policy condition failed</Message></Error>"
795+
.to_string(),
796+
));
797+
*invalid_policy.status_mut() = StatusCode::BAD_REQUEST;
798+
let invalid_policy = rewrite_post_policy_condition_status(invalid_policy).await?;
799+
assert_eq!(invalid_policy.status(), StatusCode::FORBIDDEN);
800+
801+
let mut access_denied = HttpResponse::new(Body::from(
802+
"<Error><Code>AccessDenied</Code><Message>condition mismatch</Message></Error>"
803+
.to_string(),
804+
));
805+
*access_denied.status_mut() = StatusCode::FORBIDDEN;
806+
let access_denied = rewrite_post_policy_condition_status(access_denied).await?;
807+
assert_eq!(access_denied.status(), StatusCode::BAD_REQUEST);
808+
809+
let mut expired = HttpResponse::new(Body::from(
810+
"<Error><Code>AccessDenied</Code><Message>Request has expired</Message></Error>"
811+
.to_string(),
812+
));
813+
*expired.status_mut() = StatusCode::FORBIDDEN;
814+
let expired = rewrite_post_policy_condition_status(expired).await?;
815+
assert_eq!(expired.status(), StatusCode::FORBIDDEN);
816+
817+
let mut field_missing = HttpResponse::new(Body::from(
818+
"<Error><Code>AccessDenied</Code><Message>Each form field must appear</Message></Error>"
819+
.to_string(),
820+
));
821+
*field_missing.status_mut() = StatusCode::FORBIDDEN;
822+
let field_missing = rewrite_post_policy_condition_status(field_missing).await?;
823+
assert_eq!(field_missing.status(), StatusCode::FORBIDDEN);
824+
825+
let mut non_utf8 = HttpResponse::new(Body::from(Bytes::from_static(&[0xff, b'a'])));
826+
*non_utf8.status_mut() = StatusCode::FORBIDDEN;
827+
let non_utf8 = rewrite_post_policy_condition_status(non_utf8).await?;
828+
assert_eq!(non_utf8.status(), StatusCode::FORBIDDEN);
829+
let bytes = non_utf8
830+
.into_body()
831+
.collect()
832+
.await
833+
.map_err(HttpError::new)?
834+
.to_bytes();
835+
assert_eq!(bytes.as_ref(), &[0xff, b'a']);
836+
837+
Ok(())
838+
}
839+
728840
#[test]
729841
fn presigned_expiry_validation_matches_compat_contract()
730842
-> Result<(), Box<dyn std::error::Error + Send + Sync>> {
@@ -868,6 +980,10 @@ mod tests {
868980
),
869981
"EpELyoQzABuh9lHQ+KwND1xJ+Uc="
870982
);
983+
assert_eq!(
984+
sig_v2_signature(&"k".repeat(65), "data"),
985+
"zmngYEpYGiC5dY+v6heIjy+/Few="
986+
);
871987
}
872988

873989
#[test]
@@ -924,6 +1040,22 @@ mod tests {
9241040
Ok(())
9251041
}
9261042

1043+
/// Leaves create-bucket `SigV2` authorization alone when the slash signature is invalid.
1044+
#[test]
1045+
fn skips_create_bucket_sig_v2_rewrite_for_signature_mismatch() -> Result<(), hyper::http::Error>
1046+
{
1047+
let auth = AuthorizationV2 {
1048+
access_key: "access".to_string(),
1049+
signature: "signature".to_string(),
1050+
};
1051+
let mut req = request(Method::PUT, "/bucket")?;
1052+
1053+
rewrite_create_bucket_sig_v2(&mut req, "secret", &auth);
1054+
1055+
assert!(req.headers().get(header::AUTHORIZATION).is_none());
1056+
Ok(())
1057+
}
1058+
9271059
#[test]
9281060
fn sig_v2_header_compat_rejects_malformed_auth_and_rewrites_valid_bucket_request()
9291061
-> Result<(), hyper::http::Error> {

0 commit comments

Comments
 (0)