Skip to content

Commit 1588945

Browse files
drganjooFahad Zubair
andauthored
Add tracing calls when an extension parameter cannot be constructed (#3378)
## Motivation and Context When a user defines a handler function with additional parameters, these parameters are constructed using the `FromRequest` trait implementation specific to their types. If `FromRequest` fails to construct the parameter – for instance, if `Extension<State>` is expected by the user but `Extension<Arc<State>>` is actually added by the extension layer – the server currently does not log a message indicating this construction failure. Instead, it simply returns a 500 internal server error. ## Description `tracing::{trace, error}` calls have been added. ## Breaking change `FromParts<P>::Rejection` **must** implement `std::fmt::Display`. ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._ --------- Co-authored-by: Fahad Zubair <fahadzub@amazon.com>
1 parent 17545f6 commit 1588945

File tree

7 files changed

+69
-12
lines changed

7 files changed

+69
-12
lines changed

rust-runtime/aws-smithy-http-server/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "aws-smithy-http-server"
3-
version = "0.62.1"
3+
version = "0.63.0"
44
authors = ["Smithy Rust Server <smithy-rs-server@amazon.com>"]
55
edition = "2021"
66
license = "Apache-2.0"

rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ pin_project! {
117117
impl<P, Input, B, S> Future for UpgradeFuture<P, Input, B, S>
118118
where
119119
Input: FromRequest<P, B>,
120+
<Input as FromRequest<P, B>>::Rejection: std::fmt::Display,
120121
S: Service<Input>,
121122
S::Response: IntoResponse<P>,
122123
S::Error: IntoResponse<P>,
@@ -137,7 +138,13 @@ where
137138
.take()
138139
.expect("futures cannot be polled after completion")
139140
.oneshot(ok),
140-
Err(err) => return Poll::Ready(Ok(err.into_response())),
141+
Err(err) => {
142+
// The error may arise either from a `FromRequest` failure for any user-defined
143+
// handler's additional input parameters, or from a de-serialization failure
144+
// of an input parameter specific to the operation.
145+
tracing::trace!(error = %err, "parameter for the handler cannot be constructed");
146+
return Poll::Ready(Ok(err.into_response()));
147+
}
141148
}
142149
}
143150
InnerProj::Inner { call } => {
@@ -158,6 +165,7 @@ where
158165
impl<P, Input, B, S> Service<http::Request<B>> for Upgrade<P, Input, S>
159166
where
160167
Input: FromRequest<P, B>,
168+
<Input as FromRequest<P, B>>::Rejection: std::fmt::Display,
161169
S: Service<Input> + Clone,
162170
S::Response: IntoResponse<P>,
163171
S::Error: IntoResponse<P>,

rust-runtime/aws-smithy-http-server/src/protocol/aws_json/runtime_error.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,22 @@ use http::StatusCode;
1111

1212
use super::rejection::{RequestRejection, ResponseRejection};
1313

14-
#[derive(Debug)]
14+
#[derive(Debug, thiserror::Error)]
1515
pub enum RuntimeError {
16+
/// See: [`crate::protocol::rest_json_1::runtime_error::RuntimeError::Serialization`]
17+
#[error("request failed to deserialize or response failed to serialize: {0}")]
1618
Serialization(crate::Error),
19+
/// See: [`crate::protocol::rest_json_1::runtime_error::RuntimeError::InternalFailure`]
20+
#[error("internal failure: {0}")]
1721
InternalFailure(crate::Error),
22+
/// See: [`crate::protocol::rest_json_1::runtime_error::RuntimeError::NotAcceptable`]
23+
#[error("not acceptable request: request contains an `Accept` header with a MIME type, and the server cannot return a response body adhering to that MIME type")]
1824
NotAcceptable,
25+
/// See: [`crate::protocol::rest_json_1::runtime_error::RuntimeError::UnsupportedMediaType`]
26+
#[error("unsupported media type: request does not contain the expected `Content-Type` header value")]
1927
UnsupportedMediaType,
28+
/// See: [`crate::protocol::rest_json_1::runtime_error::RuntimeError::Validation`]
29+
#[error("validation failure: operation input contains data that does not adhere to the modeled constraints: {0}")]
2030
Validation(String),
2131
}
2232

rust-runtime/aws-smithy-http-server/src/protocol/rest_json_1/runtime_error.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,23 +38,28 @@ use crate::runtime_error::InternalFailureException;
3838
use crate::runtime_error::INVALID_HTTP_RESPONSE_FOR_RUNTIME_ERROR_PANIC_MESSAGE;
3939
use http::StatusCode;
4040

41-
#[derive(Debug)]
41+
#[derive(Debug, thiserror::Error)]
4242
pub enum RuntimeError {
4343
/// Request failed to deserialize or response failed to serialize.
44+
#[error("request failed to deserialize or response failed to serialize: {0}")]
4445
Serialization(crate::Error),
4546
/// As of writing, this variant can only occur upon failure to extract an
4647
/// [`crate::extension::Extension`] from the request.
48+
#[error("internal failure: {0}")]
4749
InternalFailure(crate::Error),
48-
/// Request contained an `Accept` header with a MIME type, and the server cannot return a response
50+
/// Request contains an `Accept` header with a MIME type, and the server cannot return a response
4951
/// body adhering to that MIME type.
50-
/// This is returned directly (i.e. without going through a [`RequestRejection`] first) in the
51-
/// generated SDK when calling [`crate::protocol::accept_header_classifier`] in
52-
/// `from_request`.
52+
// This is returned directly (i.e. without going through a [`RequestRejection`] first) in the
53+
// generated SDK when calling [`crate::protocol::accept_header_classifier`] in
54+
// `from_request`.
55+
#[error("not acceptable request: request contains an `Accept` header with a MIME type, and the server cannot return a response body adhering to that MIME type")]
5356
NotAcceptable,
5457
/// The request does not contain the expected `Content-Type` header value.
58+
#[error("unsupported media type: request does not contain the expected `Content-Type` header value")]
5559
UnsupportedMediaType,
5660
/// Operation input contains data that does not adhere to the modeled [constraint traits].
5761
/// [constraint traits]: <https://awslabs.github.io/smithy/2.0/spec/constraint-traits.html>
62+
#[error("validation failure: operation input contains data that does not adhere to the modeled constraints: {0}")]
5863
Validation(String),
5964
}
6065

rust-runtime/aws-smithy-http-server/src/protocol/rest_xml/runtime_error.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,22 @@ use http::StatusCode;
1111

1212
use super::rejection::{RequestRejection, ResponseRejection};
1313

14-
#[derive(Debug)]
14+
#[derive(Debug, thiserror::Error)]
1515
pub enum RuntimeError {
16+
/// See: [`crate::protocol::rest_json_1::runtime_error::RuntimeError::Serialization`]
17+
#[error("request failed to deserialize or response failed to serialize: {0}")]
1618
Serialization(crate::Error),
19+
/// See: [`crate::protocol::rest_json_1::runtime_error::RuntimeError::InternalFailure`]
20+
#[error("internal failure: {0}")]
1721
InternalFailure(crate::Error),
22+
/// See: [`crate::protocol::rest_json_1::runtime_error::RuntimeError::NotAcceptable`]
23+
#[error("not acceptable request: request contains an `Accept` header with a MIME type, and the server cannot return a response body adhering to that MIME type")]
1824
NotAcceptable,
25+
/// See: [`crate::protocol::rest_json_1::runtime_error::RuntimeError::UnsupportedMediaType`]
26+
#[error("unsupported media type: request does not contain the expected `Content-Type` header value")]
1927
UnsupportedMediaType,
28+
/// See: [`crate::protocol::rest_json_1::runtime_error::RuntimeError::Validation`]
29+
#[error("validation failure: operation input contains data that does not adhere to the modeled constraints: {0}")]
2030
Validation(String),
2131
}
2232

rust-runtime/aws-smithy-http-server/src/rejection.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,16 @@ pub mod any_rejections {
2525
//! [`IntoResponse`].
2626
2727
use super::IntoResponse;
28+
use thiserror::Error;
2829

2930
macro_rules! any_rejection {
3031
($name:ident, $($var:ident),+) => (
32+
#[derive(Debug, Error)]
3133
pub enum $name<$($var),*> {
32-
$($var ($var),)*
34+
$(
35+
#[error("{0}")]
36+
$var($var),
37+
)*
3338
}
3439

3540
impl<P, $($var,)*> IntoResponse<P> for $name<$($var),*>

rust-runtime/aws-smithy-http-server/src/request/mod.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,15 +163,34 @@ impl<P, B, T1, T2> FromRequest<P, B> for (T1, T2)
163163
where
164164
T1: FromRequest<P, B>,
165165
T2: FromParts<P>,
166+
T1::Rejection: std::fmt::Display,
167+
T2::Rejection: std::fmt::Display,
166168
{
167169
type Rejection = any_rejections::Two<T1::Rejection, T2::Rejection>;
168170
type Future = TryJoin<MapErr<T1::Future, fn(T1::Rejection) -> Self::Rejection>, Ready<Result<T2, Self::Rejection>>>;
169171

170172
fn from_request(request: Request<B>) -> Self::Future {
171173
let (mut parts, body) = request.into_parts();
172-
let t2_result = T2::from_parts(&mut parts).map_err(any_rejections::Two::B);
174+
let t2_result: Result<T2, any_rejections::Two<T1::Rejection, T2::Rejection>> = T2::from_parts(&mut parts)
175+
.map_err(|e| {
176+
// The error is likely caused by a failure to construct a parameter from the
177+
// `Request` required by the user handler. This typically occurs when the
178+
// user handler expects a specific type, such as `Extension<State>`, but
179+
// either the `ExtensionLayer` has not been added, or it adds a different
180+
// type to the extension bag, such as `Extension<Arc<State>>`.
181+
tracing::error!(
182+
error = %e,
183+
"additional parameter for the handler function could not be constructed");
184+
any_rejections::Two::B(e)
185+
});
173186
try_join(
174-
T1::from_request(Request::from_parts(parts, body)).map_err(any_rejections::Two::A),
187+
T1::from_request(Request::from_parts(parts, body)).map_err(|e| {
188+
// `T1`, the first parameter of a handler function, represents the input parameter
189+
// defined in the Smithy model. An error at this stage suggests that `T1` could not
190+
// be constructed from the `Request`.
191+
tracing::debug!(error = %e, "failed to deserialize request into operation's input");
192+
any_rejections::Two::A(e)
193+
}),
175194
ready(t2_result),
176195
)
177196
}

0 commit comments

Comments
 (0)