1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use http::{Request, Response};

use crate::{unit::UnitService, UnitRequest, UnitResult};

/// A request handler that uses types from the [`http`] crate.
/// 
/// [`http`]: https://docs.rs/http
/// 
/// Request handles with this trait can be used with the [`HttpMiddleware`]
/// adapter.
/// 
/// ## Example
/// 
/// ```no_run
/// # use unit_rs::{HttpMiddleware, Unit};
/// 
/// # fn main() {
/// let mut unit = Unit::new().unwrap();
///
/// unit.set_request_handler(HttpMiddleware::new(|req: http::Request<Vec<u8>>| {
///     let body = format!("Hello world!\n\nBody length: {}\n", req.body().len());
/// 
///     let response = http::Response::builder()
///         .header("Content-Type", "text/plain")
///         .body(body.into_bytes())
///         .unwrap();
/// 
///     Ok(response)
/// }));
/// # }
/// ```
#[cfg_attr(docsrs, doc(cfg(feature = "http")))]
pub trait HttpService {
    fn handle_request(&mut self, _req: Request<Vec<u8>>) -> UnitResult<Response<Vec<u8>>>;
}

/// Adapter middleware to use types from the [`http`] crate.
///
/// [`http`]: https://docs.rs/http
///
/// The inner request handler must implement the [`HttpService`] trait.
#[cfg_attr(docsrs, doc(cfg(feature = "http")))]
pub struct HttpMiddleware<H: HttpService>(H);

impl<H: HttpService> HttpMiddleware<H> {
    pub fn new(unit_service: H) -> Self {
        Self(unit_service)
    }
}

impl<H: HttpService> UnitService for HttpMiddleware<H> {
    // TODO: Handle errors, this is currently just a prototype
    fn handle_request(&mut self, req: UnitRequest) -> UnitResult<()> {
        let mut http_request_builder = Request::builder();

        for (name, value) in req.fields() {
            http_request_builder = http_request_builder.header(name, value);
        }

        // TODO: Read body from request
        let http_request = http_request_builder.body(Vec::new()).unwrap();

        let http_response = self.0.handle_request(http_request)?;

        // TODO: Write headers without allocating
        let headers: Vec<_> = http_response.headers().iter().collect();

        req.create_response(&headers, http_response.body())?;

        Ok(())
    }
}

impl<F> HttpService for F
where
    F: FnMut(Request<Vec<u8>>) -> UnitResult<Response<Vec<u8>>> + 'static,
{
    fn handle_request(&mut self, req: Request<Vec<u8>>) -> UnitResult<Response<Vec<u8>>> {
        self(req)
    }
}