tuwunel_service/appservice/
request.rs1use std::{fmt::Debug, mem};
2
3use bytes::BytesMut;
4use ruma::api::{
5 IncomingResponse, OutgoingRequest,
6 appservice::Registration,
7 auth_scheme::{AuthScheme, SendAccessToken},
8 path_builder::PathBuilder,
9};
10use tuwunel_core::{Err, Result, debug_error, err, implement, trace, utils, warn};
11
12#[implement(super::Service)]
17pub async fn send_request<T>(
18 &self,
19 registration: Registration,
20 request: T,
21) -> Result<Option<T::IncomingResponse>>
22where
23 T: OutgoingRequest + Debug + Send,
24 for<'a> T::Authentication: AuthScheme<Input<'a> = SendAccessToken<'a>>,
25 for<'a> T::PathBuilder: PathBuilder<Input<'a> = ()>,
26{
27 let client = &self.services.client.appservice;
28
29 let Some(dest) = registration.url else {
30 return Ok(None);
31 };
32
33 if dest == *"null" || dest.is_empty() {
34 return Ok(None);
35 }
36
37 trace!("Appservice URL \"{dest}\", Appservice ID: {}", registration.id);
38
39 let hs_token = registration.hs_token.as_str();
40 let mut http_request = request
41 .try_into_http_request::<BytesMut>(&dest, SendAccessToken::IfRequired(hs_token), ())
42 .map_err(|e| {
43 err!(BadServerResponse(
44 warn!(appservice = %registration.id, "Failed to find destination {dest}: {e:?}")
45 ))
46 })?
47 .map(BytesMut::freeze);
48
49 let mut parts = http_request.uri().clone().into_parts();
50 let old_path_and_query = parts
51 .path_and_query
52 .expect("valid request uri path and query")
53 .as_str()
54 .to_owned();
55
56 let symbol = if old_path_and_query.contains('?') { "&" } else { "?" };
57
58 parts.path_and_query = Some(
59 (old_path_and_query + symbol + "access_token=" + hs_token)
60 .parse()
61 .expect("valid path and query"),
62 );
63 *http_request.uri_mut() = parts
64 .try_into()
65 .expect("our manipulation is always valid");
66
67 let reqwest_request = reqwest::Request::try_from(http_request)?;
68
69 let mut response = client
70 .execute(reqwest_request)
71 .await
72 .map_err(|e| {
73 warn!(
74 "Could not send request to appservice \"{}\" at {dest}: {e:?}",
75 registration.id
76 );
77 e
78 })?;
79
80 let status = response.status();
82 let mut http_response_builder = http::Response::builder()
83 .status(status)
84 .version(response.version());
85
86 mem::swap(
87 response.headers_mut(),
88 http_response_builder
89 .headers_mut()
90 .expect("http::response::Builder is usable"),
91 );
92
93 let body = response.bytes().await?; if !status.is_success() {
96 debug_error!("Appservice response bytes: {:?}", utils::string_from_bytes(&body));
97 return Err!(BadServerResponse(warn!(
98 "Appservice \"{}\" returned unsuccessful HTTP response {status} at {dest}",
99 registration.id
100 )));
101 }
102
103 let response = T::IncomingResponse::try_from_http_response(
104 http_response_builder
105 .body(body)
106 .expect("reqwest body is valid http body"),
107 );
108
109 response.map(Some).map_err(|e| {
110 err!(BadServerResponse(warn!(
111 "Appservice \"{}\" returned invalid/malformed response bytes {dest}: {e}",
112 registration.id
113 )))
114 })
115}