fp_bindgen_support/http/
mod.rs

1/*!
2HTTP support for fp-bindgen.
3
4Enables making HTTP requests from within the runtime.
5(De)serializes various relevant data models like Methods, Headers, etc.
6 */
7
8use std::{collections::HashMap, str::FromStr};
9
10use http::{
11    header::HeaderName,
12    uri::{Scheme, Uri},
13    Method,
14};
15use serde::{
16    de::{self},
17    ser::SerializeMap,
18    Deserialize, Deserializer, Serializer,
19};
20use serde_bytes::ByteBuf;
21
22pub fn serialize_http_method<S>(method: &Method, serializer: S) -> Result<S::Ok, S::Error>
23where
24    S: Serializer,
25{
26    serializer.serialize_str(method.as_str())
27}
28
29pub fn deserialize_http_method<'de, D>(deserializer: D) -> Result<Method, D::Error>
30where
31    D: Deserializer<'de>,
32{
33    MethodDef::deserialize(deserializer).map(Method::from)
34}
35
36#[non_exhaustive]
37#[derive(Deserialize)]
38#[serde(rename_all = "UPPERCASE")]
39enum MethodDef {
40    Get,
41    Post,
42    Put,
43    Delete,
44    Head,
45    Options,
46    Connect,
47    Patch,
48    Trace,
49}
50
51impl From<MethodDef> for Method {
52    fn from(def: MethodDef) -> Method {
53        match def {
54            MethodDef::Get => Method::GET,
55            MethodDef::Post => Method::POST,
56            MethodDef::Put => Method::PUT,
57            MethodDef::Delete => Method::DELETE,
58            MethodDef::Head => Method::HEAD,
59            MethodDef::Options => Method::OPTIONS,
60            MethodDef::Connect => Method::CONNECT,
61            MethodDef::Patch => Method::PATCH,
62            MethodDef::Trace => Method::TRACE,
63        }
64    }
65}
66
67pub fn serialize_uri<S>(uri: &Uri, serializer: S) -> Result<S::Ok, S::Error>
68where
69    S: Serializer,
70{
71    serializer.serialize_str(&uri.to_string())
72}
73
74pub fn deserialize_uri<'de, D>(deserializer: D) -> Result<Uri, D::Error>
75where
76    D: Deserializer<'de>,
77{
78    String::deserialize(deserializer).and_then(|s| {
79        s.parse().map_err(|_| {
80            de::Error::invalid_value(
81                de::Unexpected::Other("invalid url"),
82                &"a string that contains a well-formatted url",
83            )
84        })
85    })
86}
87
88pub fn serialize_uri_scheme<S>(scheme: &Scheme, serializer: S) -> Result<S::Ok, S::Error>
89where
90    S: Serializer,
91{
92    serializer.serialize_str(scheme.as_str())
93}
94
95pub fn deserialize_uri_scheme<'de, D>(deserializer: D) -> Result<Scheme, D::Error>
96where
97    D: Deserializer<'de>,
98{
99    SchemeDef::deserialize(deserializer).map(Scheme::from)
100}
101
102pub fn serialize_header_map<S>(headers: &http::HeaderMap, serializer: S) -> Result<S::Ok, S::Error>
103where
104    S: Serializer,
105{
106    let mut map = serializer.serialize_map(None)?;
107
108    for (key, value) in headers.clone().iter() {
109        let val = serde_bytes::ByteBuf::from(value.as_bytes());
110        map.serialize_entry(key.as_str(), &val)?;
111    }
112    map.end()
113}
114
115pub fn deserialize_header_map<'de, D>(deserializer: D) -> Result<http::HeaderMap, D::Error>
116where
117    D: Deserializer<'de>,
118{
119    let mut header_map = http::HeaderMap::new();
120    let hashmap: HashMap<String, ByteBuf> = HashMap::deserialize(deserializer)?;
121    for (key, value) in hashmap {
122        let header_name = HeaderName::from_str(&key)
123            .map_err(|e| serde::de::Error::custom(format!("Unable to parse header {key}: {e}")))?;
124        header_map.insert(header_name, http::HeaderValue::from_bytes(&value).unwrap());
125    }
126    Ok(header_map)
127}
128
129#[non_exhaustive]
130#[derive(Deserialize)]
131#[serde(rename_all = "lowercase")]
132enum SchemeDef {
133    Http,
134    Https,
135}
136
137impl From<SchemeDef> for Scheme {
138    fn from(def: SchemeDef) -> Scheme {
139        match def {
140            SchemeDef::Http => Scheme::HTTP,
141            SchemeDef::Https => Scheme::HTTPS,
142        }
143    }
144}