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