Use platform-neutral path comparison for in-memory serving (fixes #1169) (#1175)

This introduces `relative-path`, a crate I've written for the specific
purpose of providing platform-neutral operations over paths the same way
they are used in URLs.

This means that `///hello///` == `/hello`, which should do the same as
the existing stripping minus the platform-specific path separators
causing the [bug being referenced](#1169).
This commit is contained in:
John-John Tedro 2020-09-21 18:02:37 +02:00 committed by Vincent Prouillet
parent c27f749a86
commit f9ae897190
5 changed files with 31 additions and 26 deletions

8
Cargo.lock generated
View file

@ -1900,6 +1900,12 @@ version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
[[package]]
name = "relative-path"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65aff7c83039e88c1c0b4bedf8dfa93d6ec84d5fc2945b37c1fa4186f46c5f94"
[[package]]
name = "remove_dir_all"
version = "0.5.3"
@ -2179,6 +2185,7 @@ dependencies = [
"link_checker",
"minify-html",
"rayon",
"relative-path",
"sass-rs",
"search",
"serde",
@ -2981,6 +2988,7 @@ dependencies = [
"lazy_static",
"notify",
"open",
"relative-path",
"site",
"termcolor",
"tokio",

View file

@ -35,6 +35,7 @@ ws = "0.9"
ctrlc = "3"
open = "1.2"
globset = "0.4"
relative-path = "1"
site = { path = "components/site" }
errors = { path = "components/errors" }

View file

@ -14,6 +14,7 @@ serde = "1"
serde_derive = "1"
sass-rs = "0.2"
lazy_static = "1.1"
relative-path = "1"
errors = { path = "../errors" }
config = { path = "../config" }

View file

@ -19,6 +19,7 @@ use config::{get_config, Config};
use errors::{bail, Error, Result};
use front_matter::InsertAnchor;
use library::{find_taxonomies, Library, Page, Paginator, Section, Taxonomy};
use relative_path::RelativePathBuf;
use templates::render_redirect_template;
use utils::fs::{
copy_directory, copy_file_if_needed, create_directory, create_file, ensure_directory_exists,
@ -28,7 +29,7 @@ use utils::templates::render_template;
lazy_static! {
/// The in-memory rendered map content
pub static ref SITE_CONTENT: Arc<RwLock<HashMap<String, String>>> = Arc::new(RwLock::new(HashMap::new()));
pub static ref SITE_CONTENT: Arc<RwLock<HashMap<RelativePathBuf, String>>> = Arc::new(RwLock::new(HashMap::new()));
}
/// Where are we building the site
@ -513,10 +514,12 @@ impl Site {
let write_dirs = self.build_mode == BuildMode::Disk || create_dirs;
ensure_directory_exists(&self.output_path)?;
let mut site_path = RelativePathBuf::new();
let mut current_path = self.output_path.to_path_buf();
for component in components {
current_path.push(component);
site_path.push(component);
if !current_path.exists() && write_dirs {
create_directory(&current_path)?;
@ -542,17 +545,10 @@ impl Site {
create_file(&end_path, &final_content)?;
}
BuildMode::Memory => {
let path = if filename != "index.html" {
let p = current_path.join(filename);
p.as_os_str().to_string_lossy().replace("public/", "/")
} else {
// TODO" remove unwrap
let p = current_path.strip_prefix(&self.output_path).unwrap();
p.as_os_str().to_string_lossy().into_owned()
}
.trim_end_matches('/')
.to_owned();
&SITE_CONTENT.write().unwrap().insert(path, final_content);
let site_path =
if filename != "index.html" { site_path.join(filename) } else { site_path };
&SITE_CONTENT.write().unwrap().insert(site_path, final_content);
}
}
@ -568,12 +564,8 @@ impl Site {
let output = page.render_html(&self.tera, &self.config, &self.library.read().unwrap())?;
let content = self.inject_livereload(output);
let components: Vec<&str> = page.path.split('/').collect();
let current_path = self.write_content(
&components,
"index.html",
content,
!page.assets.is_empty(),
)?;
let current_path =
self.write_content(&components, "index.html", content, !page.assets.is_empty())?;
// Copy any asset we found previously into the same directory as the index.html
for asset in &page.assets {
@ -932,11 +924,7 @@ impl Site {
if section.meta.generate_feed {
let library = &self.library.read().unwrap();
let pages = section
.pages
.iter()
.map(|k| library.get_page_by_key(*k))
.collect();
let pages = section.pages.iter().map(|k| library.get_page_by_key(*k)).collect();
self.render_feed(
pages,
Some(&PathBuf::from(&section.path[1..])),

View file

@ -38,6 +38,7 @@ use ws::{Message, Sender, WebSocket};
use errors::{Error as ZolaError, Result};
use globset::GlobSet;
use relative_path::{RelativePath, RelativePathBuf};
use site::sass::compile_sass;
use site::{Site, SITE_CONTENT};
use utils::fs::copy_file;
@ -69,7 +70,12 @@ static NOT_FOUND_TEXT: &[u8] = b"Not Found";
const LIVE_RELOAD: &str = include_str!("livereload.js");
async fn handle_request(req: Request<Body>, root: PathBuf) -> Result<Response<Body>> {
let path = req.uri().path().trim_end_matches('/').trim_start_matches('/');
let mut path = RelativePathBuf::new();
for c in req.uri().path().split('/') {
path.push(c);
}
// livereload.js is served using the LIVE_RELOAD str, not a file
if path == "livereload.js" {
if req.method() == Method::GET {
@ -79,7 +85,7 @@ async fn handle_request(req: Request<Body>, root: PathBuf) -> Result<Response<Bo
}
}
if let Some(content) = SITE_CONTENT.read().unwrap().get(path) {
if let Some(content) = SITE_CONTENT.read().unwrap().get(&path) {
return Ok(in_memory_html(content));
}
@ -87,7 +93,8 @@ async fn handle_request(req: Request<Body>, root: PathBuf) -> Result<Response<Bo
match result {
ResolveResult::MethodNotMatched => return Ok(method_not_allowed()),
ResolveResult::NotFound | ResolveResult::UriNotMatched => {
let content_404 = SITE_CONTENT.read().unwrap().get("404.html").map(|x| x.clone());
let not_found_path = RelativePath::new("404.html");
let content_404 = SITE_CONTENT.read().unwrap().get(not_found_path).map(|x| x.clone());
return Ok(not_found(content_404));
}
_ => (),