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;
|
||||
|
||||
use std::io;
|
||||
use rocket::response::NamedFile;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use rocket::response::NamedFile;
|
||||
|
||||
#[get("/")]
|
||||
fn index() -> io::Result<NamedFile> {
|
||||
NamedFile::open("static/index.html")
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
//! [global]
|
||||
//! address = "1.2.3.4"
|
||||
//!
|
||||
//! [devolopment]
|
||||
//! [development]
|
||||
//! address = "localhost"
|
||||
//!
|
||||
//! [production]
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
//! Borrowed and owned string types for absolute URIs.
|
||||
//!
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::convert::From;
|
||||
use std::fmt;
|
||||
use std::borrow::Cow;
|
||||
use std::str::Utf8Error;
|
||||
|
||||
use url;
|
||||
|
||||
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
|
||||
///
|
||||
|
@ -118,6 +122,32 @@ impl<'a> URI<'a> {
|
|||
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
|
||||
/// any.
|
||||
///
|
||||
|
@ -172,6 +202,41 @@ impl<'a> URI<'a> {
|
|||
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.
|
||||
///
|
||||
/// 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::str::FromStr;
|
||||
|
||||
use error::Error;
|
||||
use http::uri::URI;
|
||||
|
||||
/// Trait to create instance of some type from a form value; expected from field
|
||||
/// types in structs deriving `FromForm`.
|
||||
///
|
||||
|
@ -72,20 +72,20 @@ impl<'v> FromFormValue<'v> for String {
|
|||
|
||||
// This actually parses the value according to the standard.
|
||||
fn from_form_value(v: &'v str) -> Result<Self, Self::Error> {
|
||||
let decoder = url::percent_encoding::percent_decode(v.as_bytes());
|
||||
let res = decoder.decode_utf8().map_err(|_| v).map(|s| s.into_owned());
|
||||
match res {
|
||||
e@Err(_) => e,
|
||||
let result = URI::percent_decode(v.as_bytes());
|
||||
match result {
|
||||
Err(_) => Err(v),
|
||||
Ok(mut string) => Ok({
|
||||
// Entirely safe because we're changing the single-byte '+'.
|
||||
unsafe {
|
||||
for c in string.as_mut_vec() {
|
||||
for c in string.to_mut().as_mut_vec() {
|
||||
if *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::path::PathBuf;
|
||||
use std::fmt::Debug;
|
||||
|
||||
use url;
|
||||
|
||||
use http::uri::Segments;
|
||||
use http::uri::{URI, Segments};
|
||||
|
||||
/// 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 {
|
||||
type Error = &'a str;
|
||||
fn from_param(p: &'a str) -> Result<String, Self::Error> {
|
||||
let decoder = url::percent_encoding::percent_decode(p.as_bytes());
|
||||
decoder.decode_utf8().map_err(|_| p).map(|s| s.into_owned())
|
||||
URI::percent_decode(p.as_bytes()).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 {
|
||||
type Error = ();
|
||||
fn from_segments(segments: Segments<'a>) -> Result<PathBuf, ()> {
|
||||
Ok(segments.collect())
|
||||
type Error = Utf8Error;
|
||||
|
||||
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