mirror of https://github.com/rwf2/Rocket.git
Fix normalization and Windows issues.
This commit is contained in:
parent
e0973d95f1
commit
26db5ecb4e
|
@ -23,6 +23,10 @@ mod context {
|
|||
crate fn context<'a>(&'a self) -> impl Deref<Target=Context> + 'a {
|
||||
&self.0
|
||||
}
|
||||
|
||||
crate fn is_reloading(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,6 +79,10 @@ mod context {
|
|||
self.context.read().unwrap()
|
||||
}
|
||||
|
||||
crate fn is_reloading(&self) -> bool {
|
||||
self.watcher.is_some()
|
||||
}
|
||||
|
||||
fn context_mut<'a>(&'a self) -> impl DerefMut<Target=Context> + 'a {
|
||||
self.context.write().unwrap()
|
||||
}
|
||||
|
|
|
@ -46,8 +46,13 @@ impl<'a> Metadata<'a> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(proc_macro_hygiene, decl_macro)]
|
||||
/// # #[macro_use] extern crate rocket;
|
||||
/// # extern crate rocket_contrib;
|
||||
/// #
|
||||
/// use rocket_contrib::templates::Metadata;
|
||||
///
|
||||
/// #[get("/")]
|
||||
/// fn handler(metadata: Metadata) {
|
||||
/// // Returns `true` if the template with name `"name"` was loaded.
|
||||
/// let loaded = metadata.contains_template("name");
|
||||
|
@ -56,6 +61,27 @@ impl<'a> Metadata<'a> {
|
|||
pub fn contains_template(&self, name: &str) -> bool {
|
||||
self.0.context().templates.contains_key(name)
|
||||
}
|
||||
|
||||
/// Returns `true` if template reloading is enabled.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(proc_macro_hygiene, decl_macro)]
|
||||
/// # #[macro_use] extern crate rocket;
|
||||
/// # extern crate rocket_contrib;
|
||||
/// #
|
||||
/// use rocket_contrib::templates::Metadata;
|
||||
///
|
||||
/// #[get("/")]
|
||||
/// fn handler(metadata: Metadata) {
|
||||
/// // Returns `true` if template reloading is enabled.
|
||||
/// let reloading = metadata.reloading();
|
||||
/// }
|
||||
/// ```
|
||||
pub fn reloading(&self) -> bool {
|
||||
self.0.is_reloading()
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves the template metadata. If a template fairing hasn't been attached,
|
||||
|
|
|
@ -22,6 +22,11 @@ mod templates_tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[get("/is_reloading")]
|
||||
fn is_reloading(md: Metadata) -> Option<()> {
|
||||
if md.reloading() { Some(()) } else { None }
|
||||
}
|
||||
|
||||
fn template_root() -> PathBuf {
|
||||
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests").join("templates")
|
||||
}
|
||||
|
@ -32,7 +37,7 @@ mod templates_tests {
|
|||
.expect("valid configuration");
|
||||
|
||||
::rocket::custom(config).attach(Template::fairing())
|
||||
.mount("/", routes![template_check])
|
||||
.mount("/", routes![template_check, is_reloading])
|
||||
}
|
||||
|
||||
#[cfg(feature = "tera_templates")]
|
||||
|
@ -142,8 +147,14 @@ mod templates_tests {
|
|||
let reload_path = template_root().join("hbs").join("reload.txt.hbs");
|
||||
write_file(&reload_path, INITIAL_TEXT);
|
||||
|
||||
// verify that the initial content is correct
|
||||
// set up the client. if we can't reload templates, then just quit
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let res = client.get("/is_reloading").dispatch();
|
||||
if res.status() != Status::Ok {
|
||||
return;
|
||||
}
|
||||
|
||||
// verify that the initial content is correct
|
||||
let initial_rendered = Template::show(client.rocket(), RELOAD_TEMPLATE, ());
|
||||
assert_eq!(initial_rendered, Some(INITIAL_TEXT.into()));
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
reload
|
||||
initial
|
|
@ -5,7 +5,9 @@ use std::{io, fs::Metadata, time::SystemTime};
|
|||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Kind {
|
||||
Dynamic, Static
|
||||
#[allow(dead_code)]
|
||||
Dynamic,
|
||||
Static
|
||||
}
|
||||
|
||||
impl Kind {
|
||||
|
@ -17,11 +19,6 @@ impl Kind {
|
|||
Kind::Static => ".rlib"
|
||||
}
|
||||
}
|
||||
|
||||
fn prefix(self) -> &'static str {
|
||||
#[cfg(windows)] { "" }
|
||||
#[cfg(not(windows))] { "lib" }
|
||||
}
|
||||
}
|
||||
|
||||
fn target_path() -> PathBuf {
|
||||
|
@ -52,7 +49,7 @@ fn best_time_for(metadata: &Metadata) -> SystemTime {
|
|||
|
||||
fn extern_dep(name: &str, kind: Kind) -> io::Result<String> {
|
||||
let deps_root = target_path().join("deps");
|
||||
let dep_name = format!("{}{}", kind.prefix(), name);
|
||||
let dep_name = format!("lib{}", name);
|
||||
|
||||
let mut dep_path: Option<PathBuf> = None;
|
||||
for entry in deps_root.read_dir().expect("read_dir call failed") {
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::fmt;
|
|||
use std::path::PathBuf;
|
||||
|
||||
use rocket::{Request, Outcome::*};
|
||||
use rocket::http::ext::Normalize;
|
||||
use rocket::local::Client;
|
||||
use rocket::data::{self, Data, FromDataSimple};
|
||||
use rocket::request::Form;
|
||||
|
@ -48,7 +49,7 @@ fn post1(
|
|||
simple: Simple,
|
||||
) -> String {
|
||||
let string = format!("{}, {}, {}, {}, {}, {}",
|
||||
sky, name, a, query.field, path.display(), simple.0);
|
||||
sky, name, a, query.field, path.normalized_str(), simple.0);
|
||||
|
||||
let uri = uri!(post2: a, name.url_decode_lossy(), path, sky, query.into_inner());
|
||||
|
||||
|
@ -65,7 +66,7 @@ fn post2(
|
|||
simple: Simple,
|
||||
) -> String {
|
||||
let string = format!("{}, {}, {}, {}, {}, {}",
|
||||
sky, name, a, query.field, path.display(), simple.0);
|
||||
sky, name, a, query.field, path.normalized_str(), simple.0);
|
||||
|
||||
let uri = uri!(post2: a, name.url_decode_lossy(), path, sky, query.into_inner());
|
||||
|
||||
|
|
|
@ -98,3 +98,21 @@ impl<'a, B: 'static + ToOwned + ?Sized> IntoOwned for Cow<'a, B> {
|
|||
Cow::Owned(self.into_owned())
|
||||
}
|
||||
}
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
pub trait Normalize {
|
||||
fn normalized_str(&self) -> Cow<str>;
|
||||
}
|
||||
|
||||
impl<T: AsRef<Path>> Normalize for T {
|
||||
#[cfg(windows)]
|
||||
fn normalized_str(&self) -> Cow<str> {
|
||||
self.as_ref().to_string_lossy().replace('\\', "/").into()
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn normalized_str(&self) -> Cow<str> {
|
||||
self.as_ref().to_string_lossy()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::fmt;
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use {RawStr, uri::Uri};
|
||||
use {RawStr, uri::Uri, ext::Normalize};
|
||||
|
||||
use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
|
||||
|
||||
|
@ -203,21 +203,21 @@ impl UriDisplay for String {
|
|||
}
|
||||
}
|
||||
|
||||
/// Percent-encodes each segment in the path.
|
||||
/// Percent-encodes each segment in the path and normalizes separators.
|
||||
impl UriDisplay for PathBuf {
|
||||
#[inline(always)]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let string = self.to_string_lossy();
|
||||
let string = self.normalized_str();
|
||||
let enc: Cow<str> = utf8_percent_encode(&string, PATH_ENCODE_SET).into();
|
||||
write!(f, "{}", enc)
|
||||
}
|
||||
}
|
||||
|
||||
/// Percent-encodes each segment in the path.
|
||||
/// Percent-encodes each segment in the and normalizes separators.
|
||||
impl UriDisplay for Path {
|
||||
#[inline(always)]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let string = self.to_string_lossy();
|
||||
let string = self.normalized_str();
|
||||
let enc: Cow<str> = utf8_percent_encode(&string, PATH_ENCODE_SET).into();
|
||||
write!(f, "{}", enc)
|
||||
}
|
||||
|
|
|
@ -927,7 +927,10 @@ impl Config {
|
|||
///
|
||||
/// assert_eq!(config.root(), current_dir().unwrap());
|
||||
/// assert_eq!(config.root_relative("abc"), config.root().join("abc"));
|
||||
/// # #[cfg(not(windows))]
|
||||
/// assert_eq!(config.root_relative("/abc"), Path::new("/abc"));
|
||||
/// # #[cfg(windows)]
|
||||
/// # assert_eq!(config.root_relative("C:\\abc"), Path::new("C:\\abc"));
|
||||
/// ```
|
||||
pub fn root_relative<P: AsRef<Path>>(&self, path: P) -> PathBuf {
|
||||
let path = path.as_ref();
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use std::{fmt, io};
|
||||
use std::borrow::Cow;
|
||||
use std::path::{Path, PathBuf, Component};
|
||||
use std::io;
|
||||
|
||||
pub trait ReadExt: io::Read {
|
||||
fn read_max(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
|
||||
|
@ -19,37 +17,3 @@ pub trait ReadExt: io::Read {
|
|||
}
|
||||
|
||||
impl<T: io::Read> ReadExt for T { }
|
||||
|
||||
pub struct NormalizedPath<'a>(&'a Path);
|
||||
|
||||
impl<'a> fmt::Display for NormalizedPath<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fn to_str<'c>(c: &'c Component) -> Cow<'c, str> {
|
||||
c.as_os_str().to_string_lossy()
|
||||
}
|
||||
|
||||
let mut components = self.0.components();
|
||||
match (components.next(), components.next()) {
|
||||
(Some(Component::RootDir), Some(c)) => write!(f, "/{}", to_str(&c))?,
|
||||
(Some(a), Some(b)) => write!(f, "{}/{}", to_str(&a), to_str(&b))?,
|
||||
(Some(c), None) => write!(f, "{}", to_str(&c))?,
|
||||
_ => return Ok(())
|
||||
};
|
||||
|
||||
for c in components {
|
||||
write!(f, "/{}", to_str(&c))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Normalize {
|
||||
fn normalized(&self) -> NormalizedPath;
|
||||
}
|
||||
|
||||
impl<T: AsRef<Path>> Normalize for T {
|
||||
fn normalized(&self) -> NormalizedPath {
|
||||
NormalizedPath(self.as_ref())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,7 +116,6 @@ extern crate isatty;
|
|||
#[cfg(test)] #[macro_use] extern crate lazy_static;
|
||||
|
||||
#[doc(hidden)] #[macro_use] pub mod logger;
|
||||
#[doc(hidden)] pub mod ext;
|
||||
pub mod local;
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
|
@ -142,6 +141,7 @@ mod router;
|
|||
mod rocket;
|
||||
mod codegen;
|
||||
mod catcher;
|
||||
mod ext;
|
||||
|
||||
#[doc(inline)] pub use response::Response;
|
||||
#[doc(inline)] pub use handler::{Handler, ErrorHandler};
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
#[macro_use] extern crate rocket;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use rocket::ext::Normalize;
|
||||
use rocket::http::ext::Normalize;
|
||||
use rocket::Route;
|
||||
|
||||
#[get("/<path..>")]
|
||||
fn files(route: &Route, path: PathBuf) -> String {
|
||||
Path::new(route.base()).join(path).normalized().to_string()
|
||||
Path::new(route.base()).join(path).normalized_str().to_string()
|
||||
}
|
||||
|
||||
mod route_guard_tests {
|
||||
|
|
|
@ -3,7 +3,7 @@ extern crate rocket;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use std::io;
|
||||
use std::{io, env};
|
||||
use std::fs::File;
|
||||
|
||||
use rocket::{Request, Handler, Route, Data, Catcher};
|
||||
|
@ -43,7 +43,7 @@ fn upload<'r>(req: &'r Request, data: Data) -> Outcome<'r> {
|
|||
return Outcome::failure(Status::BadRequest);
|
||||
}
|
||||
|
||||
let file = File::create("/tmp/upload.txt");
|
||||
let file = File::create(env::temp_dir().join("upload.txt"));
|
||||
if let Ok(mut file) = file {
|
||||
if let Ok(n) = io::copy(&mut data.open(), &mut file) {
|
||||
return Outcome::from(req, format!("OK: {} bytes uploaded.", n));
|
||||
|
@ -58,7 +58,7 @@ fn upload<'r>(req: &'r Request, data: Data) -> Outcome<'r> {
|
|||
}
|
||||
|
||||
fn get_upload<'r>(req: &'r Request, _: Data) -> Outcome<'r> {
|
||||
Outcome::from(req, File::open("/tmp/upload.txt").ok())
|
||||
Outcome::from(req, File::open(env::temp_dir().join("upload.txt")).ok())
|
||||
}
|
||||
|
||||
fn not_found_handler<'r>(req: &'r Request) -> response::Result<'r> {
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
|
||||
#[cfg(test)] mod tests;
|
||||
|
||||
use std::io;
|
||||
use std::{io, env};
|
||||
use rocket::Data;
|
||||
|
||||
#[post("/upload", format = "plain", data = "<data>")]
|
||||
fn upload(data: Data) -> io::Result<String> {
|
||||
data.stream_to_file("/tmp/upload.txt").map(|n| n.to_string())
|
||||
data.stream_to_file(env::temp_dir().join("upload.txt")).map(|n| n.to_string())
|
||||
}
|
||||
|
||||
#[get("/")]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use rocket::local::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
use std::env;
|
||||
use std::io::Read;
|
||||
use std::fs::{self, File};
|
||||
|
||||
|
@ -16,7 +17,8 @@ fn test_index() {
|
|||
#[test]
|
||||
fn test_raw_upload() {
|
||||
// Delete the upload file before we begin.
|
||||
let _ = fs::remove_file("/tmp/upload.txt");
|
||||
let upload_file = env::temp_dir().join("upload.txt");
|
||||
let _ = fs::remove_file(&upload_file);
|
||||
|
||||
// Do the upload. Make sure we get the expected results.
|
||||
let client = Client::new(super::rocket()).unwrap();
|
||||
|
@ -30,7 +32,7 @@ fn test_raw_upload() {
|
|||
|
||||
// Ensure we find the body in the /tmp/upload.txt file.
|
||||
let mut file_contents = String::new();
|
||||
let mut file = File::open("/tmp/upload.txt").expect("open upload.txt file");
|
||||
let mut file = File::open(&upload_file).expect("open upload.txt file");
|
||||
file.read_to_string(&mut file_contents).expect("read upload.txt");
|
||||
assert_eq!(&file_contents, UPLOAD_CONTENTS);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue