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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use crate::util::{open_with_metadata, RequestedPath};
use http::{Method, Request};
use mime_guess::{Mime, MimeGuess};
use std::fs::Metadata;
use std::io::{Error as IoError, ErrorKind as IoErrorKind};
use std::path::PathBuf;
use tokio::fs::File;
#[derive(Debug)]
pub enum ResolveResult {
MethodNotMatched,
UriNotMatched,
NotFound,
PermissionDenied,
IsDirectory,
Found(File, Metadata, Mime),
}
fn map_open_err(err: IoError) -> Result<ResolveResult, IoError> {
match err.kind() {
IoErrorKind::NotFound => Ok(ResolveResult::NotFound),
IoErrorKind::PermissionDenied => Ok(ResolveResult::PermissionDenied),
_ => Err(err),
}
}
pub async fn resolve<B>(
root: impl Into<PathBuf>,
req: &Request<B>,
) -> Result<ResolveResult, IoError> {
match *req.method() {
Method::HEAD | Method::GET => {}
_ => {
return Ok(ResolveResult::MethodNotMatched);
}
}
if req.uri().scheme_str().is_some() || req.uri().host().is_some() {
return Ok(ResolveResult::UriNotMatched);
}
resolve_path(root, req.uri().path()).await
}
pub async fn resolve_path(
root: impl Into<PathBuf>,
request_path: &str,
) -> Result<ResolveResult, IoError> {
let RequestedPath {
mut full_path,
is_dir_request,
} = RequestedPath::resolve(root, request_path);
let (file, metadata) = match open_with_metadata(&full_path).await {
Ok(pair) => pair,
Err(err) => return map_open_err(err),
};
if is_dir_request && !metadata.is_dir() {
return Ok(ResolveResult::NotFound);
}
if !is_dir_request && metadata.is_dir() {
return Ok(ResolveResult::IsDirectory);
}
if !is_dir_request {
let mime = MimeGuess::from_path(&full_path).first_or_octet_stream();
return Ok(ResolveResult::Found(file, metadata, mime));
}
full_path.push("index.html");
let (file, metadata) = match open_with_metadata(&full_path).await {
Ok(pair) => pair,
Err(err) => return map_open_err(err),
};
if metadata.is_dir() {
return Ok(ResolveResult::NotFound);
}
let mime = MimeGuess::from_path(full_path).first_or_octet_stream();
Ok(ResolveResult::Found(file, metadata, mime))
}