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
12#[cfg(test)]
13#[doc = include_str!("../README.md")]
14mod readme {}
15
16#[cfg(feature = "client")]
17pub mod client;
18
19use std::borrow::Cow;
20use trillium::{Conn, Handler, KnownHeaderName::Location, Status};
21
22#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
26pub enum RedirectStatus {
27 MultipleChoices,
29 MovedPermanently,
31 #[default]
33 Found,
34 SeeOther,
36 TemporaryRedirect,
38 PermanentRedirect,
40}
41
42impl From<RedirectStatus> for Status {
43 fn from(value: RedirectStatus) -> Self {
44 match value {
45 RedirectStatus::MultipleChoices => Status::MultipleChoice,
46 RedirectStatus::MovedPermanently => Status::MovedPermanently,
47 RedirectStatus::Found => Status::Found,
48 RedirectStatus::SeeOther => Status::SeeOther,
49 RedirectStatus::TemporaryRedirect => Status::TemporaryRedirect,
50 RedirectStatus::PermanentRedirect => Status::PermanentRedirect,
51 }
52 }
53}
54
55#[derive(Clone, Debug)]
57pub struct Redirect {
58 to: Cow<'static, str>,
59 status: RedirectStatus,
60}
61
62impl Redirect {
63 pub fn to(to: impl Into<Cow<'static, str>>) -> Self {
65 Self {
66 to: to.into(),
67 status: RedirectStatus::default(),
68 }
69 }
70
71 pub fn with_redirect_status(mut self, status: RedirectStatus) -> Self {
73 self.status = status;
74 self
75 }
76}
77
78pub fn redirect(to: impl Into<Cow<'static, str>>) -> Redirect {
80 Redirect::to(to)
81}
82
83impl Handler for Redirect {
84 async fn run(&self, conn: Conn) -> Conn {
85 conn.redirect_as(self.to.clone(), self.status)
86 }
87}
88
89pub trait RedirectConnExt {
91 fn redirect(self, to: impl Into<Cow<'static, str>>) -> Self;
93 fn redirect_as(self, to: impl Into<Cow<'static, str>>, status: RedirectStatus) -> Self;
95}
96
97impl RedirectConnExt for Conn {
98 fn redirect(self, to: impl Into<Cow<'static, str>>) -> Self {
99 self.redirect_as(to, RedirectStatus::default())
100 }
101
102 fn redirect_as(self, to: impl Into<Cow<'static, str>>, status: RedirectStatus) -> Self {
103 self.with_status(status)
104 .with_response_header(Location, to.into())
105 .halt()
106 }
107}