hyper_staticfile/util/
requested_path.rs

1use std::path::{Component, Path, PathBuf};
2
3#[inline]
4fn decode_percents(string: &str) -> String {
5    percent_encoding::percent_decode_str(string)
6        .decode_utf8_lossy()
7        .into_owned()
8}
9
10fn sanitize_path(path: &Path) -> PathBuf {
11    path.components()
12        .fold(PathBuf::new(), |mut result, p| match p {
13            Component::Normal(x) => {
14                // Parse again to prevent a malicious component containing
15                // a Windows drive letter, e.g.: `/anypath/c:/windows/win.ini`
16                if Path::new(&x)
17                    .components()
18                    .all(|c| matches!(c, Component::Normal(_)))
19                {
20                    result.push(x);
21                }
22                result
23            }
24            Component::ParentDir => {
25                result.pop();
26                result
27            }
28            _ => result,
29        })
30}
31
32/// Processed request path.
33pub struct RequestedPath {
34    /// Sanitized path of the request.
35    pub sanitized: PathBuf,
36    /// Whether a directory was requested. (The input ended with a slash.)
37    pub is_dir_request: bool,
38}
39
40impl RequestedPath {
41    /// Process a request path.
42    pub fn resolve(request_path: &str) -> Self {
43        let is_dir_request = request_path.as_bytes().last() == Some(&b'/');
44        let request_path = PathBuf::from(decode_percents(request_path));
45        RequestedPath {
46            sanitized: sanitize_path(&request_path),
47            is_dir_request,
48        }
49    }
50}