1use std::str::FromStr;
2
3use http::Uri;
4use http::uri::{InvalidUri, PathAndQuery, Scheme};
5use percent_encoding::{AsciiSet, utf8_percent_encode};
6
7use crate::{WELL_KNOWN_PATH, WebFingerRequest, WebFingerResponse};
8
9const QUERY: AsciiSet = percent_encoding::CONTROLS
23 .add(b' ')
25 .add(b'"')
26 .add(b'#')
27 .add(b'<')
28 .add(b'>')
29 .add(b'[')
30 .add(b'\\')
31 .add(b']')
32 .add(b'^')
33 .add(b'`')
34 .add(b'{')
35 .add(b'|')
36 .add(b'}')
37 .add(b'=')
39 .add(b'&');
40
41impl TryFrom<&WebFingerRequest> for PathAndQuery {
42 type Error = InvalidUri;
43
44 fn try_from(query: &WebFingerRequest) -> Result<PathAndQuery, InvalidUri> {
45 let resource = query.resource.to_string();
46 let resource = utf8_percent_encode(&resource, &QUERY).to_string();
47 let mut path = WELL_KNOWN_PATH.to_owned();
48 path.push_str("?resource=");
49 path.push_str(&resource);
50 for rel in &query.rels {
51 let rel = utf8_percent_encode(rel, &QUERY).to_string();
52 path.push_str("&rel=");
53 path.push_str(&rel);
54 }
55 PathAndQuery::from_str(&path)
56 }
57}
58
59impl TryFrom<&WebFingerRequest> for Uri {
60 type Error = http::Error;
61
62 fn try_from(query: &WebFingerRequest) -> Result<Uri, http::Error> {
63 let path_and_query = PathAndQuery::try_from(query)?;
64
65 const SCHEME: Scheme = Scheme::HTTPS;
69
70 Uri::builder()
71 .scheme(SCHEME)
72 .authority(query.host.clone())
73 .path_and_query(path_and_query)
74 .build()
75 }
76}
77
78impl TryFrom<&WebFingerResponse> for http::Response<()> {
79 type Error = http::Error;
80 fn try_from(_: &WebFingerResponse) -> Result<http::Response<()>, http::Error> {
81 http::Response::builder()
82 .header("Content-Type", "application/jrd+json")
83 .body(())
84 }
85}