serverkit-hyper 0.4.0

Hyper HTTP/1 and HTTP/2 adapter for ServerKit
Documentation
use std::net::SocketAddr;

use hyper::{
    Request as HyperRequest, Response as HyperResponse,
    body::Incoming,
    header::{CONTENT_LENGTH, HeaderName, HeaderValue},
};
use serverkit::{Headers, Method, Request, Response, ResponseBody, Router};

use crate::body::{HyperRequestStream, HyperResponseBody};

pub(crate) struct HandledRequest {
    pub(crate) response: Response,
    #[cfg(feature = "websocket")]
    pub(crate) on_upgrade: hyper::upgrade::OnUpgrade,
}

pub(crate) async fn handle_request(
    router: &Router,
    #[cfg_attr(not(feature = "websocket"), allow(unused_mut))] mut request: HyperRequest<Incoming>,
    address: SocketAddr,
) -> HandledRequest {
    #[cfg(feature = "websocket")]
    let on_upgrade = hyper::upgrade::on(&mut request);
    let (parts, body) = request.into_parts();
    let mut headers = Headers::new();

    for (name, value) in &parts.headers {
        headers
            .append(name.as_str(), value.as_bytes())
            .expect("Hyper supplied an invalid request header");
    }

    let mut request = Request::from_parts(
        Method::try_from(parts.method.as_str()).expect("Hyper supplied an invalid request method"),
        parts.uri.path(),
        parts.uri.query().map(str::to_owned),
        headers,
        Box::new(HyperRequestStream::new(body)),
    );
    request.insert_extension(address);

    HandledRequest {
        response: router.handle(request).await,
        #[cfg(feature = "websocket")]
        on_upgrade,
    }
}

pub(crate) fn into_hyper_response(response: Response) -> HyperResponse<HyperResponseBody> {
    let (status, headers, body) = response.into_parts();

    #[cfg(feature = "websocket")]
    let body = match body {
        ResponseBody::WebSocket(_) => {
            let response = Response::text(501, "WebSocket requires the Tokio Hyper driver");
            let (status, headers, body) = response.into_parts();
            return into_hyper_response_parts(status, headers, body);
        }
        body => body,
    };

    into_hyper_response_parts(status, headers, body)
}

pub(crate) fn into_hyper_response_parts(
    status: u16,
    headers: Headers,
    body: ResponseBody,
) -> HyperResponse<HyperResponseBody> {
    let length = body.buffered().map(<[u8]>::len);
    let has_content_length = headers.contains("content-length");
    let mut response = HyperResponse::new(HyperResponseBody::new(body));

    match hyper::StatusCode::from_u16(status) {
        Ok(status) => *response.status_mut() = status,
        Err(_) => *response.status_mut() = hyper::StatusCode::INTERNAL_SERVER_ERROR,
    }

    append_headers(&mut response, headers);

    if !has_content_length && let Some(length) = length {
        response.headers_mut().insert(CONTENT_LENGTH, length.into());
    }

    response
}

pub(crate) fn append_headers(response: &mut HyperResponse<HyperResponseBody>, headers: Headers) {
    for (name, value) in headers.iter() {
        let name = HeaderName::from_bytes(name.as_bytes())
            .expect("ServerKit generated an invalid response header name");
        let value = HeaderValue::from_bytes(value)
            .expect("ServerKit generated an invalid response header value");

        response.headers_mut().append(name, value);
    }
}