Skip to main content

tuwunel_core/error/
response.rs

1use bytes::BytesMut;
2use http::StatusCode;
3use http_body_util::Full;
4use ruma::api::{
5	OutgoingResponse,
6	client::uiaa::UiaaResponse,
7	error::{ErrorBody, ErrorKind},
8};
9
10use super::Error;
11use crate::error;
12
13impl axum::response::IntoResponse for Error {
14	fn into_response(self) -> axum::response::Response {
15		let response: UiaaResponse = self.into();
16		response
17			.try_into_http_response::<BytesMut>()
18			.inspect_err(|e| error!("error response error: {e}"))
19			.map_or_else(
20				|_| StatusCode::INTERNAL_SERVER_ERROR.into_response(),
21				|r| {
22					r.map(BytesMut::freeze)
23						.map(Full::new)
24						.into_response()
25				},
26			)
27	}
28}
29
30impl From<Error> for UiaaResponse {
31	#[inline]
32	fn from(error: Error) -> Self {
33		if let Error::Uiaa(uiaainfo) = error {
34			return Self::AuthResponse(uiaainfo);
35		}
36
37		let body = ErrorBody::Standard(ruma::api::error::StandardErrorBody {
38			kind: error.kind(),
39			message: error.message(),
40		});
41
42		Self::MatrixError(ruma::api::error::Error::new(error.status_code(), body))
43	}
44}
45
46pub(super) fn status_code(kind: &ErrorKind, hint: StatusCode) -> StatusCode {
47	if hint == StatusCode::BAD_REQUEST {
48		bad_request_code(kind)
49	} else {
50		hint
51	}
52}
53
54pub(super) fn bad_request_code(kind: &ErrorKind) -> StatusCode {
55	use ErrorKind::*;
56
57	match kind {
58		// 504
59		| NotYetUploaded | ConnectionTimeout => StatusCode::GATEWAY_TIMEOUT,
60
61		// 502
62		| BadStatus(..) | ConnectionFailed => StatusCode::BAD_GATEWAY,
63
64		// 429
65		| LimitExceeded { .. } => StatusCode::TOO_MANY_REQUESTS,
66
67		// 413
68		| TooLarge => StatusCode::PAYLOAD_TOO_LARGE,
69
70		// 409
71		| CannotOverwriteMedia => StatusCode::CONFLICT,
72
73		// 404
74		| NotFound | NotImplemented | FeatureDisabled | Unrecognized => StatusCode::NOT_FOUND,
75
76		// 403
77		| GuestAccessForbidden
78		| ThreepidAuthFailed
79		| UserDeactivated
80		| ThreepidDenied
81		| InviteBlocked
82		| WrongRoomKeysVersion { .. }
83		| Forbidden => StatusCode::FORBIDDEN,
84
85		// 401
86		| UnknownToken { .. } | MissingToken | Unauthorized => StatusCode::UNAUTHORIZED,
87
88		// 400
89		| _ => StatusCode::BAD_REQUEST,
90	}
91}
92
93pub(super) fn ruma_error_message(error: &ruma::api::error::Error) -> String {
94	if let ErrorBody::Standard(ruma::api::error::StandardErrorBody { message, .. }) = &error.body
95	{
96		return message.clone();
97	}
98
99	format!("{error}")
100}
101
102pub(super) fn ruma_error_kind(e: &ruma::api::error::Error) -> &ErrorKind {
103	e.error_kind().unwrap_or(&ErrorKind::Unknown)
104}
105
106pub(super) fn io_error_code(kind: std::io::ErrorKind) -> StatusCode {
107	use std::io::ErrorKind;
108
109	match kind {
110		| ErrorKind::InvalidInput => StatusCode::BAD_REQUEST,
111		| ErrorKind::PermissionDenied => StatusCode::FORBIDDEN,
112		| ErrorKind::NotFound => StatusCode::NOT_FOUND,
113		| ErrorKind::TimedOut => StatusCode::GATEWAY_TIMEOUT,
114		| ErrorKind::FileTooLarge => StatusCode::PAYLOAD_TOO_LARGE,
115		| ErrorKind::StorageFull => StatusCode::INSUFFICIENT_STORAGE,
116		| ErrorKind::Interrupted => StatusCode::SERVICE_UNAVAILABLE,
117		| _ => StatusCode::INTERNAL_SERVER_ERROR,
118	}
119}