wasi_net/reqwest/
request_builder.rs

1#![allow(dead_code)]
2use http::StatusCode;
3use std::borrow::Cow;
4use std::collections::HashMap;
5use std::io::Write;
6
7use super::*;
8use crate::backend::utils::*;
9use crate::backend::Command as BackendCommand;
10use crate::backend::Response as BackendResponse;
11
12pub struct RequestBuilder {
13    pub(crate) method: http::Method,
14    pub(crate) url: url::Url,
15    pub(crate) client: Client,
16    pub(crate) headers: HashMap<String, String>,
17    pub(crate) request: Option<Body>,
18}
19
20impl RequestBuilder {
21    pub fn header<T>(mut self, header: http::header::HeaderName, value: T) -> Self
22    where
23        T: Into<Cow<'static, str>>,
24    {
25        self.headers
26            .insert(header.to_string(), value.into().to_string());
27        self
28    }
29
30    pub fn multipart(self, multipart: multipart::Form) -> RequestBuilder {
31        let mut builder = self.header(header::CONTENT_TYPE, "application/x-www-form-urlencoded");
32        builder.request = Some(Body::from(multipart.to_string()));
33        builder
34    }
35
36    pub fn bearer_auth<T>(self, token: T) -> RequestBuilder
37    where
38        T: std::fmt::Display,
39    {
40        let token = format!("{}", token);
41        if token.len() <= 0 {
42            return self;
43        }
44        let header_value = format!("Bearer {}", token);
45        self.header(header::AUTHORIZATION, header_value)
46    }
47
48    pub fn send(self) -> Result<Response, std::io::Error> {
49        let url = self.url.to_string();
50
51        let submit = BackendCommand::WebRequestVersion1 {
52            url,
53            method: self.method.to_string(),
54            headers: self
55                .headers
56                .iter()
57                .map(|(a, b)| (a.clone(), b.clone()))
58                .collect(),
59            body: self
60                .request
61                .iter()
62                .filter_map(|a| a.as_bytes())
63                .map(|a| a.to_vec())
64                .next(),
65        };
66        let mut submit = submit.serialize()?;
67        submit += "\n";
68
69        let mut file = std::fs::File::open("/dev/web")?;
70
71        let _ = file.write_all(submit.as_bytes());
72
73        let res = read_response(&mut file)?;
74        let (ok, redirected, status, status_text, headers, has_data) = match res {
75            BackendResponse::Error { msg } => {
76                return Err(std::io::Error::new(std::io::ErrorKind::Other, msg.as_str()));
77            }
78            BackendResponse::WebSocketVersion1 { .. } => {
79                return Err(std::io::Error::new(
80                    std::io::ErrorKind::Other,
81                    "server returned a web socket instead of a web request",
82                ));
83            }
84            BackendResponse::WebRequestVersion1 {
85                ok,
86                redirected,
87                status,
88                status_text,
89                headers,
90                has_data,
91            } => (ok, redirected, status, status_text, headers, has_data),
92            _ => {
93                return Err(std::io::Error::new(
94                    std::io::ErrorKind::Other,
95                    "the socket does not support this response type",
96                ));
97            }
98        };
99
100        let status = StatusCode::from_u16(status).map_err(|err| {
101            std::io::Error::new(
102                std::io::ErrorKind::Other,
103                format!("invalid status code returned by the server - {}", err).as_str(),
104            )
105        })?;
106
107        let data = if has_data {
108            let mut data = Vec::new();
109            read_to_end(&mut file, &mut data)?;
110            Some(data)
111        } else {
112            None
113        };
114
115        Ok(Response {
116            ok,
117            redirected,
118            status,
119            status_text,
120            headers,
121            pos: 0usize,
122            data,
123        })
124    }
125}