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