Skip to content

Commit 653e4cd

Browse files
authored
Revamp errors for aws-sigv4 (#1937)
1 parent 12f217b commit 653e4cd

File tree

7 files changed

+129
-20
lines changed

7 files changed

+129
-20
lines changed

aws/rust-runtime/aws-sig-auth/external-types.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
allowed_external_types = [
22
"aws_sigv4::http_request::sign::SignableBody",
3+
"aws_sigv4::http_request::error::SigningError",
34
"aws_smithy_http::*",
45
"aws_types::*",
56
"http::request::Request",

aws/rust-runtime/aws-sig-auth/src/middleware.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ impl From<SigningError> for SigningStageError {
103103
impl Error for SigningStageError {
104104
fn source(&self) -> Option<&(dyn Error + 'static)> {
105105
match &self {
106-
SigningStageError::SigningFailure(err) => Some(err.as_ref()),
106+
SigningStageError::SigningFailure(err) => Some(err),
107107
_ => None,
108108
}
109109
}
@@ -160,7 +160,7 @@ impl MapRequest for SigV4SigningStage {
160160
let signature = self
161161
.signer
162162
.sign(operation_config, &request_config, &creds, &mut req)
163-
.map_err(|err| SigningStageError::SigningFailure(err))?;
163+
.map_err(SigningStageError::SigningFailure)?;
164164
config.insert(signature);
165165
Ok(req)
166166
})

aws/rust-runtime/aws-sig-auth/src/signer.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ use aws_smithy_http::body::SdkBody;
1212
use aws_types::region::SigningRegion;
1313
use aws_types::Credentials;
1414
use aws_types::SigningService;
15-
use std::error::Error;
1615
use std::fmt;
1716
use std::time::{Duration, SystemTime};
1817

1918
pub use aws_sigv4::http_request::SignableBody;
19+
pub type SigningError = aws_sigv4::http_request::SigningError;
2020

2121
const EXPIRATION_WARNING: &str = "Presigned request will expire before the given \
2222
`expires_in` duration because the credentials used to sign it will expire first.";
@@ -121,8 +121,6 @@ impl fmt::Debug for SigV4Signer {
121121
}
122122
}
123123

124-
pub type SigningError = Box<dyn Error + Send + Sync>;
125-
126124
impl SigV4Signer {
127125
pub fn new() -> Self {
128126
SigV4Signer { _private: () }

aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
use super::query_writer::QueryWriter;
7-
use super::{Error, PayloadChecksumKind, SignableBody, SignatureLocation, SigningParams};
86
use crate::date_time::{format_date, format_date_time};
7+
use crate::http_request::error::CanonicalRequestError;
8+
use crate::http_request::query_writer::QueryWriter;
99
use crate::http_request::sign::SignableRequest;
1010
use crate::http_request::url_escape::percent_encode_path;
1111
use crate::http_request::PercentEncodingMode;
12+
use crate::http_request::{PayloadChecksumKind, SignableBody, SignatureLocation, SigningParams};
1213
use crate::sign::sha256_hex_string;
1314
use http::header::{HeaderName, HOST};
1415
use http::{HeaderMap, HeaderValue, Method, Uri};
@@ -124,7 +125,7 @@ impl<'a> CanonicalRequest<'a> {
124125
pub(super) fn from<'b>(
125126
req: &'b SignableRequest<'b>,
126127
params: &'b SigningParams<'b>,
127-
) -> Result<CanonicalRequest<'b>, Error> {
128+
) -> Result<CanonicalRequest<'b>, CanonicalRequestError> {
128129
// Path encoding: if specified, re-encode % as %25
129130
// Set method and path into CanonicalRequest
130131
let path = req.uri().path();
@@ -182,7 +183,7 @@ impl<'a> CanonicalRequest<'a> {
182183
params: &SigningParams<'_>,
183184
payload_hash: &str,
184185
date_time: &str,
185-
) -> Result<(Vec<CanonicalHeaderName>, HeaderMap), Error> {
186+
) -> Result<(Vec<CanonicalHeaderName>, HeaderMap), CanonicalRequestError> {
186187
// Header computation:
187188
// The canonical request will include headers not present in the input. We need to clone and
188189
// normalize the headers from the original request and add:
@@ -375,9 +376,15 @@ fn trim_spaces_from_byte_string(bytes: &[u8]) -> &[u8] {
375376

376377
/// Works just like [trim_all] but acts on HeaderValues instead of bytes.
377378
/// Will ensure that the underlying bytes are valid UTF-8.
378-
fn normalize_header_value(header_value: &HeaderValue) -> Result<HeaderValue, Error> {
379+
fn normalize_header_value(
380+
header_value: &HeaderValue,
381+
) -> Result<HeaderValue, CanonicalRequestError> {
379382
let trimmed_value = trim_all(header_value.as_bytes());
380-
HeaderValue::from_str(std::str::from_utf8(&trimmed_value)?).map_err(Error::from)
383+
HeaderValue::from_str(
384+
std::str::from_utf8(&trimmed_value)
385+
.map_err(CanonicalRequestError::invalid_utf8_in_header_value)?,
386+
)
387+
.map_err(CanonicalRequestError::from)
381388
}
382389

383390
#[derive(Debug, PartialEq, Default)]
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
use http::header::{InvalidHeaderName, InvalidHeaderValue};
7+
use std::error::Error;
8+
use std::fmt;
9+
use std::str::Utf8Error;
10+
11+
#[derive(Debug)]
12+
enum SigningErrorKind {
13+
FailedToCreateCanonicalRequest { source: CanonicalRequestError },
14+
}
15+
16+
/// Error signing request
17+
#[derive(Debug)]
18+
pub struct SigningError {
19+
kind: SigningErrorKind,
20+
}
21+
22+
impl fmt::Display for SigningError {
23+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24+
match self.kind {
25+
SigningErrorKind::FailedToCreateCanonicalRequest { .. } => {
26+
write!(f, "failed to create canonical request")
27+
}
28+
}
29+
}
30+
}
31+
32+
impl Error for SigningError {
33+
fn source(&self) -> Option<&(dyn Error + 'static)> {
34+
match &self.kind {
35+
SigningErrorKind::FailedToCreateCanonicalRequest { source } => Some(source),
36+
}
37+
}
38+
}
39+
40+
impl From<CanonicalRequestError> for SigningError {
41+
fn from(source: CanonicalRequestError) -> Self {
42+
Self {
43+
kind: SigningErrorKind::FailedToCreateCanonicalRequest { source },
44+
}
45+
}
46+
}
47+
48+
#[derive(Debug)]
49+
enum CanonicalRequestErrorKind {
50+
InvalidHeaderName { source: InvalidHeaderName },
51+
InvalidHeaderValue { source: InvalidHeaderValue },
52+
InvalidUtf8InHeaderValue { source: Utf8Error },
53+
}
54+
55+
#[derive(Debug)]
56+
pub(crate) struct CanonicalRequestError {
57+
kind: CanonicalRequestErrorKind,
58+
}
59+
60+
impl fmt::Display for CanonicalRequestError {
61+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62+
use CanonicalRequestErrorKind::*;
63+
match self.kind {
64+
InvalidHeaderName { .. } => write!(f, "invalid header name"),
65+
InvalidHeaderValue { .. } => write!(f, "invalid header value"),
66+
InvalidUtf8InHeaderValue { .. } => write!(f, "invalid UTF-8 in header value"),
67+
}
68+
}
69+
}
70+
71+
impl Error for CanonicalRequestError {
72+
fn source(&self) -> Option<&(dyn Error + 'static)> {
73+
use CanonicalRequestErrorKind::*;
74+
match &self.kind {
75+
InvalidHeaderName { source } => Some(source),
76+
InvalidHeaderValue { source } => Some(source),
77+
InvalidUtf8InHeaderValue { source } => Some(source),
78+
}
79+
}
80+
}
81+
82+
impl CanonicalRequestError {
83+
pub(crate) fn invalid_utf8_in_header_value(source: Utf8Error) -> Self {
84+
Self {
85+
kind: CanonicalRequestErrorKind::InvalidUtf8InHeaderValue { source },
86+
}
87+
}
88+
}
89+
90+
impl From<InvalidHeaderName> for CanonicalRequestError {
91+
fn from(source: InvalidHeaderName) -> Self {
92+
Self {
93+
kind: CanonicalRequestErrorKind::InvalidHeaderName { source },
94+
}
95+
}
96+
}
97+
98+
impl From<InvalidHeaderValue> for CanonicalRequestError {
99+
fn from(source: InvalidHeaderValue) -> Self {
100+
Self {
101+
kind: CanonicalRequestErrorKind::InvalidHeaderValue { source },
102+
}
103+
}
104+
}

aws/rust-runtime/aws-sigv4/src/http_request/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
//! # Example: Signing an HTTP request
99
//!
1010
//! ```rust
11-
//! # fn test() -> Result<(), aws_sigv4::http_request::Error> {
11+
//! # fn test() -> Result<(), aws_sigv4::http_request::SigningError> {
1212
//! use aws_sigv4::http_request::{sign, SigningSettings, SigningParams, SignableRequest};
1313
//! use http;
1414
//! use std::time::SystemTime;
@@ -42,6 +42,7 @@
4242
//!
4343
4444
mod canonical_request;
45+
mod error;
4546
mod query_writer;
4647
mod settings;
4748
mod sign;
@@ -50,7 +51,8 @@ mod url_escape;
5051
#[cfg(test)]
5152
pub(crate) mod test;
5253

54+
pub use error::SigningError;
5355
pub use settings::{
5456
PayloadChecksumKind, PercentEncodingMode, SignatureLocation, SigningParams, SigningSettings,
5557
};
56-
pub use sign::{sign, Error, SignableBody, SignableRequest};
58+
pub use sign::{sign, SignableBody, SignableRequest};

aws/rust-runtime/aws-sigv4/src/http_request/sign.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6+
use super::error::SigningError;
67
use super::{PayloadChecksumKind, SignatureLocation};
78
use crate::http_request::canonical_request::header;
89
use crate::http_request::canonical_request::param;
@@ -15,12 +16,8 @@ use http::header::HeaderValue;
1516
use http::{HeaderMap, Method, Uri};
1617
use std::borrow::Cow;
1718
use std::convert::TryFrom;
18-
use std::error::Error as StdError;
1919
use std::str;
2020

21-
/// Signing error type
22-
pub type Error = Box<dyn StdError + Send + Sync + 'static>;
23-
2421
/// Represents all of the information necessary to sign an HTTP request.
2522
#[derive(Debug)]
2623
#[non_exhaustive]
@@ -155,7 +152,7 @@ impl SigningInstructions {
155152
pub fn sign<'a>(
156153
request: SignableRequest<'a>,
157154
params: &'a SigningParams<'a>,
158-
) -> Result<SigningOutput<SigningInstructions>, Error> {
155+
) -> Result<SigningOutput<SigningInstructions>, SigningError> {
159156
tracing::trace!(request = ?request, params = ?params, "signing request");
160157
match params.settings.signature_location {
161158
SignatureLocation::Headers => {
@@ -181,7 +178,7 @@ type CalculatedParams = Vec<(&'static str, Cow<'static, str>)>;
181178
fn calculate_signing_params<'a>(
182179
request: &'a SignableRequest<'a>,
183180
params: &'a SigningParams<'a>,
184-
) -> Result<(CalculatedParams, String), Error> {
181+
) -> Result<(CalculatedParams, String), SigningError> {
185182
let creq = CanonicalRequest::from(request, params)?;
186183
tracing::trace!(canonical_request = %creq);
187184

@@ -230,7 +227,7 @@ fn calculate_signing_params<'a>(
230227
fn calculate_signing_headers<'a>(
231228
request: &'a SignableRequest<'a>,
232229
params: &'a SigningParams<'a>,
233-
) -> Result<SigningOutput<HeaderMap<HeaderValue>>, Error> {
230+
) -> Result<SigningOutput<HeaderMap<HeaderValue>>, SigningError> {
234231
// Step 1: https://docs.aws.amazon.com/en_pv/general/latest/gr/sigv4-create-canonical-request.html.
235232
let creq = CanonicalRequest::from(request, params)?;
236233
tracing::trace!(canonical_request = %creq);

0 commit comments

Comments
 (0)