aws_sdk_s3/
s3_request_id.rs1use aws_smithy_runtime_api::client::result::SdkError;
8use aws_smithy_runtime_api::http::{Headers, Response};
9use aws_smithy_types::error::metadata::{Builder as ErrorMetadataBuilder, ErrorMetadata};
10
11const EXTENDED_REQUEST_ID: &str = "s3_extended_request_id";
12
13pub trait RequestIdExt {
17 fn extended_request_id(&self) -> Option<&str>;
19}
20
21impl<E> RequestIdExt for SdkError<E, Response> {
22 fn extended_request_id(&self) -> Option<&str> {
23 match self {
24 Self::ResponseError(err) => err.raw().headers().extended_request_id(),
25 Self::ServiceError(err) => err.raw().headers().extended_request_id(),
26 _ => None,
27 }
28 }
29}
30
31impl RequestIdExt for ErrorMetadata {
32 fn extended_request_id(&self) -> Option<&str> {
33 self.extra(EXTENDED_REQUEST_ID)
34 }
35}
36
37impl<B> RequestIdExt for Response<B> {
38 fn extended_request_id(&self) -> Option<&str> {
39 self.headers().extended_request_id()
40 }
41}
42
43impl RequestIdExt for Headers {
44 fn extended_request_id(&self) -> Option<&str> {
45 self.get("x-amz-id-2")
46 }
47}
48
49impl<O, E> RequestIdExt for Result<O, E>
50where
51 O: RequestIdExt,
52 E: RequestIdExt,
53{
54 fn extended_request_id(&self) -> Option<&str> {
55 match self {
56 Ok(ok) => ok.extended_request_id(),
57 Err(err) => err.extended_request_id(),
58 }
59 }
60}
61
62pub(crate) fn apply_extended_request_id(builder: ErrorMetadataBuilder, headers: &Headers) -> ErrorMetadataBuilder {
64 if let Some(extended_request_id) = headers.extended_request_id() {
65 builder.custom(EXTENDED_REQUEST_ID, extended_request_id)
66 } else {
67 builder
68 }
69}
70
71#[cfg(test)]
72mod test {
73 use super::*;
74 use aws_smithy_runtime_api::client::result::SdkError;
75 use aws_smithy_types::body::SdkBody;
76
77 #[test]
78 fn handle_missing_header() {
79 let resp = Response::try_from(http::Response::builder().status(400).body("").unwrap()).unwrap();
80 let mut builder = ErrorMetadata::builder().message("123");
81 builder = apply_extended_request_id(builder, resp.headers());
82 assert_eq!(builder.build().extended_request_id(), None);
83 }
84
85 #[test]
86 fn test_extended_request_id_sdk_error() {
87 let without_extended_request_id = || Response::try_from(http::Response::builder().body(SdkBody::empty()).unwrap()).unwrap();
88 let with_extended_request_id = || {
89 Response::try_from(
90 http::Response::builder()
91 .header("x-amz-id-2", "some-request-id")
92 .body(SdkBody::empty())
93 .unwrap(),
94 )
95 .unwrap()
96 };
97 assert_eq!(
98 None,
99 SdkError::<(), _>::response_error("test", without_extended_request_id()).extended_request_id()
100 );
101 assert_eq!(
102 Some("some-request-id"),
103 SdkError::<(), _>::response_error("test", with_extended_request_id()).extended_request_id()
104 );
105 assert_eq!(None, SdkError::service_error((), without_extended_request_id()).extended_request_id());
106 assert_eq!(
107 Some("some-request-id"),
108 SdkError::service_error((), with_extended_request_id()).extended_request_id()
109 );
110 }
111
112 #[test]
113 fn test_extract_extended_request_id() {
114 let mut headers = Headers::new();
115 assert_eq!(None, headers.extended_request_id());
116
117 headers.append("x-amz-id-2", "some-request-id");
118 assert_eq!(Some("some-request-id"), headers.extended_request_id());
119 }
120
121 #[test]
122 fn test_apply_extended_request_id() {
123 let mut headers = Headers::new();
124 assert_eq!(
125 ErrorMetadata::builder().build(),
126 apply_extended_request_id(ErrorMetadata::builder(), &headers).build(),
127 );
128
129 headers.append("x-amz-id-2", "some-request-id");
130 assert_eq!(
131 ErrorMetadata::builder().custom(EXTENDED_REQUEST_ID, "some-request-id").build(),
132 apply_extended_request_id(ErrorMetadata::builder(), &headers).build(),
133 );
134 }
135
136 #[test]
137 fn test_error_metadata_extended_request_id_impl() {
138 let err = ErrorMetadata::builder().custom(EXTENDED_REQUEST_ID, "some-request-id").build();
139 assert_eq!(Some("some-request-id"), err.extended_request_id());
140 }
141}