ruma_client_api/uiaa/
get_uiaa_fallback_page.rs1pub mod v3 {
6 use ruma_common::{
11 api::{auth_scheme::NoAccessToken, request},
12 metadata,
13 };
14
15 use crate::uiaa::AuthType;
16
17 metadata! {
18 method: GET,
19 rate_limited: false,
20 authentication: NoAccessToken,
21 history: {
22 1.0 => "/_matrix/client/r0/auth/{auth_type}/fallback/web",
23 1.1 => "/_matrix/client/v3/auth/{auth_type}/fallback/web",
24 }
25 }
26
27 #[request]
29 pub struct Request {
30 #[ruma_api(path)]
32 pub auth_type: AuthType,
33
34 #[ruma_api(query)]
36 pub session: String,
37 }
38
39 impl Request {
40 pub fn new(auth_type: AuthType, session: String) -> Self {
42 Self { auth_type, session }
43 }
44 }
45
46 #[derive(Debug, Clone)]
48 #[allow(clippy::exhaustive_enums)]
49 pub enum Response {
50 Redirect(Redirect),
52
53 Html(HtmlPage),
55 }
56
57 #[derive(Debug, Clone)]
59 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
60 pub struct Redirect {
61 pub url: String,
63 }
64
65 #[derive(Debug, Clone)]
67 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
68 pub struct HtmlPage {
69 pub body: Vec<u8>,
71 }
72
73 impl Response {
74 pub fn html(body: Vec<u8>) -> Self {
76 Self::Html(HtmlPage { body })
77 }
78
79 pub fn redirect(url: String) -> Self {
81 Self::Redirect(Redirect { url })
82 }
83 }
84
85 #[doc(hidden)]
86 #[allow(clippy::exhaustive_enums)]
87 pub enum ResponseBody {
88 Redirect,
89 Html(HtmlPage),
90 }
91
92 #[cfg(feature = "server")]
93 impl ruma_common::api::OutgoingBody for ResponseBody {
94 type Error = ruma_common::api::error::IntoHttpError;
95
96 fn try_into_buf<T: Default + bytes::BufMut + AsRef<[u8]>>(self) -> Result<T, Self::Error> {
97 let body = match self {
98 Self::Redirect => Vec::new(),
99 Self::Html(HtmlPage { body }) => body,
100 };
101
102 Ok(ruma_common::api::BytesBody(body).try_into_buf()?)
103 }
104 }
105
106 #[cfg(feature = "server")]
107 impl ruma_common::api::OutgoingResponse for Response {
108 type Body = ResponseBody;
109
110 fn try_into_http_response_inner(
111 self,
112 ) -> Result<http::Response<Self::Body>, ruma_common::api::error::IntoHttpError> {
113 match self {
114 Response::Redirect(Redirect { url }) => Ok(http::Response::builder()
115 .status(http::StatusCode::FOUND)
116 .header(http::header::LOCATION, url)
117 .body(ResponseBody::Redirect)?),
118 Response::Html(html) => Ok(http::Response::builder()
119 .status(http::StatusCode::OK)
120 .header(http::header::CONTENT_TYPE, "text/html; charset=utf-8")
121 .body(ResponseBody::Html(html))?),
122 }
123 }
124 }
125
126 #[cfg(feature = "client")]
127 impl ruma_common::api::IncomingResponse for Response {
128 type EndpointError = ruma_common::api::error::Error;
129
130 fn try_from_http_response_inner(
131 response: http::Response<&[u8]>,
132 ) -> Result<Self, ruma_common::api::error::DeserializationError> {
133 use ruma_common::api::error::HeaderDeserializationError;
134
135 if response.status() == http::StatusCode::FOUND {
136 let Some(location) = response.headers().get(http::header::LOCATION) else {
137 return Err(HeaderDeserializationError::MissingHeader(
138 http::header::LOCATION.to_string(),
139 )
140 .into());
141 };
142
143 let url = location.to_str()?;
144 return Ok(Self::Redirect(Redirect { url: url.to_owned() }));
145 }
146
147 let body = response.into_body().to_owned();
148 Ok(Self::Html(HtmlPage { body }))
149 }
150 }
151
152 #[cfg(all(test, feature = "client"))]
153 mod tests_client {
154 use assert_matches2::assert_let;
155 use http::header::{CONTENT_TYPE, LOCATION};
156 use ruma_common::api::IncomingResponseExt as _;
157
158 use super::Response;
159
160 #[test]
161 fn incoming_redirect() {
162 use super::Redirect;
163
164 let http_response = http::Response::builder()
165 .status(http::StatusCode::FOUND)
166 .header(LOCATION, "http://localhost/redirect")
167 .body(b"".as_slice())
168 .unwrap();
169
170 let response = Response::try_from_http_response(http_response).unwrap();
171 assert_let!(Response::Redirect(Redirect { url }) = response);
172 assert_eq!(url, "http://localhost/redirect");
173 }
174
175 #[test]
176 fn incoming_html() {
177 use super::HtmlPage;
178
179 let http_response = http::Response::builder()
180 .status(http::StatusCode::OK)
181 .header(CONTENT_TYPE, "text/html; charset=utf-8")
182 .body(b"<h1>My Page</h1>".as_slice())
183 .unwrap();
184
185 let response = Response::try_from_http_response(http_response).unwrap();
186 assert_let!(Response::Html(HtmlPage { body }) = response);
187 assert_eq!(body, b"<h1>My Page</h1>");
188 }
189 }
190
191 #[cfg(all(test, feature = "server"))]
192 mod tests_server {
193 use http::header::{CONTENT_TYPE, LOCATION};
194 use ruma_common::api::OutgoingResponseExt as _;
195
196 use super::Response;
197
198 #[test]
199 fn outgoing_redirect() {
200 let response = Response::redirect("http://localhost/redirect".to_owned());
201
202 let http_response = response.try_into_http_response::<Vec<u8>>().unwrap();
203
204 assert_eq!(http_response.status(), http::StatusCode::FOUND);
205 assert_eq!(
206 http_response.headers().get(LOCATION).unwrap().to_str().unwrap(),
207 "http://localhost/redirect"
208 );
209 assert!(http_response.into_body().is_empty());
210 }
211
212 #[test]
213 fn outgoing_html() {
214 let response = Response::html(b"<h1>My Page</h1>".to_vec());
215
216 let http_response = response.try_into_http_response::<Vec<u8>>().unwrap();
217
218 assert_eq!(http_response.status(), http::StatusCode::OK);
219 assert_eq!(
220 http_response.headers().get(CONTENT_TYPE).unwrap().to_str().unwrap(),
221 "text/html; charset=utf-8"
222 );
223 assert_eq!(http_response.into_body(), b"<h1>My Page</h1>");
224 }
225 }
226}