about summary refs log tree commit diff
path: root/src/fs.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs.rs')
-rw-r--r--src/fs.rs50
1 files changed, 40 insertions, 10 deletions
diff --git a/src/fs.rs b/src/fs.rs
index d9b8810..b44e4c4 100644
--- a/src/fs.rs
+++ b/src/fs.rs
@@ -9,12 +9,14 @@ use crate::RuntimeError;
 #[derive(Clone, Debug, PartialEq)]
 pub struct Webpath {
 	webcanon: Utf8PathBuf,
+	is_dir: bool,
 }
 
 impl FromStr for Webpath {
 	type Err = RuntimeError;
 
 	fn from_str(raw: &str) -> Result<Self, Self::Err> {
+		let is_dir = raw.trim_end().ends_with('/');
 		let mut curr = Utf8PathBuf::new();
 
 		for component in raw.split('/') {
@@ -31,7 +33,10 @@ impl FromStr for Webpath {
 			}
 		}
 
-		Ok(Self { webcanon: curr })
+		Ok(Self {
+			webcanon: curr,
+			is_dir,
+		})
 	}
 }
 
@@ -41,6 +46,17 @@ impl Webpath {
 	pub fn is_index(&self) -> bool {
 		self.webcanon == ""
 	}
+
+	/// Whether or not this Webpath points to a directory (has a trailing slash)
+	pub fn is_dir(&self) -> bool {
+		self.is_dir
+	}
+
+	/// Return a String that interprets this Webpath as a directory, adding a
+	/// trailing slash
+	pub fn as_dir(&self) -> String {
+		format!("/{}/", self.webcanon)
+	}
 }
 
 impl Deref for Webpath {
@@ -72,6 +88,11 @@ impl fmt::Display for Webpath {
 const ROOT_INDEX: &str = "home.html";
 const DIRFILE_EXT: &str = "html";
 
+pub struct PathResolution {
+	pub filepath: Utf8PathBuf,
+	pub is_dirfile: bool,
+}
+
 #[derive(Clone, Debug)]
 pub struct Filesystem {
 	webroot: Utf8PathBuf,
@@ -84,10 +105,13 @@ impl Filesystem {
 		}
 	}
 
-	pub fn resolve(&self, webpath: &Webpath) -> Result<Utf8PathBuf, RuntimeError> {
+	pub fn resolve(&self, webpath: &Webpath) -> Result<PathResolution, RuntimeError> {
 		println!("resolve = {webpath}");
 		if webpath.is_index() || webpath == ROOT_INDEX {
-			return Ok(self.webroot.join(ROOT_INDEX));
+			return Ok(PathResolution {
+				filepath: self.webroot.join(ROOT_INDEX),
+				is_dirfile: false,
+			});
 		}
 
 		let path = self.webroot.join(webpath);
@@ -95,7 +119,10 @@ impl Filesystem {
 
 		// If it's a file then return the path immediatly
 		if metadata.is_file() {
-			Ok(path)
+			Ok(PathResolution {
+				filepath: path,
+				is_dirfile: false,
+			})
 		} else {
 			// we check this above. but still..
 			//TODO: gen- probably don't unwrap
@@ -103,7 +130,10 @@ impl Filesystem {
 			let dirfile = path.join(format!("{filename}.{DIRFILE_EXT}"));
 
 			if dirfile.exists() {
-				Ok(dirfile)
+				Ok(PathResolution {
+					filepath: dirfile,
+					is_dirfile: true,
+				})
 			} else {
 				Err(RuntimeError::NotFound {
 					source: io::ErrorKind::NotFound.into(),
@@ -182,11 +212,11 @@ mod test {
 	fn filesystem_resolves_index() {
 		let fs = Filesystem::new(TESTROOT);
 		assert_eq!(
-			fs.resolve(&webpath!("/")).unwrap(),
+			fs.resolve(&webpath!("/")).unwrap().filepath,
 			format!("{TESTROOT}/{ROOT_INDEX}")
 		);
 		assert_eq!(
-			fs.resolve(&webpath!("/one/..")).unwrap(),
+			fs.resolve(&webpath!("/one/..")).unwrap().filepath,
 			format!("{TESTROOT}/{ROOT_INDEX}")
 		);
 	}
@@ -195,15 +225,15 @@ mod test {
 	fn filesystem_resolves_dirfile() {
 		let fs = Filesystem::new(TESTROOT);
 		assert_eq!(
-			fs.resolve(&webpath!("/one")).unwrap(),
+			fs.resolve(&webpath!("/one")).unwrap().filepath,
 			format!("{TESTROOT}/one/one.html")
 		);
 		assert_eq!(
-			fs.resolve(&webpath!("/one/eleven/")).unwrap(),
+			fs.resolve(&webpath!("/one/eleven/")).unwrap().filepath,
 			format!("{TESTROOT}/one/eleven/eleven.html")
 		);
 		assert_eq!(
-			fs.resolve(&webpath!("/one/eleven/..")).unwrap(),
+			fs.resolve(&webpath!("/one/eleven/..")).unwrap().filepath,
 			format!("{TESTROOT}/one/one.html")
 		);
 	}