Skip to main content

aws_smithy_schema/schema/
error_envelope.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! Shared helpers for parsing AWS protocol error envelopes.
7//!
8//! The JSON and CBOR protocols both extract an error code from a response
9//! envelope and honor the awsQueryCompatible `X-Amzn-Query-Error` header.
10//! The wire conventions for the code (a `namespace#Name` shape id, optionally
11//! with a trailing `:url` suffix) and for that header are identical across the
12//! two protocols, so the parsing lives here instead of being duplicated in
13//! each codec.
14
15use aws_smithy_runtime_api::http::Headers;
16
17/// Strips a leading `namespace#` prefix and a trailing `:url` suffix from a
18/// wire-format error code, leaving just the bare shape name.
19///
20/// Examples:
21/// - `"FooError"` → `"FooError"`
22/// - `"com.example#FooError"` → `"FooError"`
23/// - `"FooError:http://internal.example.com/coral/.../"` → `"FooError"`
24/// - `"com.example#FooError:http://..."` → `"FooError"`
25pub fn sanitize_error_code(error_code: &str) -> &str {
26    // Strip a trailing URL-style suffix (`:url`) first ...
27    let error_code = match error_code.find(':') {
28        Some(idx) => &error_code[..idx],
29        None => error_code,
30    };
31    // ... then a leading `namespace#` prefix.
32    match error_code.find('#') {
33        Some(idx) => &error_code[idx + 1..],
34        None => error_code,
35    }
36}
37
38/// Parses an `X-Amzn-Query-Error: <code>;<type>` header into its `(code, type)`
39/// halves, as emitted by awsQueryCompatible services.
40///
41/// Returns `None` if the header is absent or has no `;` separator.
42pub fn parse_query_compatible_header(headers: &Headers) -> Option<(&str, &str)> {
43    let value = headers.get("x-amzn-query-error")?;
44    value
45        .find(';')
46        .map(|idx| (&value[..idx], &value[idx + 1..]))
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52    use aws_smithy_runtime_api::http::Headers;
53
54    #[test]
55    fn sanitize_strips_namespace_and_url() {
56        assert_eq!(sanitize_error_code("FooError"), "FooError");
57        assert_eq!(sanitize_error_code("com.example#FooError"), "FooError");
58        assert_eq!(
59            sanitize_error_code("FooError:http://internal.example.com/x"),
60            "FooError"
61        );
62        assert_eq!(
63            sanitize_error_code("com.example#FooError:http://internal/x"),
64            "FooError"
65        );
66    }
67
68    #[test]
69    fn query_compatible_header_splits_on_semicolon() {
70        let mut headers = Headers::new();
71        headers.insert("x-amzn-query-error", "AWS.SimpleQueueService.Foo;Sender");
72        assert_eq!(
73            parse_query_compatible_header(&headers),
74            Some(("AWS.SimpleQueueService.Foo", "Sender"))
75        );
76    }
77
78    #[test]
79    fn query_compatible_header_absent_or_malformed_is_none() {
80        let empty = Headers::new();
81        assert_eq!(parse_query_compatible_header(&empty), None);
82
83        let mut no_separator = Headers::new();
84        no_separator.insert("x-amzn-query-error", "NoSemicolon");
85        assert_eq!(parse_query_compatible_header(&no_separator), None);
86    }
87}