mirror of https://github.com/rwf2/Rocket.git
Add URI::percent_decoding helper method. Safeguard Pathbuf FromSegments implementation.
This commit is contained in:
parent
4326c9103e
commit
c98d047038
|
@ -4,9 +4,10 @@
|
||||||
extern crate rocket;
|
extern crate rocket;
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use rocket::response::NamedFile;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use rocket::response::NamedFile;
|
||||||
|
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
fn index() -> io::Result<NamedFile> {
|
fn index() -> io::Result<NamedFile> {
|
||||||
NamedFile::open("static/index.html")
|
NamedFile::open("static/index.html")
|
||||||
|
|
|
@ -85,7 +85,7 @@
|
||||||
//! [global]
|
//! [global]
|
||||||
//! address = "1.2.3.4"
|
//! address = "1.2.3.4"
|
||||||
//!
|
//!
|
||||||
//! [devolopment]
|
//! [development]
|
||||||
//! address = "localhost"
|
//! address = "localhost"
|
||||||
//!
|
//!
|
||||||
//! [production]
|
//! [production]
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
//! Borrowed and owned string types for absolute URIs.
|
//! Borrowed and owned string types for absolute URIs.
|
||||||
//!
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::str::Utf8Error;
|
||||||
|
|
||||||
|
use url;
|
||||||
|
|
||||||
use router::Collider;
|
use router::Collider;
|
||||||
|
|
||||||
|
@ -77,7 +80,8 @@ impl<'a> URI<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over the segments of this URI. Skips empty segments.
|
/// Returns an iterator over the segments of the path in this URI. Skips
|
||||||
|
/// empty segments.
|
||||||
///
|
///
|
||||||
/// ### Examples
|
/// ### Examples
|
||||||
///
|
///
|
||||||
|
@ -118,6 +122,32 @@ impl<'a> URI<'a> {
|
||||||
Segments(self.path)
|
Segments(self.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the path part of this URI.
|
||||||
|
///
|
||||||
|
/// ### Examples
|
||||||
|
///
|
||||||
|
/// A URI with only a path:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use rocket::http::uri::URI;
|
||||||
|
///
|
||||||
|
/// let uri = URI::new("/a/b/c");
|
||||||
|
/// assert_eq!(uri.path(), "/a/b/c");
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// A URI with other components:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use rocket::http::uri::URI;
|
||||||
|
///
|
||||||
|
/// let uri = URI::new("/a/b/c?name=bob#done");
|
||||||
|
/// assert_eq!(uri.path(), "/a/b/c");
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn path(&self) -> &'a str {
|
||||||
|
self.path
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the query part of this URI without the question mark, if there is
|
/// Returns the query part of this URI without the question mark, if there is
|
||||||
/// any.
|
/// any.
|
||||||
///
|
///
|
||||||
|
@ -172,6 +202,41 @@ impl<'a> URI<'a> {
|
||||||
self.fragment
|
self.fragment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a URL-decoded version of the string. If the percent encoded
|
||||||
|
/// values are not valid UTF-8, an `Err` is returned.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use rocket::http::uri::URI;
|
||||||
|
///
|
||||||
|
/// let uri = URI::new("/Hello%2C%20world%21");
|
||||||
|
/// let decoded_path = URI::percent_decode(uri.path().as_bytes()).expect("decoded");
|
||||||
|
/// assert_eq!(decoded_path, "/Hello, world!");
|
||||||
|
/// ```
|
||||||
|
pub fn percent_decode<'s>(string: &'s [u8]) -> Result<Cow<'s, str>, Utf8Error> {
|
||||||
|
let decoder = url::percent_encoding::percent_decode(string);
|
||||||
|
decoder.decode_utf8()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a URL-decoded version of the path. Any invalid UTF-8
|
||||||
|
/// percent-encoded byte sequences will be replaced <20> U+FFFD, the
|
||||||
|
/// replacement character.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use rocket::http::uri::URI;
|
||||||
|
///
|
||||||
|
/// let uri = URI::new("/Hello%2C%20world%21");
|
||||||
|
/// let decoded_path = URI::percent_decode_lossy(uri.path().as_bytes());
|
||||||
|
/// assert_eq!(decoded_path, "/Hello, world!");
|
||||||
|
/// ```
|
||||||
|
pub fn percent_decode_lossy<'s>(string: &'s [u8]) -> Cow<'s, str> {
|
||||||
|
let decoder = url::percent_encoding::percent_decode(string);
|
||||||
|
decoder.decode_utf8_lossy()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the inner string of this URI.
|
/// Returns the inner string of this URI.
|
||||||
///
|
///
|
||||||
/// The returned string is in raw form. It contains empty segments. If you'd
|
/// The returned string is in raw form. It contains empty segments. If you'd
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use url;
|
|
||||||
|
|
||||||
use error::Error;
|
|
||||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use error::Error;
|
||||||
|
use http::uri::URI;
|
||||||
|
|
||||||
/// Trait to create instance of some type from a form value; expected from field
|
/// Trait to create instance of some type from a form value; expected from field
|
||||||
/// types in structs deriving `FromForm`.
|
/// types in structs deriving `FromForm`.
|
||||||
///
|
///
|
||||||
|
@ -72,20 +72,20 @@ impl<'v> FromFormValue<'v> for String {
|
||||||
|
|
||||||
// This actually parses the value according to the standard.
|
// This actually parses the value according to the standard.
|
||||||
fn from_form_value(v: &'v str) -> Result<Self, Self::Error> {
|
fn from_form_value(v: &'v str) -> Result<Self, Self::Error> {
|
||||||
let decoder = url::percent_encoding::percent_decode(v.as_bytes());
|
let result = URI::percent_decode(v.as_bytes());
|
||||||
let res = decoder.decode_utf8().map_err(|_| v).map(|s| s.into_owned());
|
match result {
|
||||||
match res {
|
Err(_) => Err(v),
|
||||||
e@Err(_) => e,
|
|
||||||
Ok(mut string) => Ok({
|
Ok(mut string) => Ok({
|
||||||
|
// Entirely safe because we're changing the single-byte '+'.
|
||||||
unsafe {
|
unsafe {
|
||||||
for c in string.as_mut_vec() {
|
for c in string.to_mut().as_mut_vec() {
|
||||||
if *c == b'+' {
|
if *c == b'+' {
|
||||||
*c = b' ';
|
*c = b' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string.into_owned()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
use std::str::FromStr;
|
use std::str::{Utf8Error, FromStr};
|
||||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use url;
|
use http::uri::{URI, Segments};
|
||||||
|
|
||||||
use http::uri::Segments;
|
|
||||||
|
|
||||||
/// Trait to convert a dynamic path segment string to a concrete value.
|
/// Trait to convert a dynamic path segment string to a concrete value.
|
||||||
///
|
///
|
||||||
|
@ -68,8 +66,7 @@ impl<'a> FromParam<'a> for &'a str {
|
||||||
impl<'a> FromParam<'a> for String {
|
impl<'a> FromParam<'a> for String {
|
||||||
type Error = &'a str;
|
type Error = &'a str;
|
||||||
fn from_param(p: &'a str) -> Result<String, Self::Error> {
|
fn from_param(p: &'a str) -> Result<String, Self::Error> {
|
||||||
let decoder = url::percent_encoding::percent_decode(p.as_bytes());
|
URI::percent_decode(p.as_bytes()).map_err(|_| p).map(|s| s.into_owned())
|
||||||
decoder.decode_utf8().map_err(|_| p).map(|s| s.into_owned())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,10 +130,26 @@ impl<'a> FromSegments<'a> for Segments<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a `PathBuf` from a `Segments` iterator. The returned `PathBuf` is
|
||||||
|
/// percent-decoded. If a segment is equal to "..", the previous segment (if
|
||||||
|
/// any) is skipped. For security purposes, any other segments that begin with
|
||||||
|
/// "*" or "." are ignored. If a percent-decoded segment results in invalid
|
||||||
|
/// UTF8, an `Err` is returned.
|
||||||
impl<'a> FromSegments<'a> for PathBuf {
|
impl<'a> FromSegments<'a> for PathBuf {
|
||||||
type Error = ();
|
type Error = Utf8Error;
|
||||||
fn from_segments(segments: Segments<'a>) -> Result<PathBuf, ()> {
|
|
||||||
Ok(segments.collect())
|
fn from_segments(segments: Segments<'a>) -> Result<PathBuf, Utf8Error> {
|
||||||
|
let mut buf = PathBuf::new();
|
||||||
|
for segment in segments {
|
||||||
|
let decoded = URI::percent_decode(segment.as_bytes())?;
|
||||||
|
if decoded == ".." {
|
||||||
|
buf.pop();
|
||||||
|
} else if !(decoded.starts_with(".") || decoded.starts_with("*")) {
|
||||||
|
buf.push(&*decoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue