1#![forbid(unsafe_code)]
3#![deny(
4 missing_copy_implementations,
5 rustdoc::missing_crate_level_docs,
6 missing_debug_implementations,
7 missing_docs,
8 nonstandard_style,
9 unused_qualifications
10)]
11#![cfg_attr(docsrs, feature(doc_cfg))]
12
13#[cfg(test)]
14#[doc = include_str!("../README.md")]
15mod readme {}
16
17#[cfg(feature = "client")]
18#[cfg_attr(docsrs, doc(cfg(feature = "client")))]
19pub mod client;
20
21use std::borrow::Cow;
22use trillium::{Conn, Handler, KnownHeaderName::Location, Status};
23
24#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
28pub enum RedirectStatus {
29 MultipleChoices,
31 MovedPermanently,
33 #[default]
35 Found,
36 SeeOther,
38 TemporaryRedirect,
40 PermanentRedirect,
42}
43
44impl From<RedirectStatus> for Status {
45 fn from(value: RedirectStatus) -> Self {
46 match value {
47 RedirectStatus::MultipleChoices => Status::MultipleChoice,
48 RedirectStatus::MovedPermanently => Status::MovedPermanently,
49 RedirectStatus::Found => Status::Found,
50 RedirectStatus::SeeOther => Status::SeeOther,
51 RedirectStatus::TemporaryRedirect => Status::TemporaryRedirect,
52 RedirectStatus::PermanentRedirect => Status::PermanentRedirect,
53 }
54 }
55}
56
57#[derive(Clone, Debug)]
59pub struct Redirect {
60 to: Cow<'static, str>,
61 status: RedirectStatus,
62}
63
64impl Redirect {
65 pub fn to(to: impl Into<Cow<'static, str>>) -> Self {
67 Self {
68 to: to.into(),
69 status: RedirectStatus::default(),
70 }
71 }
72
73 pub fn with_redirect_status(mut self, status: RedirectStatus) -> Self {
75 self.status = status;
76 self
77 }
78}
79
80pub fn redirect(to: impl Into<Cow<'static, str>>) -> Redirect {
82 Redirect::to(to)
83}
84
85impl Handler for Redirect {
86 async fn run(&self, conn: Conn) -> Conn {
87 conn.redirect_as(self.to.clone(), self.status)
88 }
89}
90
91pub trait RedirectConnExt {
93 fn redirect(self, to: impl Into<Cow<'static, str>>) -> Self;
95 fn redirect_as(self, to: impl Into<Cow<'static, str>>, status: RedirectStatus) -> Self;
97}
98
99impl RedirectConnExt for Conn {
100 fn redirect(self, to: impl Into<Cow<'static, str>>) -> Self {
101 self.redirect_as(to, RedirectStatus::default())
102 }
103
104 fn redirect_as(self, to: impl Into<Cow<'static, str>>, status: RedirectStatus) -> Self {
105 self.with_status(status)
106 .with_response_header(Location, to.into())
107 .halt()
108 }
109}