From 9e81b926c9e1871417cd0798dfc57399c785d5ba Mon Sep 17 00:00:00 2001
From: Amos Wenger <amoswenger@gmail.com>
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<Uri, _> = s.parse();
+        assert!(uri.is_err());
+    }
 }

From ce16d54799d2458428535463be86ef6fc2a19cc7 Mon Sep 17 00:00:00 2001
From: Amos Wenger <amoswenger@gmail.com>
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<Uri> 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]