From 909eae894af5c71c15661fa59939ed1811b2b3d2 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Mon, 11 Sep 2017 02:27:23 -0700 Subject: [PATCH] Don't implement 'UriDisplay' for all 'T: Display'. We don't know if that 'Display' implementation is URI safe, so using it blindly could result in generating bad URIs. --- .../tests/compile-fail/typed-uri-bad-type.rs | 2 +- lib/src/http/uri.rs | 49 +++++++++++++++---- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/codegen/tests/compile-fail/typed-uri-bad-type.rs b/codegen/tests/compile-fail/typed-uri-bad-type.rs index 98c3f139..1761ea1f 100644 --- a/codegen/tests/compile-fail/typed-uri-bad-type.rs +++ b/codegen/tests/compile-fail/typed-uri-bad-type.rs @@ -18,7 +18,7 @@ impl<'a> FromParam<'a> for S { fn simple(id: i32) -> &'static str { "" } #[post("//")] - //~^ ERROR the trait bound `S: std::fmt::Display` is not satisfied + //~^ ERROR the trait bound `S: rocket::http::uri::UriDisplay` is not satisfied fn not_uri_display(id: i32, name: S) -> &'static str { "" } #[post("//")] diff --git a/lib/src/http/uri.rs b/lib/src/http/uri.rs index f5950efb..5e68a871 100644 --- a/lib/src/http/uri.rs +++ b/lib/src/http/uri.rs @@ -352,17 +352,10 @@ pub trait UriDisplay { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result; } -impl UriDisplay for T { - #[inline(always)] - default fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ::fmt(self, f) - } -} - impl<'a> fmt::Display for &'a UriDisplay { #[inline(always)] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - (**self).fmt(f) + UriDisplay::fmt(*self, f) } } @@ -380,13 +373,51 @@ impl<'a> UriDisplay for &'a str { } } -impl<'a> UriDisplay for String { +impl<'a> UriDisplay for Cow<'a, str> { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", URI::percent_encode(self)) + } +} + +impl UriDisplay for String { #[inline(always)] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", URI::percent_encode(self.as_str())) } } +macro_rules! impl_with_display { + ($($T:ty),+) => {$( + impl UriDisplay for $T { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } + } + )+} +} + +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + +impl_with_display! { + i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64, bool, + IpAddr, Ipv4Addr, Ipv6Addr +} + +macro_rules! impl_for_ref { + ($($T:ty),+) => {$( + impl<'a, T: UriDisplay + ?Sized> UriDisplay for $T { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + UriDisplay::fmt(*self, f) + } + } + )+} +} + +impl_for_ref!(&'a mut T, &'a T); + /// Iterator over the segments of an absolute URI path. Skips empty segments. /// /// ### Examples