Skip to main content

tuwunel_service/resolver/
well_known.rs

1use tuwunel_core::{Result, debug, debug_error, debug_info, debug_warn, implement, trace};
2
3use super::DestString;
4use crate::client::read_response_capped;
5
6#[implement(super::Service)]
7#[tracing::instrument(
8	name = "well-known",
9	level = "debug",
10	ret(level = "debug"),
11	skip(self)
12)]
13pub(super) async fn request_well_known(&self, dest: &str) -> Result<Option<DestString>> {
14	trace!("Requesting well known for {dest}");
15	let response = self
16		.services
17		.client
18		.well_known
19		.get(format!("https://{dest}/.well-known/matrix/server"))
20		.send()
21		.await;
22
23	trace!("response: {response:?}");
24	if let Err(e) = &response {
25		debug!("error: {e:?}");
26		return Ok(None);
27	}
28
29	let response = response?;
30	if !response.status().is_success() {
31		debug!("response not 2XX");
32		return Ok(None);
33	}
34
35	let Ok(body) = read_response_capped(response, 12288).await else {
36		debug_warn!("response unreadable or exceeds size limit");
37		return Ok(None);
38	};
39
40	let text = String::from_utf8_lossy(&body);
41	trace!("response text: {text:?}");
42
43	let body: serde_json::Value = serde_json::from_str(&text).unwrap_or_default();
44
45	let m_server = body
46		.get("m.server")
47		.unwrap_or(&serde_json::Value::Null)
48		.as_str()
49		.unwrap_or_default();
50
51	if ruma::identifiers_validation::server_name::validate(m_server).is_err() {
52		debug_error!("response content missing or invalid");
53		return Ok(None);
54	}
55
56	debug_info!("{dest:?} found at {m_server:?}");
57	Ok(Some(m_server.into()))
58}