aws_smithy_runtime_api/http/
error.rs1use crate::box_error::BoxError;
9use http_1x::header::{InvalidHeaderName, InvalidHeaderValue};
10use http_1x::uri::InvalidUri;
11use std::error::Error;
12use std::fmt::{Debug, Display, Formatter};
13use std::str::Utf8Error;
14
15#[derive(Debug)]
16pub struct HttpError {
20 kind: Kind,
21 source: Option<BoxError>,
22}
23
24#[derive(Debug)]
25enum Kind {
26 #[cfg(feature = "http-02x")]
27 InvalidExtensions,
28 InvalidHeaderName,
29 InvalidHeaderValue,
30 InvalidMethod,
31 InvalidStatusCode,
32 InvalidUri,
33 InvalidUriParts,
34 MissingAuthority,
35 MissingScheme,
36 NonUtf8Header(NonUtf8Header),
37}
38
39#[derive(Debug)]
40pub(super) struct NonUtf8Header {
41 error: Utf8Error,
42 value: Vec<u8>,
43 name: Option<String>,
44}
45
46impl NonUtf8Header {
47 #[cfg(any(feature = "http-1x", feature = "http-02x"))]
48 pub(super) fn new(name: String, value: Vec<u8>, error: Utf8Error) -> Self {
49 Self {
50 error,
51 value,
52 name: Some(name),
53 }
54 }
55
56 pub(super) fn new_missing_name(value: Vec<u8>, error: Utf8Error) -> Self {
57 Self {
58 error,
59 value,
60 name: None,
61 }
62 }
63}
64
65impl HttpError {
66 #[cfg(feature = "http-02x")]
67 pub(super) fn invalid_extensions() -> Self {
68 Self {
69 kind: Kind::InvalidExtensions,
70 source: None,
71 }
72 }
73
74 pub(super) fn invalid_header_name(err: InvalidHeaderName) -> Self {
75 Self {
76 kind: Kind::InvalidHeaderName,
77 source: Some(Box::new(err)),
78 }
79 }
80
81 pub(super) fn invalid_method(err: http_1x::method::InvalidMethod) -> Self {
82 Self {
83 kind: Kind::InvalidMethod,
84 source: Some(Box::new(err)),
85 }
86 }
87
88 pub(super) fn invalid_header_value(err: InvalidHeaderValue) -> Self {
89 Self {
90 kind: Kind::InvalidHeaderValue,
91 source: Some(Box::new(err)),
92 }
93 }
94
95 pub(super) fn invalid_status_code() -> Self {
96 Self {
97 kind: Kind::InvalidStatusCode,
98 source: None,
99 }
100 }
101
102 pub(super) fn invalid_uri(err: InvalidUri) -> Self {
103 Self {
104 kind: Kind::InvalidUri,
105 source: Some(Box::new(err)),
106 }
107 }
108
109 #[cfg(feature = "http-02x")]
110 pub(super) fn invalid_uri_h0(err: http_02x::uri::InvalidUri) -> Self {
111 Self {
112 kind: Kind::InvalidUri,
113 source: Some(Box::new(err)),
114 }
115 }
116
117 pub(super) fn invalid_uri_parts(err: http_1x::Error) -> Self {
118 Self {
119 kind: Kind::InvalidUriParts,
120 source: Some(Box::new(err)),
121 }
122 }
123
124 pub(super) fn missing_authority() -> Self {
125 Self {
126 kind: Kind::MissingAuthority,
127 source: None,
128 }
129 }
130
131 pub(super) fn missing_scheme() -> Self {
132 Self {
133 kind: Kind::MissingScheme,
134 source: None,
135 }
136 }
137
138 pub(super) fn non_utf8_header(non_utf8_header: NonUtf8Header) -> Self {
139 Self {
140 kind: Kind::NonUtf8Header(non_utf8_header),
141 source: None,
142 }
143 }
144}
145
146impl Display for HttpError {
147 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
148 use Kind::*;
149 match &self.kind {
150 #[cfg(feature = "http-02x")]
151 InvalidExtensions => write!(f, "Extensions were provided during initialization. This prevents the request format from being converted."),
152 InvalidHeaderName => write!(f, "invalid header name"),
153 InvalidHeaderValue => write!(f, "invalid header value"),
154 InvalidMethod => write!(f, "invalid HTTP method"),
155 InvalidStatusCode => write!(f, "invalid HTTP status code"),
156 InvalidUri => write!(f, "endpoint is not a valid URI"),
157 InvalidUriParts => write!(f, "endpoint parts are not valid"),
158 MissingAuthority => write!(f, "endpoint must contain authority"),
159 MissingScheme => write!(f, "endpoint must contain scheme"),
160 NonUtf8Header(hv) => {
161 let key = hv.name.as_deref().unwrap_or("<unknown>");
163 let value = String::from_utf8_lossy(&hv.value);
164 let index = hv.error.valid_up_to();
165 write!(f, "header `{key}={value}` contains non-UTF8 octet at index {index}")
166 },
167 }
168 }
169}
170
171impl Error for HttpError {
172 fn source(&self) -> Option<&(dyn Error + 'static)> {
173 self.source.as_ref().map(|err| err.as_ref() as _)
174 }
175}