47
47
//!
48
48
//! Consult `crate::proto::$protocolName::rejection` for rejection types for other protocols.
49
49
50
- use std:: num:: TryFromIntError ;
51
-
52
- use strum_macros:: Display ;
53
-
54
50
use crate :: rejection:: MissingContentTypeReason ;
51
+ use std:: num:: TryFromIntError ;
52
+ use thiserror:: Error ;
55
53
56
54
/// Errors that can occur when serializing the operation output provided by the service implementer
57
55
/// into an HTTP response.
58
- #[ derive( Debug , Display ) ]
56
+ #[ derive( Debug , Error ) ]
59
57
pub enum ResponseRejection {
60
58
/// Used when the service implementer provides an integer outside the 100-999 range for a
61
59
/// member targeted by `httpResponseCode`.
62
60
/// See <https://github.com/awslabs/smithy/issues/1116>.
61
+ #[ error( "invalid bound HTTP status code; status codes must be inside the 100-999 range: {0}" ) ]
63
62
InvalidHttpStatusCode ( TryFromIntError ) ,
64
63
65
- /// Used when an invalid HTTP header value (a value that cannot be parsed as an
66
- /// `[http::header::HeaderValue]`) is provided for a shape member bound to an HTTP header with
64
+ /// Used when an invalid HTTP header name (a value that cannot be parsed as an
65
+ /// [`http::header::HeaderName`]) or HTTP header value (a value that cannot be parsed as an
66
+ /// [`http::header::HeaderValue`]) is provided for a shape member bound to an HTTP header with
67
67
/// `httpHeader` or `httpPrefixHeaders`.
68
68
/// Used when failing to serialize an `httpPayload`-bound struct into an HTTP response body.
69
- Build ( crate :: Error ) ,
70
-
71
- /// Used when failing to serialize a struct into a `String` for the HTTP response body (for
72
- /// example, converting a struct into a JSON-encoded `String`).
73
- Serialization ( crate :: Error ) ,
69
+ #[ error( "error building HTTP response: {0}" ) ]
70
+ Build ( #[ from] aws_smithy_http:: operation:: error:: BuildError ) ,
71
+
72
+ /// Used when failing to serialize a struct into a `String` for the JSON-encoded HTTP response
73
+ /// body.
74
+ /// Fun fact: as of writing, this can only happen when date formatting
75
+ /// (`aws_smithy_types::date_time::DateTime:fmt`) fails, which can only happen if the
76
+ /// supplied timestamp is outside of the valid range when formatting using RFC-3339, i.e. a
77
+ /// date outside the `0001-01-01T00:00:00.000Z`-`9999-12-31T23:59:59.999Z` range is supplied.
78
+ #[ error( "error serializing JSON-encoded body: {0}" ) ]
79
+ Serialization ( #[ from] aws_smithy_http:: operation:: error:: SerializationError ) ,
74
80
75
81
/// Used when consuming an [`http::response::Builder`] into the constructed [`http::Response`]
76
82
/// when calling [`http::response::Builder::body`].
77
83
/// This error can happen if an invalid HTTP header value (a value that cannot be parsed as an
78
84
/// `[http::header::HeaderValue]`) is used for the protocol-specific response `Content-Type`
79
85
/// header, or for additional protocol-specific headers (like `X-Amzn-Errortype` to signal
80
86
/// errors in RestJson1).
81
- Http ( crate :: Error ) ,
87
+ #[ error( "error building HTTP response: {0}" ) ]
88
+ HttpBuild ( #[ from] http:: Error ) ,
82
89
}
83
90
84
- impl std:: error:: Error for ResponseRejection { }
85
-
86
- convert_to_response_rejection ! ( aws_smithy_http:: operation:: error:: BuildError , Build ) ;
87
- convert_to_response_rejection ! ( aws_smithy_http:: operation:: error:: SerializationError , Serialization ) ;
88
- convert_to_response_rejection ! ( http:: Error , Http ) ;
89
-
90
91
/// Errors that can occur when deserializing an HTTP request into an _operation input_, the input
91
92
/// that is passed as the first argument to operation handlers.
92
93
///
@@ -98,59 +99,65 @@ convert_to_response_rejection!(http::Error, Http);
98
99
/// deliberate design choice to keep code generation simple. After all, this type is an inner
99
100
/// detail of the framework the service implementer does not interact with.
100
101
///
101
- /// If a variant takes in a value, it represents the underlying cause of the error. This inner
102
- /// value should be of the type-erased boxed error type `[crate::Error]`. In practice, some of the
103
- /// variants that take in a value are only instantiated with errors of a single type in the
104
- /// generated code. For example, `UriPatternMismatch` is only instantiated with an error coming
105
- /// from a `nom` parser, `nom::Err<nom::error::Error<&str>>`. This is reflected in the converters
106
- /// below that convert from one of these very specific error types into one of the variants. For
107
- /// example, the `RequestRejection` implements `From<hyper::Error>` to construct the `HttpBody`
108
- /// variant. This is a deliberate design choice to make the code simpler and less prone to changes.
102
+ /// If a variant takes in a value, it represents the underlying cause of the error.
109
103
///
110
104
/// The variants are _roughly_ sorted in the order in which the HTTP request is processed.
111
- #[ derive( Debug , Display ) ]
105
+ #[ derive( Debug , Error ) ]
112
106
pub enum RequestRejection {
113
107
/// Used when failing to convert non-streaming requests into a byte slab with
114
108
/// `hyper::body::to_bytes`.
115
- HttpBody ( crate :: Error ) ,
109
+ #[ error( "error converting non-streaming body to bytes: {0}" ) ]
110
+ BufferHttpBodyBytes ( crate :: Error ) ,
116
111
117
112
/// Used when checking the `Content-Type` header.
118
- MissingContentType ( MissingContentTypeReason ) ,
113
+ #[ error( "expected `Content-Type` header not found: {0}" ) ]
114
+ MissingContentType ( #[ from] MissingContentTypeReason ) ,
119
115
120
116
/// Used when failing to deserialize the HTTP body's bytes into a JSON document conforming to
121
117
/// the modeled input it should represent.
122
- JsonDeserialize ( crate :: Error ) ,
118
+ #[ error( "error deserializing request HTTP body as JSON: {0}" ) ]
119
+ JsonDeserialize ( #[ from] aws_smithy_json:: deserialize:: error:: DeserializeError ) ,
123
120
124
121
/// Used when failing to parse HTTP headers that are bound to input members with the `httpHeader`
125
122
/// or the `httpPrefixHeaders` traits.
126
- HeaderParse ( crate :: Error ) ,
123
+ #[ error( "error binding request HTTP headers: {0}" ) ]
124
+ HeaderParse ( #[ from] aws_smithy_http:: header:: ParseError ) ,
127
125
126
+ // In theory, the next two errors should never happen because the router should have already
127
+ // rejected the request.
128
128
/// Used when the URI pattern has a literal after the greedy label, and it is not found in the
129
129
/// request's URL.
130
+ #[ error( "request URI does not match pattern because of literal suffix after greedy label was not found" ) ]
130
131
UriPatternGreedyLabelPostfixNotFound ,
131
132
/// Used when the `nom` parser's input does not match the URI pattern.
133
+ #[ error( "request URI does not match `@http` URI pattern: {0}" ) ]
132
134
UriPatternMismatch ( crate :: Error ) ,
133
135
134
136
/// Used when percent-decoding URL query string.
135
137
/// Used when percent-decoding URI path label.
136
- InvalidUtf8 ( crate :: Error ) ,
138
+ /// This is caused when calling
139
+ /// [`percent_encoding::percent_decode_str`](https://docs.rs/percent-encoding/latest/percent_encoding/fn.percent_decode_str.html).
140
+ /// This can happen when the percent-encoded data decodes to bytes that are
141
+ /// not a well-formed UTF-8 string.
142
+ #[ error( "request URI cannot be percent decoded into valid UTF-8" ) ]
143
+ PercentEncodedUriNotValidUtf8 ( #[ from] core:: str:: Utf8Error ) ,
137
144
138
145
/// Used when failing to deserialize strings from a URL query string and from URI path labels
139
146
/// into an [`aws_smithy_types::DateTime`].
140
- DateTimeParse ( crate :: Error ) ,
147
+ #[ error( "error parsing timestamp from request URI: {0}" ) ]
148
+ DateTimeParse ( #[ from] aws_smithy_types:: date_time:: DateTimeParseError ) ,
141
149
142
150
/// Used when failing to deserialize strings from a URL query string and from URI path labels
143
151
/// into "primitive" types.
144
- PrimitiveParse ( crate :: Error ) ,
152
+ #[ error( "error parsing primitive type from request URI: {0}" ) ]
153
+ PrimitiveParse ( #[ from] aws_smithy_types:: primitive:: PrimitiveParseError ) ,
145
154
146
155
/// Used when consuming the input struct builder, and constraint violations occur.
147
- // Unlike the rejections above, this does not take in `crate::Error`, since it is constructed
148
- // directly in the code-generated SDK instead of in this crate.
156
+ // This rejection is constructed directly in the code-generated SDK instead of in this crate.
157
+ # [ error ( "request does not adhere to modeled constraints: {0}" ) ]
149
158
ConstraintViolation ( String ) ,
150
159
}
151
160
152
- impl std:: error:: Error for RequestRejection { }
153
-
154
161
// Consider a conversion between `T` and `U` followed by a bubbling up of the conversion error
155
162
// through `Result<_, RequestRejection>`. This [`From`] implementation accomodates the special case
156
163
// where `T` and `U` are equal, in such cases `T`/`U` a enjoy `TryFrom<T>` with
@@ -170,43 +177,24 @@ impl From<std::convert::Infallible> for RequestRejection {
170
177
}
171
178
}
172
179
173
- impl From < MissingContentTypeReason > for RequestRejection {
174
- fn from ( e : MissingContentTypeReason ) -> Self {
175
- Self :: MissingContentType ( e)
176
- }
177
- }
178
-
179
180
// These converters are solely to make code-generation simpler. They convert from a specific error
180
181
// type (from a runtime/third-party crate or the standard library) into a variant of the
181
182
// [`crate::rejection::RequestRejection`] enum holding the type-erased boxed [`crate::Error`]
182
183
// type. Generated functions that use [crate::rejection::RequestRejection] can thus use `?` to
183
184
// bubble up instead of having to sprinkle things like [`Result::map_err`] everywhere.
184
185
185
- convert_to_request_rejection ! ( aws_smithy_json:: deserialize:: error:: DeserializeError , JsonDeserialize ) ;
186
- convert_to_request_rejection ! ( aws_smithy_http:: header:: ParseError , HeaderParse ) ;
187
- convert_to_request_rejection ! ( aws_smithy_types:: date_time:: DateTimeParseError , DateTimeParse ) ;
188
- convert_to_request_rejection ! ( aws_smithy_types:: primitive:: PrimitiveParseError , PrimitiveParse ) ;
189
- convert_to_request_rejection ! ( serde_urlencoded:: de:: Error , InvalidUtf8 ) ;
190
-
191
186
impl From < nom:: Err < nom:: error:: Error < & str > > > for RequestRejection {
192
187
fn from ( err : nom:: Err < nom:: error:: Error < & str > > ) -> Self {
193
188
Self :: UriPatternMismatch ( crate :: Error :: new ( err. to_owned ( ) ) )
194
189
}
195
190
}
196
191
197
- // Used when calling
198
- // [`percent_encoding::percent_decode_str`](https://docs.rs/percent-encoding/latest/percent_encoding/fn.percent_decode_str.html)
199
- // and bubbling up.
200
- // This can happen when the percent-encoded data in e.g. a query string decodes to bytes that are
201
- // not a well-formed UTF-8 string.
202
- convert_to_request_rejection ! ( std:: str :: Utf8Error , InvalidUtf8 ) ;
203
-
204
192
// `[crate::body::Body]` is `[hyper::Body]`, whose associated `Error` type is `[hyper::Error]`. We
205
193
// need this converter for when we convert the body into bytes in the framework, since protocol
206
194
// tests use `[crate::body::Body]` as their body type when constructing requests (and almost
207
195
// everyone will run a Hyper-based server in their services).
208
- convert_to_request_rejection ! ( hyper:: Error , HttpBody ) ;
196
+ convert_to_request_rejection ! ( hyper:: Error , BufferHttpBodyBytes ) ;
209
197
210
198
// Useful in general, but it also required in order to accept Lambda HTTP requests using
211
199
// `Router<lambda_http::Body>` since `lambda_http::Error` is a type alias for `Box<dyn Error + ..>`.
212
- convert_to_request_rejection ! ( Box <dyn std:: error:: Error + Send + Sync + ' static >, HttpBody ) ;
200
+ convert_to_request_rejection ! ( Box <dyn std:: error:: Error + Send + Sync + ' static >, BufferHttpBodyBytes ) ;
0 commit comments