-fn respond(request: cgi::Request) -> Result<cgi::Response, String> {
- let greeting = std::fs::read_to_string("greeting.txt").map_err(|_| "Couldn't open file")?;
+use std::path::{Path, PathBuf};
- Ok(cgi::text_response(200, greeting))
+const DATA_PATH: &str = "/var/lib/voter";
+
+fn validate_path(path: &str) -> Result<PathBuf, cgi::Response> {
+ let invalid_path = || cgi::text_response(404, "Invalid path");
+ if path == "/" {
+ return Err(cgi::text_response(404, "(This is the voting place. You should have been given a more specific URL for the specific thing you've been invited to vote on.)"));
+ }
+ if path.contains("..") || !path.starts_with("/") {
+ return Err(invalid_path());
+ }
+ let dir = Path::new(&format!("{DATA_PATH}{path}")).to_path_buf();
+ if !dir
+ .canonicalize()
+ .map_err(|_| invalid_path())?
+ .starts_with(DATA_PATH)
+ {
+ return Err(invalid_path());
+ }
+ if !dir.is_dir() {
+ return Err(invalid_path());
+ }
+ Ok(dir)
+}
+
+fn prompt_for_vote(dir: PathBuf, request: cgi::Request) -> Result<cgi::Response, cgi::Response> {
+ Err(cgi::text_response(503, "Not Implemented"))
+}
+
+fn record_vote(dir: PathBuf, request: cgi::Request) -> Result<cgi::Response, cgi::Response> {
+ Err(cgi::text_response(503, "Not Implemented"))
+}
+
+fn respond(request: cgi::Request) -> Result<cgi::Response, cgi::Response> {
+ let dir = validate_path(request.uri().path())?;
+ match request.method() {
+ &cgi::http::Method::GET => prompt_for_vote(dir, request),
+ &cgi::http::Method::POST => record_vote(dir, request),
+ _ => Err(cgi::text_response(405, "Huh?")),
+ }
+}
+
+fn respond_or_report_error(request: cgi::Request) -> cgi::Response {
+ match respond(request) {
+ Ok(result) => result,
+ Err(error) => error,
+ }
}
-cgi::cgi_try_main! { respond }
+cgi::cgi_main! { respond_or_report_error }