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 => StatusCode::GATEWAY_TIMEOUT,
60
61		// 429
62		| LimitExceeded { .. } => StatusCode::TOO_MANY_REQUESTS,
63
64		// 413
65		| TooLarge => StatusCode::PAYLOAD_TOO_LARGE,
66
67		// 409
68		| CannotOverwriteMedia => StatusCode::CONFLICT,
69
70		// 404
71		| NotFound | NotImplemented | FeatureDisabled | Unrecognized => StatusCode::NOT_FOUND,
72
73		// 403
74		| GuestAccessForbidden
75		| ThreepidAuthFailed
76		| UserDeactivated
77		| ThreepidDenied
78		| InviteBlocked
79		| WrongRoomKeysVersion { .. }
80		| Forbidden => StatusCode::FORBIDDEN,
81
82		// 401
83		| UnknownToken { .. } | MissingToken | Unauthorized => StatusCode::UNAUTHORIZED,
84
85		// 400
86		| _ => StatusCode::BAD_REQUEST,
87	}
88}
89
90pub(super) fn ruma_error_message(error: &ruma::api::error::Error) -> String {
91	if let ErrorBody::Standard(ruma::api::error::StandardErrorBody { message, .. }) = &error.body
92	{
93		return message.clone();
94	}
95
96	format!("{error}")
97}
98
99pub(super) fn ruma_error_kind(e: &ruma::api::error::Error) -> &ErrorKind {
100	e.error_kind().unwrap_or(&ErrorKind::Unknown)
101}
102
103pub(super) fn io_error_code(kind: std::io::ErrorKind) -> StatusCode {
104	use std::io::ErrorKind;
105
106	match kind {
107		| ErrorKind::InvalidInput => StatusCode::BAD_REQUEST,
108		| ErrorKind::PermissionDenied => StatusCode::FORBIDDEN,
109		| ErrorKind::NotFound => StatusCode::NOT_FOUND,
110		| ErrorKind::TimedOut => StatusCode::GATEWAY_TIMEOUT,
111		| ErrorKind::FileTooLarge => StatusCode::PAYLOAD_TOO_LARGE,
112		| ErrorKind::StorageFull => StatusCode::INSUFFICIENT_STORAGE,
113		| ErrorKind::Interrupted => StatusCode::SERVICE_UNAVAILABLE,
114		| _ => StatusCode::INTERNAL_SERVER_ERROR,
115	}
116}