From 9e81b926c9e1871417cd0798dfc57399c785d5ba Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Tue, 15 Mar 2022 14:52:45 +0100 Subject: [PATCH 1/2] Add `Location::uri` constructor As far as I know, all URI characters should be valid Header value characters, so we can have an infallible constructor for Location from an `Uri`. This doesn't cover all uses of the Location header, since it allows URI-references like `/People.html#tim`, but it's an ergonomic win already, as mentioned in https://github.com/hyperium/headers/issues/48 --- src/common/location.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/common/location.rs b/src/common/location.rs index 54a1cc51..6eb58077 100644 --- a/src/common/location.rs +++ b/src/common/location.rs @@ -1,3 +1,4 @@ +use http::Uri; use HeaderValue; /// `Location` header, defined in @@ -28,6 +29,18 @@ derive_header! { name: LOCATION } +impl Location { + /// Creates a `Location` header from a uri + pub fn uri(uri: Uri) -> Self { + let uri = uri.to_string(); + // cf. https://www.rfc-editor.org/rfc/rfc3986#section-2 + Self( + HeaderValue::from_str(&uri) + .expect("All URI characters should be valid HTTP header value characters"), + ) + } +} + #[cfg(test)] mod tests { use super::super::test_decode; @@ -48,4 +61,20 @@ mod tests { assert_eq!(loc, Location(HeaderValue::from_static(s))); } + + #[test] + fn uri_constructor() { + let s = "https://www.rust-lang.org/tools"; + let uri: Uri = s.parse().unwrap(); + let loc = Location::uri(uri); + + assert_eq!(loc, Location(HeaderValue::from_static(s))); + } + + #[test] + fn uri_constructor_invalid_chars() { + let s = "https://www.rust-lang.org/hélas"; + let uri: Result = s.parse(); + assert!(uri.is_err()); + } } From ce16d54799d2458428535463be86ef6fc2a19cc7 Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Tue, 15 Mar 2022 15:18:45 +0100 Subject: [PATCH 2/2] Move to a From impl, add accessor --- src/common/location.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/common/location.rs b/src/common/location.rs index 6eb58077..51d6afd3 100644 --- a/src/common/location.rs +++ b/src/common/location.rs @@ -1,3 +1,5 @@ +use std::convert::TryFrom; + use http::Uri; use HeaderValue; @@ -30,12 +32,17 @@ derive_header! { } impl Location { - /// Creates a `Location` header from a uri - pub fn uri(uri: Uri) -> Self { - let uri = uri.to_string(); - // cf. https://www.rfc-editor.org/rfc/rfc3986#section-2 + /// Accesses the header's value + pub fn value(&self) -> &HeaderValue { + &self.0 + } +} + +impl From for Location { + fn from(uri: Uri) -> Self { Self( - HeaderValue::from_str(&uri) + HeaderValue::try_from(uri.to_string()) + // cf. https://www.rfc-editor.org/rfc/rfc3986#section-2 .expect("All URI characters should be valid HTTP header value characters"), ) } @@ -66,9 +73,10 @@ mod tests { fn uri_constructor() { let s = "https://www.rust-lang.org/tools"; let uri: Uri = s.parse().unwrap(); - let loc = Location::uri(uri); + let loc = Location::from(uri); assert_eq!(loc, Location(HeaderValue::from_static(s))); + assert_eq!(loc.value().to_str().unwrap(), s); } #[test]