flawless-http 1.0.0-beta.3

HTTP client for https://flawless.dev.
Documentation
use crate::{transport::HTTPTransport, Request};

/// Implemented for everything that can be turned into a body.
///
/// In some cases additional headers are set for specific types, like `Content-Length` or `Content-Type`.
/// That's why this trait takes and returns a [`Request`].
///
/// If you are implementing this trait for your custom type, avoid overriding already present headers.
pub trait IntoBody<T: HTTPTransport> {
    fn into(self, request: Request<T>) -> (Request<T>, Vec<u8>);
}

impl<T: HTTPTransport> IntoBody<T> for Vec<u8> {
    fn into(self, request: Request<T>) -> (Request<T>, Vec<u8>) {
        let request = if request.header("Content-Length").is_some() {
            request
        } else {
            request.set_header("Content-Length", self.len().to_string())
        };
        (request, self)
    }
}

impl<T: HTTPTransport> IntoBody<T> for &[u8] {
    fn into(self, request: Request<T>) -> (Request<T>, Vec<u8>) {
        let body: Vec<u8> = self.to_owned();
        let request = if request.header("Content-Length").is_some() {
            request
        } else {
            request.set_header("Content-Length", body.len().to_string())
        };
        (request, body)
    }
}

impl<T: HTTPTransport> IntoBody<T> for String {
    fn into(self, request: Request<T>) -> (Request<T>, Vec<u8>) {
        let body: Vec<u8> = self.into_bytes();
        let request = if request.header("Content-Length").is_some() {
            request
        } else {
            request.set_header("Content-Length", body.len().to_string())
        };
        (request, body)
    }
}

impl<T: HTTPTransport> IntoBody<T> for &str {
    fn into(self, request: Request<T>) -> (Request<T>, Vec<u8>) {
        let body: Vec<u8> = self.to_owned().into_bytes();
        let request = if request.header("Content-Length").is_some() {
            request
        } else {
            request.set_header("Content-Length", body.len().to_string())
        };
        (request, body)
    }
}

impl<T: HTTPTransport> IntoBody<T> for &[(&str, &str)] {
    fn into(self, request: Request<T>) -> (Request<T>, Vec<u8>) {
        let encoded = form_urlencoded::Serializer::new(String::new()).extend_pairs(self).finish();
        let body: Vec<u8> = encoded.into_bytes();
        let request = if request.header("Content-Type").is_some() {
            request
        } else {
            request.set_header("Content-Type", "application/x-www-form-urlencoded")
        };
        let request = if request.header("Content-Length").is_some() {
            request
        } else {
            request.set_header("Content-Length", body.len().to_string())
        };
        (request, body)
    }
}

#[cfg(feature = "json")]
impl<T: HTTPTransport> IntoBody<T> for serde_json::Value {
    fn into(self, request: Request<T>) -> (Request<T>, Vec<u8>) {
        let body: Vec<u8> = self.to_string().into_bytes();
        let request = if request.header("Content-Type").is_some() {
            request
        } else {
            request.set_header("Content-Type", "application/json")
        };
        let request = if request.header("Content-Length").is_some() {
            request
        } else {
            request.set_header("Content-Length", body.len().to_string())
        };
        (request, body)
    }
}