aboutsummaryrefslogtreecommitdiff
path: root/src/error.rs
blob: a49301ad40f9bd3e04177480a77c5bb0e6426c05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use hyper::http::response::Builder;
use hyper::StatusCode;
use sputnik::hyper_body::FormError;
use sputnik::request::QueryError;
use sputnik::response::EmptyBuilder;
use std::str::Utf8Error;

use crate::{HyperResponse, Page};

/// For convenience this enum also contains nonerroneous variants.
#[derive(Debug)]
pub enum Error {
    /// A 400 bad request error.
    BadRequest(String),
    /// A 401 unauthorized error.
    Unauthorized(String),
    /// A 403 forbidden error.
    Forbidden(String),
    /// A 404 not found error.
    NotFound(String),
    /// A 500 internal server error.
    Internal(String),
    /// A 304 response.
    NotModified,
    /// A 302 redirect to the given path.
    Redirect(String),

    // TODO: use Redirect instead
    /// Missing trailing slash.
    MissingTrailingSlash(String),
}

impl From<Utf8Error> for Error {
    fn from(_: Utf8Error) -> Self {
        Self::BadRequest("invalid UTF-8".into())
    }
}

impl From<git2::Error> for Error {
    fn from(e: git2::Error) -> Self {
        eprintln!("git error: {}", e);
        Self::Internal("something went wrong with git".into())
    }
}

impl From<FormError> for Error {
    fn from(e: FormError) -> Self {
        Self::BadRequest(e.to_string())
    }
}

impl From<QueryError> for Error {
    fn from(e: QueryError) -> Self {
        Self::BadRequest(e.to_string())
    }
}

impl From<Error> for HyperResponse {
    fn from(err: Error) -> Self {
        let (status, message) = match err {
            Error::BadRequest(msg) => (400, msg),
            Error::Unauthorized(msg) => (401, msg),
            Error::Forbidden(msg) => (403, msg),
            Error::NotFound(msg) => (404, msg),
            Error::Internal(msg) => (500, msg),
            Error::NotModified => {
                return Builder::new()
                    .status(StatusCode::NOT_MODIFIED)
                    .empty()
                    .unwrap();
            }
            Error::MissingTrailingSlash(path) => {
                return Builder::new()
                    .status(StatusCode::FOUND)
                    .header("location", format!("{}/", path))
                    .body("redirecting".into())
                    .unwrap();
            }
            Error::Redirect(target) => {
                return Builder::new()
                    .status(StatusCode::FOUND)
                    .header("location", target)
                    .body("redirecting".into())
                    .unwrap();
            }
        };
        Builder::new()
            .status(status)
            .header("content-type", "text/html")
            .body(
                Page {
                    body: format!("<div>{}</div>", message),
                    ..Page::default()
                }
                .render()
                .into(),
            )
            .unwrap()
    }
}