1
1
use crate :: headers:: { HeaderName , HeaderValue , Headers , CONTENT_LOCATION } ;
2
2
use crate :: { Status , Url } ;
3
3
4
+ use std:: convert:: TryInto ;
5
+
6
+ /// Indicates an alternate location for the returned data.
4
7
///
5
8
/// # Specifications
6
9
///
7
- /// - [RFC 7230 , section 3.3 .2: Content-Length](https://tools.ietf.org/html/rfc7231#section-3.1.4.2)
10
+ /// - [RFC 7231 , section 3.1.4 .2: Content-Length](https://tools.ietf.org/html/rfc7231#section-3.1.4.2)
8
11
///
9
12
/// # Examples
10
13
///
@@ -26,18 +29,21 @@ use crate::{Status, Url};
26
29
/// ```
27
30
#[ derive( Debug ) ]
28
31
pub struct ContentLocation {
29
- url : String ,
32
+ url : Url ,
30
33
}
31
34
32
- #[ allow( clippy:: len_without_is_empty) ]
33
35
impl ContentLocation {
34
36
/// Create a new instance of `Content-Location` header.
35
37
pub fn new ( url : String ) -> Self {
36
- Self { url }
38
+ Self { url : Url :: parse ( & url ) . unwrap ( ) }
37
39
}
38
40
39
41
/// Create a new instance from headers.
40
- pub fn from_headers ( headers : impl AsRef < Headers > ) -> crate :: Result < Option < Self > > {
42
+ pub fn from_headers < U > ( base_url : U , headers : impl AsRef < Headers > ) -> crate :: Result < Option < Self > >
43
+ where
44
+ U : TryInto < Url > ,
45
+ U :: Error : std:: fmt:: Debug ,
46
+ {
41
47
let headers = match headers. as_ref ( ) . get ( CONTENT_LOCATION ) {
42
48
Some ( headers) => headers,
43
49
None => return Ok ( None ) ,
@@ -46,8 +52,9 @@ impl ContentLocation {
46
52
// If we successfully parsed the header then there's always at least one
47
53
// entry. We want the last entry.
48
54
let value = headers. iter ( ) . last ( ) . unwrap ( ) ;
49
- let url = Url :: parse ( value. as_str ( ) . trim ( ) ) . status ( 400 ) ?;
50
- Ok ( Some ( Self { url : url. into_string ( ) } ) )
55
+ let base = base_url. try_into ( ) . expect ( "Could not convert into a valid url" ) ;
56
+ let url = base. join ( value. as_str ( ) . trim ( ) ) . status ( 400 ) ?;
57
+ Ok ( Some ( Self { url } ) )
51
58
}
52
59
53
60
/// Sets the header.
@@ -62,7 +69,7 @@ impl ContentLocation {
62
69
63
70
/// Get the `HeaderValue`.
64
71
pub fn value ( & self ) -> HeaderValue {
65
- let output = format ! ( "{}" , self . url) ;
72
+ let output = format ! ( "{}" , self . url. as_str ( ) ) ;
66
73
67
74
// SAFETY: the internal string is validated to be ASCII.
68
75
unsafe { HeaderValue :: from_bytes_unchecked ( output. into ( ) ) }
@@ -75,7 +82,7 @@ impl ContentLocation {
75
82
76
83
/// Set the url.
77
84
pub fn set_location ( & mut self , location : & str ) {
78
- self . url = location. to_string ( ) ;
85
+ self . url = Url :: parse ( location) . unwrap ( ) ;
79
86
}
80
87
}
81
88
@@ -86,21 +93,21 @@ mod test {
86
93
87
94
#[ test]
88
95
fn smoke ( ) -> crate :: Result < ( ) > {
89
- let content_location = ContentLocation :: new ( "https://example.net/test" . to_string ( ) ) ;
96
+ let content_location = ContentLocation :: new ( "https://example.net/test.json " . to_string ( ) ) ;
90
97
91
98
let mut headers = Headers :: new ( ) ;
92
99
content_location. apply ( & mut headers) ;
93
100
94
- let content_location = ContentLocation :: from_headers ( headers) ?. unwrap ( ) ;
95
- assert_eq ! ( content_location. location( ) , "https://example.net/test" ) ;
101
+ let content_location = ContentLocation :: from_headers ( Url :: parse ( "https://example.net/" ) . unwrap ( ) , headers ) ?. unwrap ( ) ;
102
+ assert_eq ! ( content_location. location( ) , "https://example.net/test.json " ) ;
96
103
Ok ( ( ) )
97
104
}
98
105
99
106
#[ test]
100
107
fn bad_request_on_parse_error ( ) -> crate :: Result < ( ) > {
101
108
let mut headers = Headers :: new ( ) ;
102
- headers. insert ( CONTENT_LOCATION , "<nori ate the tag. yum.>" ) ;
103
- let err = ContentLocation :: from_headers ( headers) . unwrap_err ( ) ;
109
+ headers. insert ( CONTENT_LOCATION , "htt:// <nori ate the tag. yum.>" ) ;
110
+ let err = ContentLocation :: from_headers ( Url :: parse ( "https://example.net" ) . unwrap ( ) , headers) . unwrap_err ( ) ;
104
111
assert_eq ! ( err. status( ) , 400 ) ;
105
112
Ok ( ( ) )
106
113
}
0 commit comments