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
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! Responder implementations.
//!
//! Reponders determine how the server will respond.

use std::fmt;
use std::future::Future;
use std::pin::Pin;

// import the cycle macro so that it's available if people glob import this module.
#[doc(inline)]
pub use crate::cycle;

/// Respond with an HTTP response.
pub trait Responder: Send + fmt::Debug {
    /// Return a future that outputs an HTTP response.
    fn respond(&mut self) -> Pin<Box<dyn Future<Output = http::Response<hyper::Body>> + Send>>;
}

/// respond with the provided status code.
pub fn status_code(code: u16) -> impl Responder {
    StatusCode(code)
}
/// The `StatusCode` responder returned by [status_code()](fn.status_code.html)
#[derive(Debug)]
pub struct StatusCode(u16);
impl Responder for StatusCode {
    fn respond(&mut self) -> Pin<Box<dyn Future<Output = http::Response<hyper::Body>> + Send>> {
        async fn _respond(status_code: u16) -> http::Response<hyper::Body> {
            http::Response::builder()
                .status(status_code)
                .body(hyper::Body::empty())
                .unwrap()
        }
        Box::pin(_respond(self.0))
    }
}

/// respond with a body that is the json encoding of data.
///
/// The status code will be `200` and the content-type will be
/// `application/json`.
pub fn json_encoded<T>(data: T) -> impl Responder
where
    T: serde::Serialize,
{
    JsonEncoded(serde_json::to_string(&data).unwrap())
}
/// The `JsonEncoded` responder returned by [json_encoded()](fn.json_encoded.html)
#[derive(Debug)]
pub struct JsonEncoded(String);
impl Responder for JsonEncoded {
    fn respond(&mut self) -> Pin<Box<dyn Future<Output = http::Response<hyper::Body>> + Send>> {
        async fn _respond(body: String) -> http::Response<hyper::Body> {
            http::Response::builder()
                .status(200)
                .header("Content-Type", "application/json")
                .body(body.into())
                .unwrap()
        }
        Box::pin(_respond(self.0.clone()))
    }
}

/// respond with a body that is the url encoding of data.
///
/// The status code will be `200` and the content-type will be
/// `application/x-www-form-urlencoded`.
pub fn url_encoded<T>(data: T) -> impl Responder
where
    T: serde::Serialize,
{
    UrlEncoded(serde_urlencoded::to_string(&data).unwrap())
}
/// The `UrlEncoded` responder returned by [url_encoded()](fn.url_encoded.html)
#[derive(Debug)]
pub struct UrlEncoded(String);
impl Responder for UrlEncoded {
    fn respond(&mut self) -> Pin<Box<dyn Future<Output = http::Response<hyper::Body>> + Send>> {
        async fn _respond(body: String) -> http::Response<hyper::Body> {
            http::Response::builder()
                .status(200)
                .header("Content-Type", "application/x-www-form-urlencoded")
                .body(body.into())
                .unwrap()
        }
        Box::pin(_respond(self.0.clone()))
    }
}

impl<B> Responder for http::Response<B>
where
    B: Clone + Into<hyper::Body> + Send + fmt::Debug,
{
    fn respond(&mut self) -> Pin<Box<dyn Future<Output = http::Response<hyper::Body>> + Send>> {
        async fn _respond(resp: http::Response<hyper::Body>) -> http::Response<hyper::Body> {
            resp
        }
        let mut builder = http::Response::builder();
        builder = builder
            .status(self.status().clone())
            .version(self.version().clone());
        *builder.headers_mut().unwrap() = self.headers().clone();
        let resp = builder.body(self.body().clone().into()).unwrap();

        Box::pin(_respond(resp))
    }
}

/// Cycle through the provided list of responders.
pub fn cycle(responders: Vec<Box<dyn Responder>>) -> impl Responder {
    if responders.is_empty() {
        panic!("empty vector provided to cycle");
    }
    Cycle { idx: 0, responders }
}
/// The `Cycle` responder returned by [cycle()](fn.cycle.html)
#[derive(Debug)]
pub struct Cycle {
    idx: usize,
    responders: Vec<Box<dyn Responder>>,
}
impl Responder for Cycle {
    fn respond(&mut self) -> Pin<Box<dyn Future<Output = http::Response<hyper::Body>> + Send>> {
        let response = self.responders[self.idx].respond();
        self.idx = (self.idx + 1) % self.responders.len();
        response
    }
}

#[cfg(test)]
mod tests {}