http_mini_lib/utils/
fs.rs

1use std::fs;
2use std::io::{Error, ErrorKind};
3use std::path::Path;
4
5/// # Validate path
6///
7/// Checks:
8/// * path is not a symlink
9/// * path is not relative
10pub fn validate_path(path: &Path) -> bool {
11    !path.is_symlink() && !path.is_relative()
12}
13
14/// # Retrieve file contents
15pub fn get_file_contents(path: &str) -> Result<Vec<u8>, Error> {
16    let path_metadata = fs::metadata(path);
17    if path_metadata.is_err() {
18        return Err(path_metadata.err().unwrap());
19    }
20
21    let file_data = fs::read(path);
22    if file_data.is_err() {
23        return Err(file_data.err().unwrap());
24    }
25
26    Ok(file_data.ok().unwrap())
27}
28
29const HTML_TEMPLATE: &str =
30    "<!DOCTYPE html><html><head><title>###TITLE###</title></head><body>###BODY###</body></html>";
31const LISTING_LIST_START: &str = "<ul>";
32const LISTING_LIST_END: &str = "</ul>";
33const LISTING_LIST_ITEM_START: &str = "<li>";
34const LISTING_LIST_ITEM_END: &str = "</li>";
35const LISTING_DIR: &str = "<strong>DIR</strong>&nbsp;&nbsp;&nbsp; ";
36const LISTING_FILE: &str = "file&nbsp;&nbsp;&nbsp;&nbsp; ";
37const LISTING_LINK_PART_1: &str = "<a href=\"";
38const LISTING_LINK_PART_2: &str = "\" target=\"_self\">";
39const LISTING_LINK_PART_3: &str = "</a>";
40const LISTING_DIR_SLASH: &str = "/";
41
42pub fn get_dir_contents_as_html(
43    path: &Path,
44    source_dir: &Path,
45    address: &str,
46) -> Result<String, Error> {
47    if !path.is_dir() {
48        return Err(Error::new(ErrorKind::NotFound, "Not a directory"));
49    }
50
51    if !path.starts_with(source_dir) {
52        return Err(Error::new(ErrorKind::NotFound, "Access forbidden"));
53    }
54
55    let dir_read = fs::read_dir(path);
56    if dir_read.is_err() {
57        return Err(dir_read.err().unwrap());
58    }
59
60    let mut result = format!("{}\n", LISTING_LIST_START);
61
62    let dir_paths = dir_read.unwrap();
63    for dir_path in dir_paths {
64        if dir_path.is_err() {
65            continue;
66        }
67
68        let dir_path = dir_path.unwrap();
69        let is_dir = dir_path.path().is_dir();
70        let entry_display_path = dir_path
71            .path()
72            .into_os_string()
73            .into_string()
74            .unwrap()
75            .replace(source_dir.to_str().unwrap(), ".");
76        let entry_server_uri = format!("{}{}", address, entry_display_path.trim_start_matches("."));
77
78        result = format!(
79            "{}{}{}{}{}{}{}{}{}{}\n",
80            result,
81            LISTING_LIST_ITEM_START,
82            if is_dir { LISTING_DIR } else { LISTING_FILE },
83            LISTING_LINK_PART_1,
84            entry_server_uri,
85            LISTING_LINK_PART_2,
86            entry_display_path,
87            LISTING_LINK_PART_3,
88            if is_dir { LISTING_DIR_SLASH } else { "" },
89            LISTING_LIST_ITEM_END,
90        );
91    }
92    result = format!("{}\n{}\n", result, LISTING_LIST_END);
93    result = HTML_TEMPLATE
94        .replace(
95            "###TITLE###",
96            path.to_str()
97                .unwrap()
98                .replace(source_dir.to_str().unwrap(), ".")
99                .as_str(),
100        )
101        .replace("###BODY###", result.as_str());
102
103    Ok(result)
104}