-
Notifications
You must be signed in to change notification settings - Fork 197
/
Copy pathruntime_error.rs
115 lines (101 loc) · 4.86 KB
/
runtime_error.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
//! Runtime error type.
//!
//! This module contains [`RuntimeError`] type.
//!
//! As opposed to rejection types (see [`crate::rejection`]), which are an internal detail about
//! the framework, `RuntimeError` is surfaced to clients in HTTP responses: indeed, it implements
//! [`RuntimeError::into_response`]. Rejections can be "grouped" and converted into a
//! specific `RuntimeError` kind: for example, all request rejections due to serialization issues
//! can be conflated under the [`RuntimeErrorKind::Serialization`] enum variant.
//!
//! The HTTP response representation of the specific `RuntimeError` can be protocol-specific: for
//! example, the runtime error in the RestJson1 protocol sets the `X-Amzn-Errortype` header.
//!
//! Generated code works always works with [`crate::rejection`] types when deserializing requests
//! and serializing response. Just before a response needs to be sent, the generated code looks up
//! and converts into the corresponding `RuntimeError`, and then it uses the its
//! [`RuntimeError::into_response`] method to render and send a response.
use crate::{protocols::Protocol, response::Response};
#[derive(Debug)]
pub enum RuntimeErrorKind {
/// The requested operation does not exist.
UnknownOperation,
/// Request failed to deserialize or response failed to serialize.
Serialization(crate::Error),
/// As of writing, this variant can only occur upon failure to extract an
/// [`crate::extension::Extension`] from the request.
InternalFailure(crate::Error),
// UnsupportedMediaType,
NotAcceptable,
}
/// String representation of the runtime error type.
/// Used as the value of the `X-Amzn-Errortype` header in RestJson1.
/// Used as the value passed to construct an [`crate::extension::RuntimeErrorExtension`].
impl RuntimeErrorKind {
pub fn name(&self) -> &'static str {
match self {
RuntimeErrorKind::Serialization(_) => "SerializationException",
RuntimeErrorKind::InternalFailure(_) => "InternalFailureException",
RuntimeErrorKind::UnknownOperation => "UnknownOperationException",
RuntimeErrorKind::NotAcceptable => "NotAcceptableException",
}
}
}
#[derive(Debug)]
pub struct RuntimeError {
pub protocol: Protocol,
pub kind: RuntimeErrorKind,
}
impl RuntimeError {
pub fn into_response(self) -> Response {
let status_code = match self.kind {
RuntimeErrorKind::Serialization(_) => http::StatusCode::BAD_REQUEST,
RuntimeErrorKind::InternalFailure(_) => http::StatusCode::INTERNAL_SERVER_ERROR,
RuntimeErrorKind::UnknownOperation => http::StatusCode::NOT_FOUND,
RuntimeErrorKind::NotAcceptable => http::StatusCode::NOT_ACCEPTABLE,
};
let body = crate::body::to_boxed(match self.protocol {
Protocol::RestJson1 => "{}",
Protocol::RestXml => "",
// See https://awslabs.github.io/smithy/1.0/spec/aws/aws-json-1_0-protocol.html#empty-body-serialization
Protocol::AwsJson10 => "",
// See https://awslabs.github.io/smithy/1.0/spec/aws/aws-json-1_1-protocol.html#empty-body-serialization
Protocol::AwsJson11 => "",
});
let mut builder = http::Response::builder();
builder = builder.status(status_code);
match self.protocol {
Protocol::RestJson1 => {
builder = builder
.header("Content-Type", "application/json")
.header("X-Amzn-Errortype", self.kind.name());
}
Protocol::RestXml => builder = builder.header("Content-Type", "application/xml"),
Protocol::AwsJson10 => builder = builder.header("Content-Type", "application/x-amz-json-1.0"),
Protocol::AwsJson11 => builder = builder.header("Content-Type", "application/x-amz-json-1.1"),
}
builder = builder.extension(crate::extension::RuntimeErrorExtension::new(String::from(
self.kind.name(),
)));
builder.body(body).expect("invalid HTTP response for `RuntimeError`; please file a bug report under https://github.com/awslabs/smithy-rs/issues")
}
}
impl From<crate::rejection::RequestExtensionNotFoundRejection> for RuntimeErrorKind {
fn from(err: crate::rejection::RequestExtensionNotFoundRejection) -> Self {
RuntimeErrorKind::InternalFailure(crate::Error::new(err))
}
}
impl From<crate::rejection::ResponseRejection> for RuntimeErrorKind {
fn from(err: crate::rejection::ResponseRejection) -> Self {
RuntimeErrorKind::Serialization(crate::Error::new(err))
}
}
impl From<crate::rejection::RequestRejection> for RuntimeErrorKind {
fn from(err: crate::rejection::RequestRejection) -> Self {
RuntimeErrorKind::Serialization(crate::Error::new(err))
}
}