Skip to main content

trillium_head/
lib.rs

1/*!
2# Trillium handler for HEAD requests
3
4This simple handler rewrites HEAD requests to be GET requests, and
5then before sending the response, removes the outbound body but sets a
6content length header. Any handlers subsequent to this one see a GET
7request.
8*/
9#![forbid(unsafe_code)]
10#![deny(
11    missing_copy_implementations,
12    rustdoc::missing_crate_level_docs,
13    missing_debug_implementations,
14    missing_docs,
15    nonstandard_style,
16    unused_qualifications
17)]
18
19use trillium::{async_trait, conn_unwrap, Conn, Handler, KnownHeaderName::ContentLength, Method};
20
21/**
22Trillium handler for HEAD requests
23
24See crate-level docs for an explanation
25*/
26#[derive(Default, Clone, Copy, Debug)]
27pub struct Head {
28    _my_private_things: (),
29}
30
31impl Head {
32    /// constructs a new Head handler
33    pub fn new() -> Self {
34        Self::default()
35    }
36}
37
38#[derive(Clone, Copy, Debug)]
39struct RequestWasHead;
40
41#[async_trait]
42impl Handler for Head {
43    async fn run(&self, mut conn: Conn) -> Conn {
44        if conn.method() == Method::Head {
45            conn.inner_mut().set_method(Method::Get);
46            conn.insert_state(RequestWasHead);
47        }
48
49        conn
50    }
51
52    async fn before_send(&self, mut conn: Conn) -> Conn {
53        conn_unwrap!(conn.state::<RequestWasHead>(), conn);
54        conn.inner_mut().set_method(Method::Head);
55        let len = conn_unwrap!(
56            conn.inner_mut()
57                .take_response_body()
58                .and_then(|body| body.len()),
59            conn
60        );
61        conn.with_response_header(ContentLength, len.to_string())
62    }
63}
64
65/// Alias for [`Head::new`]
66pub fn head() -> Head {
67    Head::new()
68}