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
101
102
103
104
105
106
107
108
109
use crate::value::{to_value, Value};
use crate::{Error, ErrorKind};
use hyper::{http, Body, HeaderMap, Response, StatusCode};
use serde::Serialize;
pub const DEFAULT_MIME: &str = "application/octet-stream";
#[macro_export]
macro_rules! hyper_response {
($code: expr, $message: expr) => {
hyper::Response::builder()
.status($code)
.body(Body::from($message))
};
($code: expr) => {
hyper::Response::builder()
.status($code)
.body(Body::from(""))
};
}
pub type HResult = std::result::Result<HContent, Error>;
pub trait HResultX {
fn into_hyper_response(self) -> Result<Response<Body>, http::Error>;
}
impl HResultX for HResult {
fn into_hyper_response(self) -> Result<Response<Body>, http::Error> {
match self {
Ok(resp) => match resp {
HContent::Data(v, mime, header_map) => {
let mut r = Response::builder();
if let Some(mt) = mime {
if mt.starts_with("text/") {
r = r.header(
hyper::header::CONTENT_TYPE,
&format!("{};charset=utf-8", mt),
);
} else {
r = r.header(hyper::header::CONTENT_TYPE, mt);
}
} else {
r = r.header(hyper::header::CONTENT_TYPE, DEFAULT_MIME);
}
let mut result = r.status(StatusCode::OK).body(Body::from(v))?;
if let Some(h) = header_map {
result.headers_mut().extend(h);
}
Ok(result)
}
HContent::Value(val) => match serde_json::to_vec(&val) {
Ok(v) => Response::builder()
.header(hyper::header::CONTENT_TYPE, "application/json")
.status(StatusCode::OK)
.body(Body::from(v)),
Err(e) => {
hyper_response!(StatusCode::INTERNAL_SERVER_ERROR, e.to_string())
}
},
HContent::Redirect(l) => Response::builder()
.status(StatusCode::MOVED_PERMANENTLY)
.header(hyper::header::LOCATION, l)
.body(Body::from("")),
},
Err(e) if e.kind() == ErrorKind::ResourceNotFound => {
hyper_response!(StatusCode::NOT_FOUND, e.to_string())
}
Err(e) if e.kind() == ErrorKind::AccessDenied => {
hyper_response!(StatusCode::FORBIDDEN, e.to_string())
}
Err(e) if e.kind() == ErrorKind::InvalidParameter => {
hyper_response!(StatusCode::BAD_REQUEST, e.to_string())
}
Err(e) => {
hyper_response!(StatusCode::INTERNAL_SERVER_ERROR, e.to_string())
}
}
}
}
pub enum HContent {
Data(Vec<u8>, Option<&'static str>, Option<HeaderMap>),
Value(Value),
Redirect(String),
}
impl HContent {
pub fn ok() -> Self {
#[derive(Serialize)]
struct OK {
ok: bool,
}
HContent::Value(to_value(OK { ok: true }).unwrap())
}
pub fn not_ok() -> Self {
#[derive(Serialize)]
struct OK {
ok: bool,
}
HContent::Value(to_value(OK { ok: false }).unwrap())
}
}